diff --git a/.gn b/.gn
index ee62553..4f9cf60 100644
--- a/.gn
+++ b/.gn
@@ -166,6 +166,7 @@
   "//third_party/harfbuzz-ng/BUILD.gn",
   "//third_party/libaddressinput/BUILD.gn",
   "//third_party/opus/BUILD.gn",
+  "//third_party/trace-viewer/BUILD.gn",
   "//third_party/WebKit/Source/bindings/bindings.gni",
   "//third_party/WebKit/Source/bindings/scripts/scripts.gni",
   "//third_party/WebKit/Source/config.gni",
diff --git a/DEPS b/DEPS
index 062fbc2..0e247909 100644
--- a/DEPS
+++ b/DEPS
@@ -34,20 +34,20 @@
   'llvm_url': 'http://src.chromium.org/llvm-project',
   'llvm_git': 'https://llvm.googlesource.com',
   'webkit_trunk': 'http://src.chromium.org/blink/trunk',
-  'webkit_revision': '4769f3e7e6851362a2220aa7b3608fd72d47fce5', # from svn revision 196425
+  'webkit_revision': 'c189b79fada8084bde27587f4590b881076046ae', # from svn revision 196690
   'chromium_git': 'https://chromium.googlesource.com',
   'chromiumos_git': 'https://chromium.googlesource.com/chromiumos',
   'pdfium_git': 'https://pdfium.googlesource.com',
   'skia_git': 'https://skia.googlesource.com',
   'boringssl_git': 'https://boringssl.googlesource.com',
-  'libvpx_revision': '654e6615e1ef38ae95b9e03f937fb4dae4db7323',
+  'libvpx_revision': 'a43631169b4200f2000c8cfa82404ce507e31486',
   'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
-  'skia_revision': '08d171445b4006a5d620c6121048f4c383dba4d9',
+  'skia_revision': '0963f5dab079627c5523ce6a443af27a33e361f7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and V8 without interference from each other.
   'v8_branch': 'trunk',
-  'v8_revision': 'fd1eb4ee0f41fabba3312b504d379c4a6f289693',
+  'v8_revision': 'a50f5ef40866cf5f8ebdca98f4a99e902bdbb2c4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling WebRTC
   # and V8 without interference from each other.
@@ -58,7 +58,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '10eb591a434c48f0ef9ad2cda2f4867bacd1c9f9',
+  'angle_revision': '6e0302a87d447b260688ac0d4ad1b932a363ddbf',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -74,7 +74,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': '8a228f5bfe82e8178fc42262a1cc21e82c3f8bf8',
+  'boringssl_revision': 'af0e32cb84f0c9cc65b9233a3414d2562642b342',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nss
   # and whatever else without interference from each other.
@@ -94,7 +94,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': 'ec2d51e124a58435534985710f421145d10b093e',
+  'nacl_revision': 'ac4a825a3a3fda9c4884c7f6c82b895b3ae6085e',
 }
 
 # Only these hosts are allowed for dependencies in this DEPS file.
@@ -132,13 +132,13 @@
    Var('chromium_git') + '/crashpad/crashpad.git' + '@' + '00c42ae7bdcf40d15c02b87e088c1eb565a51333',
 
   'src/third_party/trace-viewer':
-   Var('chromium_git') + '/external/trace-viewer.git' + '@' + '473c6c4e8722676153d3449c67094aa55d6f6799',
+   Var('chromium_git') + '/external/trace-viewer.git' + '@' + 'cd91381c069ce9a6db35f335999759fab6dac7b9',
 
   'src/third_party/WebKit':
    Var('chromium_git') + '/chromium/blink.git' + '@' +  Var('webkit_revision'),
 
   'src/third_party/icu':
-   Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'f1ad7f9ba957571dc692ea3e187612c685615e19',
+   Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '9939a5d5314b6d59d5fb070902d73304c2482f88',
 
   'src/third_party/libexif/sources':
    Var('chromium_git') + '/chromium/deps/libexif/sources.git' + '@' + 'ed98343daabd7b4497f97fda972e132e6877c48a',
@@ -159,7 +159,7 @@
     Var('chromium_git') + '/external/grit-i18n.git' + '@' + 'c1b1591a05209c1ad467e845ba8543c22f9072af', # from svn revision 189
 
   'src/tools/gyp':
-    Var('chromium_git') + '/external/gyp.git' + '@' + '29e94a3285ee899d14d5e56a6001682620d3778f',
+    Var('chromium_git') + '/external/gyp.git' + '@' + 'fdc7b812f99e48c00e9a487bd56751bbeae07043',
 
   'src/tools/swarming_client':
    Var('chromium_git') + '/external/swarming.client.git' + '@' +  Var('swarming_revision'),
@@ -189,7 +189,7 @@
     Var('chromium_git') + '/external/bidichecker/lib.git' + '@' + '97f2aa645b74c28c57eca56992235c79850fa9e0',
 
   'src/third_party/webgl/src':
-   Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '1e318b3f0ad952d22477151eec98d37fa08e5bc7',
+   Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '8986f8bfa84547b1a30a9256ebdd665024d68d71',
 
   'src/third_party/webdriver/pylib':
     Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
@@ -201,7 +201,7 @@
    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'c0f05636c4472e5d3c0045ec34464aec46c5fb70',
 
   'src/third_party/libjingle/source/talk':
-    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '9329d80ec7306d3c2ee3bc3c17508956627ddeff', # commit position 9354
+    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '78b410bcd08fe61fb91c4e1a307f5f0c7b5f8001', # commit position 9384
 
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/usrsctplib.git' + '@' + '36444a999739e9e408f8f587cb4c3ffeef2e50ac', # from svn revision 9215
@@ -225,7 +225,7 @@
    Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '13eda41c8f674fa500743161c0a17581dd58e41c', # commit position 9354
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '95797c571819af56d1c15beebc503c57e8ca1df4', # commit position 9390
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
@@ -234,7 +234,7 @@
     Var('chromium_git') + '/external/github.com/open-source-parsers/jsoncpp.git' + '@' + 'f572e8e42e22cfcf5ab0aea26574f408943edfa4', # from svn 248
 
   'src/third_party/libyuv':
-    Var('chromium_git') + '/external/libyuv.git' + '@' + '35aa92a1ea1bbcca6bf97e69e7a65f1caa987675', # from svn revision 1385
+    Var('chromium_git') + '/external/libyuv.git' + '@' + '632c50f29cdacb8c5872ce9938444b676b4a0c81', # from svn revision 1407
 
   'src/third_party/smhasher/src':
     Var('chromium_git') + '/external/smhasher.git' + '@' + 'e87738e57558e0ec472b2fc3a643b838e5b6e88f',
@@ -254,7 +254,7 @@
    Var('chromium_git') + '/chromium/tools/deps2git.git' + '@' + 'f04828eb0b5acd3e7ad983c024870f17f17b06d9',
 
   'src/third_party/webpagereplay':
-   Var('chromium_git') + '/external/github.com/chromium/web-page-replay.git' + '@' + 'e53550b73e8e098938a651bc8ceb3681e5980567',
+   Var('chromium_git') + '/external/github.com/chromium/web-page-replay.git' + '@' + '5da5975950daa7b30a6938da73fd0b3200901b0c',
 
   'src/third_party/pywebsocket/src':
     Var('chromium_git') + '/external/pywebsocket/src.git' + '@' + 'cb349e87ddb30ff8d1fa1a89be39cec901f4a29c',
diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp
index 3528246..bbd23c61 100644
--- a/android_webview/android_webview.gyp
+++ b/android_webview/android_webview.gyp
@@ -156,6 +156,7 @@
       'type': 'static_library',
       'dependencies': [
         '../android_webview/native/webview_native.gyp:webview_native',
+        '../cc/cc.gyp:cc_surfaces',
         '../components/components.gyp:auto_login_parser',
         '../components/components.gyp:autofill_content_renderer',
         '../components/components.gyp:breakpad_host',
@@ -300,8 +301,6 @@
         'common/android_webview_message_generator.h',
         'common/aw_content_client.cc',
         'common/aw_content_client.h',
-        'common/aw_crash_handler.cc',
-        'common/aw_crash_handler.h',
         'common/aw_hit_test_data.cc',
         'common/aw_hit_test_data.h',
         'common/aw_message_port_messages.h',
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS
index 9fd4db1c..5896228 100644
--- a/android_webview/browser/DEPS
+++ b/android_webview/browser/DEPS
@@ -7,7 +7,6 @@
 
   "+cc",
   "-cc/blink",
-  "-cc/surfaces",
 
   "+components/auto_login_parser",
   "+components/autofill/content/browser",
diff --git a/android_webview/browser/aw_browser_main_parts.cc b/android_webview/browser/aw_browser_main_parts.cc
index 4ea656ce..4e5548e 100644
--- a/android_webview/browser/aw_browser_main_parts.cc
+++ b/android_webview/browser/aw_browser_main_parts.cc
@@ -61,7 +61,8 @@
       base::android::GetDefaultLocale(),
       NULL,
       ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES);
-  std::string locale = l10n_util::GetApplicationLocale(std::string()) + ".pak";
+  std::string locale =
+      "assets/" + l10n_util::GetApplicationLocale(std::string()) + ".pak";
   int pak_fd = base::android::OpenApkAsset(locale, &pak_region);
   if (pak_fd != -1) {
     ui::ResourceBundle::CleanupSharedInstance();
@@ -74,7 +75,8 @@
 
   // Try to directly mmap the webviewchromium.pak from the apk. Fall back to
   // load from file, using PATH_SERVICE, otherwise.
-  pak_fd = base::android::OpenApkAsset("webviewchromium.pak", &pak_region);
+  pak_fd = base::android::OpenApkAsset("assets/webviewchromium.pak",
+                                       &pak_region);
   if (pak_fd != -1) {
     ui::ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion(
         base::File(pak_fd), pak_region, ui::SCALE_FACTOR_NONE);
diff --git a/android_webview/browser/hardware_renderer.cc b/android_webview/browser/hardware_renderer.cc
index d9760d2b..7e271ce3 100644
--- a/android_webview/browser/hardware_renderer.cc
+++ b/android_webview/browser/hardware_renderer.cc
@@ -15,14 +15,14 @@
 #include "base/auto_reset.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/trace_event/trace_event.h"
-#include "cc/layers/delegated_frame_provider.h"
-#include "cc/layers/delegated_renderer_layer.h"
-#include "cc/layers/layer.h"
 #include "cc/output/compositor_frame.h"
 #include "cc/output/output_surface.h"
-#include "cc/scheduler/begin_frame_source.h"
-#include "cc/trees/layer_tree_host.h"
-#include "cc/trees/layer_tree_settings.h"
+#include "cc/output/renderer_settings.h"
+#include "cc/quads/shared_quad_state.h"
+#include "cc/quads/surface_draw_quad.h"
+#include "cc/surfaces/display.h"
+#include "cc/surfaces/surface_factory.h"
+#include "cc/surfaces/surface_id_allocator.h"
 #include "gpu/command_buffer/client/gl_in_process_context.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "ui/gfx/geometry/rect_conversions.h"
@@ -30,79 +30,46 @@
 #include "ui/gfx/transform.h"
 #include "ui/gl/gl_bindings.h"
 
-namespace {
-cc::LayerSettings HardwareRendererLayerSettings() {
-  return cc::LayerSettings();
-}
-}
-
 namespace android_webview {
 
 HardwareRenderer::HardwareRenderer(SharedRendererState* state)
     : shared_renderer_state_(state),
       last_egl_context_(eglGetCurrentContext()),
-      stencil_enabled_(false),
-      viewport_clip_valid_for_dcheck_(false),
       gl_surface_(new AwGLSurface),
-      root_layer_(cc::Layer::Create(HardwareRendererLayerSettings())),
-      resource_collection_(new cc::DelegatedFrameResourceCollection),
       output_surface_(NULL) {
   DCHECK(last_egl_context_);
 
-  resource_collection_->SetClient(this);
-
-  cc::LayerTreeSettings settings;
+  cc::RendererSettings settings;
 
   // Should be kept in sync with compositor_impl_android.cc.
-  settings.renderer_settings.allow_antialiasing = false;
-  settings.renderer_settings.highp_threshold_min = 2048;
+  settings.allow_antialiasing = false;
+  settings.highp_threshold_min = 2048;
 
   // Webview does not own the surface so should not clear it.
-  settings.renderer_settings.should_clear_root_render_pass = false;
+  settings.should_clear_root_render_pass = false;
 
-  // TODO(enne): Update this this compositor to use a synchronous scheduler.
-  settings.single_thread_proxy_scheduler = false;
-
-  cc::LayerTreeHost::InitParams params;
-  params.client = this;
-  params.settings = &settings;
-  layer_tree_host_ = cc::LayerTreeHost::CreateSingleThreaded(this, &params);
-  layer_tree_host_->SetRootLayer(root_layer_);
-  layer_tree_host_->SetLayerTreeHostClientReady();
-  layer_tree_host_->set_has_transparent_background(true);
+  surface_manager_.reset(new cc::SurfaceManager);
+  surface_id_allocator_.reset(new cc::SurfaceIdAllocator(1));
+  display_.reset(new cc::Display(this, surface_manager_.get(), nullptr, nullptr,
+                                 settings));
+  surface_factory_.reset(new cc::SurfaceFactory(surface_manager_.get(), this));
 }
 
 HardwareRenderer::~HardwareRenderer() {
-  // Must reset everything before |resource_collection_| to ensure all
-  // resources are returned before resetting |resource_collection_| client.
-  layer_tree_host_.reset();
-  root_layer_ = NULL;
-  delegated_layer_ = NULL;
-  frame_provider_ = NULL;
-#if DCHECK_IS_ON()
-  // Check collection is empty.
-  cc::ReturnedResourceArray returned_resources;
-  resource_collection_->TakeUnusedResourcesForChildCompositor(
-      &returned_resources);
-  DCHECK_EQ(0u, returned_resources.size());
-#endif  // DCHECK_IS_ON()
-
-  resource_collection_->SetClient(NULL);
+  // Must reset everything before |surface_factory_| to ensure all
+  // resources are returned before resetting.
+  if (!root_id_.is_null())
+    surface_factory_->Destroy(root_id_);
+  if (!child_id_.is_null())
+    surface_factory_->Destroy(child_id_);
+  display_.reset();
+  surface_factory_.reset();
 
   // Reset draw constraints.
   shared_renderer_state_->PostExternalDrawConstraintsToChildCompositorOnRT(
       ParentCompositorDrawConstraints());
 }
 
-void HardwareRenderer::DidBeginMainFrame() {
-  // This is called after OutputSurface is created, but before the impl frame
-  // starts. We set the draw constraints here.
-  DCHECK(output_surface_);
-  DCHECK(viewport_clip_valid_for_dcheck_);
-  output_surface_->SetExternalStencilTest(stencil_enabled_);
-  output_surface_->SetDrawConstraints(viewport_, clip_);
-}
-
 void HardwareRenderer::CommitFrame() {
   TRACE_EVENT0("android_webview", "CommitFrame");
   scroll_offset_ = shared_renderer_state_->GetScrollOffsetOnRT();
@@ -119,35 +86,24 @@
   DCHECK(!frame->gl_frame_data);
   DCHECK(!frame->software_frame_data);
 
-  // DelegatedRendererLayerImpl applies the inverse device_scale_factor of the
-  // renderer frame, assuming that the browser compositor will scale
-  // it back up to device scale.  But on Android we put our browser layers in
-  // physical pixels and set our browser CC device_scale_factor to 1, so this
-  // suppresses the transform.
+  // On Android we put our browser layers in physical pixels and set our
+  // browser CC device_scale_factor to 1, so suppress the transform between
+  // DIP and pixels.
   frame->delegated_frame_data->device_scale_factor = 1.0f;
 
   gfx::Size frame_size =
       frame->delegated_frame_data->render_pass_list.back()->output_rect.size();
   bool size_changed = frame_size != frame_size_;
   frame_size_ = frame_size;
-
-  if (!frame_provider_.get() || size_changed) {
-    if (delegated_layer_.get()) {
-      delegated_layer_->RemoveFromParent();
-    }
-
-    frame_provider_ = new cc::DelegatedFrameProvider(
-        resource_collection_.get(), frame->delegated_frame_data.Pass());
-
-    delegated_layer_ = cc::DelegatedRendererLayer::Create(
-        HardwareRendererLayerSettings(), frame_provider_);
-    delegated_layer_->SetBounds(frame_size_);
-    delegated_layer_->SetIsDrawable(true);
-
-    root_layer_->AddChild(delegated_layer_);
-  } else {
-    frame_provider_->SetFrameData(frame->delegated_frame_data.Pass());
+  if (child_id_.is_null() || size_changed) {
+    if (!child_id_.is_null())
+      surface_factory_->Destroy(child_id_);
+    child_id_ = surface_id_allocator_->GenerateId();
+    surface_factory_->Create(child_id_);
   }
+
+  surface_factory_->SubmitFrame(child_id_, frame.Pass(),
+                                cc::SurfaceFactory::DrawCallback());
 }
 
 void HardwareRenderer::DrawGL(bool stencil_enabled,
@@ -168,58 +124,77 @@
   transform.matrix().setColMajorf(draw_info->transform);
   transform.Translate(scroll_offset_.x(), scroll_offset_.y());
 
-  viewport_.SetSize(draw_info->width, draw_info->height);
+  gfx::Size viewport(draw_info->width, draw_info->height);
   // Need to post the new transform matrix back to child compositor
   // because there is no onDraw during a Render Thread animation, and child
   // compositor might not have the tiles rasterized as the animation goes on.
   ParentCompositorDrawConstraints draw_constraints(
-      draw_info->is_layer, transform, gfx::Rect(viewport_));
+      draw_info->is_layer, transform, gfx::Rect(viewport));
   if (!child_frame_.get() || draw_constraints.NeedUpdate(*child_frame_)) {
     shared_renderer_state_->PostExternalDrawConstraintsToChildCompositorOnRT(
         draw_constraints);
   }
 
-  if (!delegated_layer_.get())
+  if (child_id_.is_null())
     return;
 
-  layer_tree_host_->SetViewportSize(viewport_);
-  clip_.SetRect(draw_info->clip_left,
-                draw_info->clip_top,
-                draw_info->clip_right - draw_info->clip_left,
-                draw_info->clip_bottom - draw_info->clip_top);
-  stencil_enabled_ = stencil_enabled;
+  gfx::Rect clip(draw_info->clip_left, draw_info->clip_top,
+                 draw_info->clip_right - draw_info->clip_left,
+                 draw_info->clip_bottom - draw_info->clip_top);
 
-  delegated_layer_->SetTransform(transform);
+  // Create a frame with a single SurfaceDrawQuad referencing the child
+  // Surface and transformed using the given transform.
+  scoped_ptr<cc::RenderPass> render_pass = cc::RenderPass::Create();
+  render_pass->SetAll(cc::RenderPassId(1, 1), gfx::Rect(viewport), clip,
+                      gfx::Transform(), true);
+
+  cc::SharedQuadState* quad_state =
+      render_pass->CreateAndAppendSharedQuadState();
+  quad_state->content_to_target_transform = transform;
+  quad_state->content_bounds = frame_size_;
+  quad_state->visible_content_rect = gfx::Rect(frame_size_);
+  quad_state->opacity = 1.f;
+
+  cc::SurfaceDrawQuad* surface_quad =
+      render_pass->CreateAndAppendDrawQuad<cc::SurfaceDrawQuad>();
+  surface_quad->SetNew(quad_state, gfx::Rect(quad_state->content_bounds),
+                       gfx::Rect(quad_state->content_bounds), child_id_);
+
+  scoped_ptr<cc::DelegatedFrameData> delegated_frame(
+      new cc::DelegatedFrameData);
+  delegated_frame->render_pass_list.push_back(render_pass.Pass());
+  scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
+  frame->delegated_frame_data = delegated_frame.Pass();
+
+  if (root_id_.is_null()) {
+    root_id_ = surface_id_allocator_->GenerateId();
+    surface_factory_->Create(root_id_);
+    display_->SetSurfaceId(root_id_, 1.f);
+  }
+  surface_factory_->SubmitFrame(root_id_, frame.Pass(),
+                                cc::SurfaceFactory::DrawCallback());
+
+  display_->Resize(viewport);
 
   gl_surface_->SetBackingFrameBufferObject(framebuffer_binding_ext);
-  {
-    base::AutoReset<bool> frame_resetter(&viewport_clip_valid_for_dcheck_,
-                                         true);
-    layer_tree_host_->SetNeedsRedrawRect(clip_);
-    layer_tree_host_->Composite(base::TimeTicks::Now());
+  if (!output_surface_) {
+    scoped_refptr<cc::ContextProvider> context_provider =
+        AwRenderThreadContextProvider::Create(
+            gl_surface_, DeferredGpuCommandService::GetInstance());
+    scoped_ptr<ParentOutputSurface> output_surface_holder(
+        new ParentOutputSurface(context_provider));
+    output_surface_ = output_surface_holder.get();
+    display_->Initialize(output_surface_holder.Pass(), nullptr);
   }
+  output_surface_->SetExternalStencilTest(stencil_enabled);
+  display_->SetExternalClip(clip);
+  display_->DrawAndSwap();
   gl_surface_->ResetBackingFrameBufferObject();
 }
 
-void HardwareRenderer::RequestNewOutputSurface() {
-  scoped_refptr<cc::ContextProvider> context_provider =
-      AwRenderThreadContextProvider::Create(
-          gl_surface_, DeferredGpuCommandService::GetInstance());
-  scoped_ptr<ParentOutputSurface> output_surface_holder(
-      new ParentOutputSurface(context_provider));
-  output_surface_ = output_surface_holder.get();
-  layer_tree_host_->SetOutputSurface(output_surface_holder.Pass());
-}
-
-void HardwareRenderer::DidFailToInitializeOutputSurface() {
-  RequestNewOutputSurface();
-}
-
-void HardwareRenderer::UnusedResourcesAreAvailable() {
-  cc::ReturnedResourceArray returned_resources;
-  resource_collection_->TakeUnusedResourcesForChildCompositor(
-      &returned_resources);
-  shared_renderer_state_->InsertReturnedResourcesOnRT(returned_resources);
+void HardwareRenderer::ReturnResources(
+    const cc::ReturnedResourceArray& resources) {
+  shared_renderer_state_->InsertReturnedResourcesOnRT(resources);
 }
 
 }  // namespace android_webview
diff --git a/android_webview/browser/hardware_renderer.h b/android_webview/browser/hardware_renderer.h
index f06501f..bc937131 100644
--- a/android_webview/browser/hardware_renderer.h
+++ b/android_webview/browser/hardware_renderer.h
@@ -7,17 +7,17 @@
 
 #include "android_webview/browser/shared_renderer_state.h"
 #include "base/memory/scoped_ptr.h"
-#include "cc/layers/delegated_frame_resource_collection.h"
-#include "cc/trees/layer_tree_host_client.h"
-#include "cc/trees/layer_tree_host_single_thread_client.h"
+#include "cc/surfaces/display_client.h"
+#include "cc/surfaces/surface_factory_client.h"
+#include "cc/surfaces/surface_id.h"
 
 struct AwDrawGLInfo;
 
 namespace cc {
-class DelegatedFrameProvider;
-class DelegatedRendererLayer;
-class Layer;
-class LayerTreeHost;
+class Display;
+class SurfaceFactory;
+class SurfaceIdAllocator;
+class SurfaceManager;
 }
 
 namespace android_webview {
@@ -26,9 +26,8 @@
 class ChildFrame;
 class ParentOutputSurface;
 
-class HardwareRenderer : public cc::LayerTreeHostClient,
-                         public cc::LayerTreeHostSingleThreadClient,
-                         public cc::DelegatedFrameResourceCollectionClient {
+class HardwareRenderer : public cc::DisplayClient,
+                         public cc::SurfaceFactoryClient {
  public:
   explicit HardwareRenderer(SharedRendererState* state);
   ~HardwareRenderer() override;
@@ -38,34 +37,16 @@
               AwDrawGLInfo* draw_info);
   void CommitFrame();
 
-  // cc::LayerTreeHostClient overrides.
-  void WillBeginMainFrame() override {}
-  void DidBeginMainFrame() override;
-  void BeginMainFrame(const cc::BeginFrameArgs& args) override {}
-  void BeginMainFrameNotExpectedSoon() override {}
-  void Layout() override {}
-  void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta,
-                           const gfx::Vector2dF& outer_delta,
-                           const gfx::Vector2dF& elastic_overscroll_delta,
-                           float page_scale,
-                           float top_controls_delta) override {}
-  void RequestNewOutputSurface() override;
-  void DidInitializeOutputSurface() override {}
-  void DidFailToInitializeOutputSurface() override;
-  void WillCommit() override {}
-  void DidCommit() override {}
-  void DidCommitAndDrawFrame() override {}
-  void DidCompleteSwapBuffers() override {}
-  void DidCompletePageScaleAnimation() override {}
-
-  // cc::LayerTreeHostSingleThreadClient overrides.
-  void DidPostSwapBuffers() override {}
-  void DidAbortSwapBuffers() override {}
-
-  // cc::DelegatedFrameResourceCollectionClient overrides.
-  void UnusedResourcesAreAvailable() override;
-
  private:
+  // cc::DisplayClient overrides.
+  void CommitVSyncParameters(base::TimeTicks timebase,
+                             base::TimeDelta interval) override {}
+  void OutputSurfaceLost() override {}
+  void SetMemoryPolicy(const cc::ManagedMemoryPolicy& policy) override {}
+
+  // cc::SurfaceFactoryClient implementation.
+  void ReturnResources(const cc::ReturnedResourceArray& resources) override;
+
   SharedRendererState* shared_renderer_state_;
 
   typedef void* EGLContext;
@@ -77,24 +58,18 @@
   // Infromation from UI on last commit.
   gfx::Vector2d scroll_offset_;
 
-  // Information from draw.
-  gfx::Size viewport_;
-  gfx::Rect clip_;
-  bool stencil_enabled_;
-  bool viewport_clip_valid_for_dcheck_;
-
   scoped_ptr<ChildFrame> child_frame_;
 
   scoped_refptr<AwGLSurface> gl_surface_;
 
-  scoped_ptr<cc::LayerTreeHost> layer_tree_host_;
-  scoped_refptr<cc::Layer> root_layer_;
+  scoped_ptr<cc::SurfaceManager> surface_manager_;
+  scoped_ptr<cc::Display> display_;
+  scoped_ptr<cc::SurfaceFactory> surface_factory_;
+  scoped_ptr<cc::SurfaceIdAllocator> surface_id_allocator_;
+  cc::SurfaceId child_id_;
+  cc::SurfaceId root_id_;
 
-  scoped_refptr<cc::DelegatedFrameResourceCollection> resource_collection_;
-  scoped_refptr<cc::DelegatedFrameProvider> frame_provider_;
-  scoped_refptr<cc::DelegatedRendererLayer> delegated_layer_;
-
-  // This is owned indirectly by |layer_tree_host_|.
+  // This is owned by |display_|.
   ParentOutputSurface* output_surface_;
 
   DISALLOW_COPY_AND_ASSIGN(HardwareRenderer);
diff --git a/android_webview/browser/parent_output_surface.cc b/android_webview/browser/parent_output_surface.cc
index 0680bc72..2ef7aa5 100644
--- a/android_webview/browser/parent_output_surface.cc
+++ b/android_webview/browser/parent_output_surface.cc
@@ -18,20 +18,14 @@
 ParentOutputSurface::~ParentOutputSurface() {
 }
 
+void ParentOutputSurface::Reshape(const gfx::Size& size, float scale_factor) {
+  DCHECK_EQ(1.f, scale_factor);
+  surface_size_ = size;
+}
+
 void ParentOutputSurface::SwapBuffers(cc::CompositorFrame* frame) {
   context_provider_->ContextGL()->ShallowFlushCHROMIUM();
   client_->DidSwapBuffers();
 }
 
-void ParentOutputSurface::SetDrawConstraints(const gfx::Size& surface_size,
-                                             const gfx::Rect& clip) {
-  DCHECK(client_);
-  surface_size_ = surface_size;
-  const gfx::Transform identity;
-  const gfx::Rect empty;
-  const bool resourceless_software_draw = false;
-  SetExternalDrawConstraints(
-      identity, empty, clip, clip, identity, resourceless_software_draw);
-}
-
 }  // namespace android_webview
diff --git a/android_webview/browser/parent_output_surface.h b/android_webview/browser/parent_output_surface.h
index 442501da..6fca5358 100644
--- a/android_webview/browser/parent_output_surface.h
+++ b/android_webview/browser/parent_output_surface.h
@@ -16,12 +16,10 @@
   ~ParentOutputSurface() override;
 
   // OutputSurface overrides.
-  void Reshape(const gfx::Size& size, float scale_factor) override {}
+  void Reshape(const gfx::Size& size, float scale_factor) override;
   void SwapBuffers(cc::CompositorFrame* frame) override;
   using cc::OutputSurface::SetExternalStencilTest;
 
-  void SetDrawConstraints(const gfx::Size& surface_size, const gfx::Rect& clip);
-
  private:
   DISALLOW_COPY_AND_ASSIGN(ParentOutputSurface);
 };
diff --git a/android_webview/common/aw_crash_handler.cc b/android_webview/common/aw_crash_handler.cc
deleted file mode 100644
index ae0f0454..0000000
--- a/android_webview/common/aw_crash_handler.cc
+++ /dev/null
@@ -1,118 +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 "android_webview/common/aw_crash_handler.h"
-
-#include <android/log.h>
-#include <signal.h>
-#include <sys/prctl.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-
-#include "base/logging.h"
-#include "build/build_config.h"
-
-namespace {
-
-const int kExceptionSignals[] = {
-  SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS
-};
-
-struct sigaction old_handlers[arraysize(kExceptionSignals)];
-
-bool crash_handler_registered;
-
-std::string g_crash_msg;
-
-const char* g_crash_msg_ptr;  // Avoid invoking STL magic in a signal handler.
-
-void AwExceptionHandler(int sig, siginfo_t* info, void* uc) {
-  if (g_crash_msg_ptr != NULL)
-    __android_log_write(ANDROID_LOG_ERROR, "chromium", g_crash_msg_ptr);
-
-  // Detect if some buggy code in the embedder did reinstall the handler using
-  // signal() instead of sigaction() (which would cause |info| to be invalid).
-  struct sigaction cur_handler;
-  if (sigaction(sig, NULL, &cur_handler) != 0 ||
-      (cur_handler.sa_flags & SA_SIGINFO) == 0) {
-    info = NULL;
-  }
-
-  // We served our purpose. Now restore the old crash handlers. If the embedder
-  // did register a custom crash handler, it will be invoked by the kernel after
-  // this function returns. Otherwise, this will end up invoking the default
-  // signal disposition.
-  for (uint32_t i = 0; i < arraysize(kExceptionSignals); ++i) {
-    if (sigaction(kExceptionSignals[i], &old_handlers[i], NULL) == -1) {
-      signal(kExceptionSignals[i], SIG_DFL);
-    }
-  }
-
-  if ((info != NULL && SI_FROMUSER(info)) || sig == SIGABRT) {
-    // This signal was triggered by somebody sending us the signal with kill().
-    // In order to retrigger it, we have to queue a new signal by calling
-    // kill() ourselves.  The special case (si_pid == 0 && sig == SIGABRT) is
-    // due to the kernel sending a SIGABRT from a user request via SysRQ.
-    if (syscall(__NR_tgkill, getpid(), syscall(__NR_gettid), sig) < 0) {
-      // If we failed to kill ourselves resort to terminating uncleanly.
-      exit(1);
-    }
-  }
-}
-
-}  // namespace
-
-namespace android_webview {
-namespace crash_handler {
-
-void RegisterCrashHandler(const std::string& version) {
-#if defined(ARCH_CPU_X86_FAMILY)
-  // Don't install signal handler on X86/64 because this breaks binary
-  // translators that handle SIGSEGV in userspace and get chained after our
-  // handler. See crbug.com/477444
-  return;
-#endif
-
-  if (crash_handler_registered) {
-    NOTREACHED();
-    return;
-  }
-
-  g_crash_msg = "### WebView " + version;
-  g_crash_msg_ptr = g_crash_msg.c_str();
-
-  // Fail if unable to store all the old handlers.
-  for (uint32_t i = 0; i < arraysize(kExceptionSignals); ++i) {
-    if (sigaction(kExceptionSignals[i], NULL, &old_handlers[i]) == -1) {
-      LOG(ERROR) << "Error while trying to retrieve old handler for signal "
-                 << kExceptionSignals[i] << ")";
-      return;
-    }
-  }
-
-  struct sigaction sa;
-  memset(&sa, 0, sizeof(sa));
-  sigemptyset(&sa.sa_mask);
-
-  // Mask all exception signals when we're handling one of them.
-  for (uint32_t i = 0; i < arraysize(kExceptionSignals); ++i)
-    sigaddset(&sa.sa_mask, kExceptionSignals[i]);
-
-  sa.sa_sigaction = AwExceptionHandler;
-  sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
-
-  for (uint32_t i = 0; i < arraysize(kExceptionSignals); ++i) {
-    if (sigaction(kExceptionSignals[i], &sa, NULL) == -1) {
-      // At this point it is impractical to back out changes, and so failure to
-      // install a signal is intentionally ignored.
-      LOG(ERROR) << "Error while overriding handler for signal "
-                 << kExceptionSignals[i];
-    }
-  }
-
-  crash_handler_registered = true;
-}
-
-}  // namespace crash_handler
-}  // namespace android_webview
diff --git a/android_webview/common/aw_crash_handler.h b/android_webview/common/aw_crash_handler.h
deleted file mode 100644
index 60e1d15..0000000
--- a/android_webview/common/aw_crash_handler.h
+++ /dev/null
@@ -1,18 +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 ANDROID_WEBVIEW_COMMON_AW_CRASH_HANDLER_H_
-#define ANDROID_WEBVIEW_COMMON_AW_CRASH_HANDLER_H_
-
-#include <string>
-
-namespace android_webview {
-namespace crash_handler {
-
-void RegisterCrashHandler(const std::string& version);
-
-}  // namespace crash_handler
-}  // namespace android_webview
-
-#endif  // ANDROID_WEBVIEW_COMMON_AW_CRASH_HANDLER_H_
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
index d608ac9..5ef433e4 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -129,10 +129,6 @@
 
         final PackageInfo packageInfo = WebViewFactory.getLoadedPackageInfo();
 
-        // Register the handler that will append the WebView version to logcat in case of a crash.
-        AwContentsStatics.registerCrashHandler(
-                "Version " + packageInfo.versionName + " (code " + packageInfo.versionCode + ")");
-
         // Load glue-layer support library.
         System.loadLibrary("webviewchromium_plat_support");
 
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewContentsClientAdapter.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewContentsClientAdapter.java
index 8412516..69f8ace9 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewContentsClientAdapter.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewContentsClientAdapter.java
@@ -630,7 +630,7 @@
         try {
             TraceEvent.begin("WebViewContentsClientAdapter.onReceivedTitle");
             if (mWebChromeClient != null) {
-                if (TRACE) Log.d(TAG, "onReceivedTitle");
+                if (TRACE) Log.d(TAG, "onReceivedTitle=\"" + title + "\"");
                 mWebChromeClient.onReceivedTitle(mWebView, title);
             }
         } finally {
@@ -1165,10 +1165,10 @@
                 result = mWebChromeClient.getDefaultVideoPoster();
             }
             if (result == null) {
-                // The ic_media_video_poster icon is transparent so we need to draw it on a gray
-                // background.
+                // The ic_play_circle_outline_black_48dp icon is transparent so we need to draw it
+                // on a gray background.
                 Bitmap poster = BitmapFactory.decodeResource(
-                        mContext.getResources(), R.drawable.ic_media_video_poster);
+                        mContext.getResources(), R.drawable.ic_play_circle_outline_black_48dp);
                 result = Bitmap.createBitmap(
                         poster.getWidth(), poster.getHeight(), poster.getConfig());
                 result.eraseColor(Color.GRAY);
diff --git a/android_webview/java/res/drawable-hdpi/ic_media_video_poster.png b/android_webview/java/res/drawable-hdpi/ic_media_video_poster.png
deleted file mode 100644
index 77b6b0e..0000000
--- a/android_webview/java/res/drawable-hdpi/ic_media_video_poster.png
+++ /dev/null
Binary files differ
diff --git a/android_webview/java/res/drawable-hdpi/ic_play_circle_outline_black_48dp.png b/android_webview/java/res/drawable-hdpi/ic_play_circle_outline_black_48dp.png
new file mode 100644
index 0000000..c5e3f91
--- /dev/null
+++ b/android_webview/java/res/drawable-hdpi/ic_play_circle_outline_black_48dp.png
Binary files differ
diff --git a/android_webview/java/res/drawable-ldpi/ic_media_video_poster.png b/android_webview/java/res/drawable-ldpi/ic_media_video_poster.png
deleted file mode 100644
index 7b34913..0000000
--- a/android_webview/java/res/drawable-ldpi/ic_media_video_poster.png
+++ /dev/null
Binary files differ
diff --git a/android_webview/java/res/drawable-mdpi/ic_media_video_poster.png b/android_webview/java/res/drawable-mdpi/ic_media_video_poster.png
deleted file mode 100644
index f457f23..0000000
--- a/android_webview/java/res/drawable-mdpi/ic_media_video_poster.png
+++ /dev/null
Binary files differ
diff --git a/android_webview/java/res/drawable-mdpi/ic_play_circle_outline_black_48dp.png b/android_webview/java/res/drawable-mdpi/ic_play_circle_outline_black_48dp.png
new file mode 100644
index 0000000..a9e0143
--- /dev/null
+++ b/android_webview/java/res/drawable-mdpi/ic_play_circle_outline_black_48dp.png
Binary files differ
diff --git a/android_webview/java/res/drawable-xhdpi/ic_media_video_poster.png b/android_webview/java/res/drawable-xhdpi/ic_media_video_poster.png
deleted file mode 100644
index 4aa4904..0000000
--- a/android_webview/java/res/drawable-xhdpi/ic_media_video_poster.png
+++ /dev/null
Binary files differ
diff --git a/android_webview/java/res/drawable-xhdpi/ic_play_circle_outline_black_48dp.png b/android_webview/java/res/drawable-xhdpi/ic_play_circle_outline_black_48dp.png
new file mode 100644
index 0000000..ad7ebd261
--- /dev/null
+++ b/android_webview/java/res/drawable-xhdpi/ic_play_circle_outline_black_48dp.png
Binary files differ
diff --git a/android_webview/java/res/drawable-xxhdpi/ic_play_circle_outline_black_48dp.png b/android_webview/java/res/drawable-xxhdpi/ic_play_circle_outline_black_48dp.png
new file mode 100644
index 0000000..8b4b318
--- /dev/null
+++ b/android_webview/java/res/drawable-xxhdpi/ic_play_circle_outline_black_48dp.png
Binary files differ
diff --git a/android_webview/java/res/drawable-xxxhdpi/ic_play_circle_outline_black_48dp.png b/android_webview/java/res/drawable-xxxhdpi/ic_play_circle_outline_black_48dp.png
new file mode 100644
index 0000000..86a407d
--- /dev/null
+++ b/android_webview/java/res/drawable-xxxhdpi/ic_play_circle_outline_black_48dp.png
Binary files differ
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java b/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java
index 4427533b..4fd2fc8 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentViewClient.java
@@ -89,7 +89,7 @@
 
     @Override
     public void onUpdateTitle(String title) {
-        mAwContentsClient.onReceivedTitle(title);
+        mAwContentsClient.updateTitle(title, true);
     }
 
     @Override
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java
index 5a07dc8..71656c5 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClient.java
@@ -13,6 +13,7 @@
 import android.net.http.SslError;
 import android.os.Looper;
 import android.os.Message;
+import android.text.TextUtils;
 import android.view.KeyEvent;
 import android.view.View;
 import android.webkit.ConsoleMessage;
@@ -44,6 +45,12 @@
     // Last background color reported from the renderer. Holds the sentinal value INVALID_COLOR
     // if not valid.
     private int mCachedRendererBackgroundColor = INVALID_COLOR;
+    // Holds the last known page title. {@link ContentViewClient#onUpdateTitle} is unreliable,
+    // particularly for navigating backwards and forwards in the history stack. Instead, the last
+    // known document title is kept here, and the clients gets updated whenever the value has
+    // actually changed. Blink also only sends updates when the document title have changed,
+    // so behaviours are consistent.
+    private String mTitle = "";
 
     private static final int INVALID_COLOR = 0;
 
@@ -324,4 +331,10 @@
             View view, ActionHandler actionHandler, boolean floating);
 
     public abstract boolean supportsFloatingActionMode();
+
+    public void updateTitle(String title, boolean forceNotification) {
+        if (!forceNotification && TextUtils.equals(mTitle, title)) return;
+        mTitle = title;
+        mCallbackHelper.postOnReceivedTitle(mTitle);
+    }
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsClientCallbackHelper.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClientCallbackHelper.java
index 500d22c..838dbe0 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsClientCallbackHelper.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClientCallbackHelper.java
@@ -89,6 +89,7 @@
     private static final int MSG_ON_SCALE_CHANGED_SCALED = 7;
     private static final int MSG_ON_RECEIVED_HTTP_ERROR = 8;
     private static final int MSG_ON_PAGE_FINISHED = 9;
+    private static final int MSG_ON_RECEIVED_TITLE = 10;
 
     // Minimum period allowed between consecutive onNewPicture calls, to rate-limit the callbacks.
     private static final long ON_NEW_PICTURE_MIN_PERIOD_MILLIS = 500;
@@ -163,6 +164,11 @@
                     mContentsClient.onPageFinished(url);
                     break;
                 }
+                case MSG_ON_RECEIVED_TITLE: {
+                    final String title = (String) msg.obj;
+                    mContentsClient.onReceivedTitle(title);
+                    break;
+                }
                 default:
                     throw new IllegalStateException(
                             "AwContentsClientCallbackHelper: unhandled message " + msg.what);
@@ -229,4 +235,8 @@
     public void postOnPageFinished(String url) {
         mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_PAGE_FINISHED, url));
     }
+
+    public void postOnReceivedTitle(String title) {
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_RECEIVED_TITLE, title));
+    }
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java b/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java
index f38c7342..3f3efed 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java
@@ -78,13 +78,6 @@
         nativeSetRecordFullDocument(recordFullDocument);
     }
 
-    /*
-     * Register the signal handler that prints out the version code upon crash.
-     */
-    public static void registerCrashHandler(String version) {
-        nativeRegisterCrashHandler(version);
-    }
-
     public static void setLegacyCacheRemovalDelayForTest(long timeoutMs) {
         nativeSetLegacyCacheRemovalDelayForTest(timeoutMs);
     }
@@ -97,6 +90,5 @@
     private static native void nativeSetDataReductionProxyEnabled(boolean enabled);
     private static native String nativeGetUnreachableWebDataUrl();
     private static native void nativeSetRecordFullDocument(boolean recordFullDocument);
-    private static native void nativeRegisterCrashHandler(String version);
     private static native void nativeSetLegacyCacheRemovalDelayForTest(long timeoutMs);
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java
index bf5af89..e8c4a5d 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java
@@ -41,4 +41,9 @@
     @Override
     @CalledByNative
     public abstract void navigationStateChanged(int flags);
+
+    // Not an override, because WebContentsDelegateAndroid maps this call
+    // into onLoad{Started|Stopped}.
+    @CalledByNative
+    public abstract void loadingStateChanged();
 }
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
index e0e4451..0f84cc5 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
@@ -271,6 +271,11 @@
         }
     }
 
+    @Override
+    public void loadingStateChanged() {
+        mContentsClient.updateTitle(mAwContents.getTitle(), false);
+    }
+
     private static class GetDisplayNameTask extends AsyncTask<Void, Void, String[]> {
         final int mProcessId;
         final int mRenderId;
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java
index 504a19f..9f8f629 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java
@@ -332,4 +332,84 @@
             webServer.shutdown();
         }
     }
+
+    private static class OnReceivedTitleClient extends TestAwContentsClient {
+        void setOnReceivedTitleCallback(Runnable onReceivedTitleCallback) {
+            mOnReceivedTitleCallback = onReceivedTitleCallback;
+        }
+        @Override
+        public void onReceivedTitle(String title) {
+            super.onReceivedTitle(title);
+            mOnReceivedTitleCallback.run();
+        }
+        private Runnable mOnReceivedTitleCallback;
+    }
+
+    // See crbug.com/494929. Need to make sure that loading a javascript: URL
+    // from inside onReceivedTitle works.
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    public void testLoadUrlFromOnReceivedTitle() throws Throwable {
+        final OnReceivedTitleClient contentsClient = new OnReceivedTitleClient();
+        final AwTestContainerView testContainerView =
+                createAwTestContainerViewOnMainSync(contentsClient);
+        final AwContents awContents = testContainerView.getAwContents();
+        final AwSettings settings = getAwSettingsOnUiThread(awContents);
+        settings.setJavaScriptEnabled(true);
+
+        contentsClient.setOnReceivedTitleCallback(new Runnable() {
+            @Override
+            public void run() {
+                awContents.loadUrl("javascript:testProperty=42;void(0);");
+            }
+        });
+
+        TestWebServer webServer = TestWebServer.start();
+        try {
+            // We need to have a navigation entry, but with an empty title. Note that
+            // trying to load a page with no title makes the received title to be
+            // the URL of the page so instead we use a "204 No Content" response.
+            final String url = webServer.setResponseWithNoContentStatus("/page.html");
+            loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), url);
+            TestAwContentsClient.OnReceivedTitleHelper onReceivedTitleHelper =
+                    contentsClient.getOnReceivedTitleHelper();
+            final String pageTitle = "Hello, World!";
+            int onReceivedTitleCallCount = onReceivedTitleHelper.getCallCount();
+            loadUrlAsync(awContents, "javascript:document.title=\"" + pageTitle + "\";void(0);");
+            onReceivedTitleHelper.waitForCallback(onReceivedTitleCallCount);
+            assertEquals(pageTitle, onReceivedTitleHelper.getTitle());
+        } finally {
+            webServer.shutdown();
+        }
+    }
+
+    public void testOnReceivedTitleForUnchangingTitle() throws Throwable {
+        final TestAwContentsClient contentsClient = new TestAwContentsClient();
+        final AwTestContainerView testContainerView =
+                createAwTestContainerViewOnMainSync(contentsClient);
+        final AwContents awContents = testContainerView.getAwContents();
+
+        TestWebServer webServer = TestWebServer.start();
+        try {
+            final String title = "Title";
+            final String url1 = webServer.setResponse("/page1.html",
+                    "<html><head><title>" + title + "</title></head>Page 1</html>", null);
+            final String url2 = webServer.setResponse("/page2.html",
+                    "<html><head><title>" + title + "</title></head>Page 2</html>", null);
+            TestAwContentsClient.OnReceivedTitleHelper onReceivedTitleHelper =
+                    contentsClient.getOnReceivedTitleHelper();
+            int onReceivedTitleCallCount = onReceivedTitleHelper.getCallCount();
+            loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), url1);
+            onReceivedTitleHelper.waitForCallback(onReceivedTitleCallCount);
+            assertEquals(title, onReceivedTitleHelper.getTitle());
+            // Verify that even if we load another page with the same title,
+            // onReceivedTitle is still being called.
+            onReceivedTitleCallCount = onReceivedTitleHelper.getCallCount();
+            loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), url2);
+            onReceivedTitleHelper.waitForCallback(onReceivedTitleCallCount);
+            assertEquals(title, onReceivedTitleHelper.getTitle());
+        } finally {
+            webServer.shutdown();
+        }
+    }
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/NavigationHistoryTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/NavigationHistoryTest.java
index 5a8c75d..f8a97e64 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/NavigationHistoryTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/NavigationHistoryTest.java
@@ -320,4 +320,34 @@
             }
         });
     }
+
+    // See http://crbug.com/481570
+    @SmallTest
+    public void testTitleUpdatedWhenGoingBack() throws Throwable {
+        final TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper =
+                mContentsClient.getOnPageFinishedHelper();
+        NavigationHistory list = getNavigationHistory(mAwContents);
+        assertEquals(0, list.getEntryCount());
+
+        final String page1Url = addPage1ToServer(mWebServer);
+        final String page2Url = addPage2ToServer(mWebServer);
+
+        TestAwContentsClient.OnReceivedTitleHelper onReceivedTitleHelper =
+                mContentsClient.getOnReceivedTitleHelper();
+        // It would be unreliable to retrieve the call count after the first loadUrlSync,
+        // as it is not synchronous with respect to updating the title. Instead, we capture
+        // the initial call count (zero?) here, and keep waiting until we receive the update
+        // from the second page load.
+        int onReceivedTitleCallCount = onReceivedTitleHelper.getCallCount();
+        loadUrlSync(mAwContents, onPageFinishedHelper, page1Url);
+        loadUrlSync(mAwContents, onPageFinishedHelper, page2Url);
+        do {
+            onReceivedTitleHelper.waitForCallback(onReceivedTitleCallCount);
+            onReceivedTitleCallCount = onReceivedTitleHelper.getCallCount();
+        } while(!PAGE_2_TITLE.equals(onReceivedTitleHelper.getTitle()));
+        HistoryUtils.goBackSync(getInstrumentation(), mAwContents.getWebContents(),
+                onPageFinishedHelper);
+        onReceivedTitleHelper.waitForCallback(onReceivedTitleCallCount);
+        assertEquals(PAGE_1_TITLE, onReceivedTitleHelper.getTitle());
+    }
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
index d368612..42e9225 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
@@ -26,7 +26,6 @@
  * AwContentsClient subclass used for testing.
  */
 public class TestAwContentsClient extends NullContentsClient {
-    private String mUpdatedTitle;
     private boolean mAllowSslError;
     private final OnPageStartedHelper mOnPageStartedHelper;
     private final OnPageFinishedHelper mOnPageFinishedHelper;
@@ -40,6 +39,7 @@
     private final OnEvaluateJavaScriptResultHelper mOnEvaluateJavaScriptResultHelper;
     private final AddMessageToConsoleHelper mAddMessageToConsoleHelper;
     private final OnScaleChangedHelper mOnScaleChangedHelper;
+    private final OnReceivedTitleHelper mOnReceivedTitleHelper;
     private final PictureListenerHelper mPictureListenerHelper;
     private final ShouldOverrideUrlLoadingHelper mShouldOverrideUrlLoadingHelper;
     private final DoUpdateVisitedHistoryHelper mDoUpdateVisitedHistoryHelper;
@@ -59,6 +59,7 @@
         mOnEvaluateJavaScriptResultHelper = new OnEvaluateJavaScriptResultHelper();
         mAddMessageToConsoleHelper = new AddMessageToConsoleHelper();
         mOnScaleChangedHelper = new OnScaleChangedHelper();
+        mOnReceivedTitleHelper = new OnReceivedTitleHelper();
         mPictureListenerHelper = new PictureListenerHelper();
         mShouldOverrideUrlLoadingHelper = new ShouldOverrideUrlLoadingHelper();
         mDoUpdateVisitedHistoryHelper = new DoUpdateVisitedHistoryHelper();
@@ -156,13 +157,32 @@
         return mPictureListenerHelper;
     }
 
+    /**
+     * Callback helper for onReceivedTitle.
+     */
+    public static class OnReceivedTitleHelper extends CallbackHelper {
+        private String mTitle;
+
+        public void notifyCalled(String title) {
+            mTitle = title;
+            super.notifyCalled();
+        }
+        public String getTitle() {
+            return mTitle;
+        }
+    }
+
+    public OnReceivedTitleHelper getOnReceivedTitleHelper() {
+        return mOnReceivedTitleHelper;
+    }
+
     @Override
     public void onReceivedTitle(String title) {
-        mUpdatedTitle = title;
+        mOnReceivedTitleHelper.notifyCalled(title);
     }
 
     public String getUpdatedTitle() {
-        return mUpdatedTitle;
+        return mOnReceivedTitleHelper.getTitle();
     }
 
     @Override
diff --git a/android_webview/lib/main/aw_main_delegate.cc b/android_webview/lib/main/aw_main_delegate.cc
index 60ad9f82..fa67e9f 100644
--- a/android_webview/lib/main/aw_main_delegate.cc
+++ b/android_webview/lib/main/aw_main_delegate.cc
@@ -106,11 +106,11 @@
   // AwContentBrowserClient::GetAdditionalMappedFilesForChildProcess.
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
 #ifdef __LP64__
-  const char kNativesFileName[] = "natives_blob_64.bin";
-  const char kSnapshotFileName[] = "snapshot_blob_64.bin";
+  const char kNativesFileName[] = "assets/natives_blob_64.bin";
+  const char kSnapshotFileName[] = "assets/snapshot_blob_64.bin";
 #else
-  const char kNativesFileName[] = "natives_blob_32.bin";
-  const char kSnapshotFileName[] = "snapshot_blob_32.bin";
+  const char kNativesFileName[] = "assets/natives_blob_32.bin";
+  const char kSnapshotFileName[] = "assets/snapshot_blob_32.bin";
 #endif // __LP64__
   // TODO(gsennton) we should use
   // gin::IsolateHolder::kNativesFileName/kSnapshotFileName
@@ -121,7 +121,7 @@
       kV8SnapshotDataDescriptor, kSnapshotFileName));
 #endif
   CHECK(base::android::RegisterApkAssetWithGlobalDescriptors(
-      kAndroidICUDataDescriptor, base::i18n::kIcuDataFileName));
+      kAndroidICUDataDescriptor, "assets/icudtl.dat"));
 
   return false;
 }
diff --git a/android_webview/native/aw_contents_statics.cc b/android_webview/native/aw_contents_statics.cc
index 8c2be12..8e1e1121 100644
--- a/android_webview/native/aw_contents_statics.cc
+++ b/android_webview/native/aw_contents_statics.cc
@@ -6,7 +6,6 @@
 
 #include "android_webview/browser/aw_browser_context.h"
 #include "android_webview/browser/net/aw_url_request_context_getter.h"
-#include "android_webview/common/aw_crash_handler.h"
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/callback.h"
@@ -88,12 +87,6 @@
 }
 
 // static
-void RegisterCrashHandler(JNIEnv* env, jclass, jstring version) {
-  crash_handler::RegisterCrashHandler(
-      ConvertJavaStringToUTF8(env, version));
-}
-
-// static
 void SetLegacyCacheRemovalDelayForTest(JNIEnv*, jclass, jlong delay_ms) {
   AwBrowserContext::SetLegacyCacheRemovalDelayForTest(delay_ms);
 }
diff --git a/android_webview/native/aw_media_url_interceptor.cc b/android_webview/native/aw_media_url_interceptor.cc
index 6923d69..a2c1cdd 100644
--- a/android_webview/native/aw_media_url_interceptor.cc
+++ b/android_webview/native/aw_media_url_interceptor.cc
@@ -21,7 +21,8 @@
 
   if (StartsWithASCII(url, asset_file_prefix, true)) {
     std::string filename(url);
-    ReplaceFirstSubstringAfterOffset(&filename, 0, asset_file_prefix, "");
+    ReplaceFirstSubstringAfterOffset(
+        &filename, 0, asset_file_prefix, "assets/");
     base::MemoryMappedFile::Region region =
         base::MemoryMappedFile::Region::kWholeFile;
     *fd = base::android::OpenApkAsset(filename, &region);
diff --git a/android_webview/native/aw_web_contents_delegate.cc b/android_webview/native/aw_web_contents_delegate.cc
index db537c8d..cd4d9cf1 100644
--- a/android_webview/native/aw_web_contents_delegate.cc
+++ b/android_webview/native/aw_web_contents_delegate.cc
@@ -204,6 +204,18 @@
   }
 }
 
+void AwWebContentsDelegate::LoadingStateChanged(WebContents* source,
+                                                bool to_different_document) {
+  // Page title may have changed, need to inform the embedder.
+  // |source| may be null if loading has started.
+  JNIEnv* env = AttachCurrentThread();
+
+  ScopedJavaLocalRef<jobject> java_delegate = GetJavaDelegate(env);
+  if (java_delegate.obj()) {
+    Java_AwWebContentsDelegate_loadingStateChanged(env, java_delegate.obj());
+  }
+}
+
 void AwWebContentsDelegate::RequestMediaAccessPermission(
     WebContents* web_contents,
     const content::MediaStreamRequest& request,
diff --git a/android_webview/native/aw_web_contents_delegate.h b/android_webview/native/aw_web_contents_delegate.h
index 75f8845eb..e49587ed8 100644
--- a/android_webview/native/aw_web_contents_delegate.h
+++ b/android_webview/native/aw_web_contents_delegate.h
@@ -49,6 +49,8 @@
 
   void CloseContents(content::WebContents* source) override;
   void ActivateContents(content::WebContents* contents) override;
+  void LoadingStateChanged(content::WebContents* source,
+                           bool to_different_document) override;
   void RequestMediaAccessPermission(
       content::WebContents* web_contents,
       const content::MediaStreamRequest& request,
diff --git a/android_webview/test/shell/res/drawable/resource_icon.png b/android_webview/test/shell/res/drawable/resource_icon.png
deleted file mode 100644
index f381f86..0000000
--- a/android_webview/test/shell/res/drawable/resource_icon.png
+++ /dev/null
Binary files differ
diff --git a/android_webview/tools/copyright_scanner.py b/android_webview/tools/copyright_scanner.py
index fb403fde..0c6b3a9 100644
--- a/android_webview/tools/copyright_scanner.py
+++ b/android_webview/tools/copyright_scanner.py
@@ -376,8 +376,11 @@
     results.append(output_api.PresubmitError(
         'The following files contain a third-party license but are not in ' \
         'a listed third-party directory and are not whitelisted. You must ' \
-        'add the following files to the whitelist file ' \
-        '%s:' % _GetWhitelistFileName(input_api),
+        'add the following files to the whitelist file %s\n' \
+        '(Note that if the code you are adding does not actually contain ' \
+        'any third-party code, it may contain the word "copyright", which ' \
+        'should be masked out, e.g. by writing it as "copy-right"):' \
+        '' % _GetWhitelistFileName(input_api),
         sorted(unknown_files)))
   if missing_files:
     results.append(output_api.PresubmitPromptWarning(
diff --git a/android_webview/tools/webview_licenses.py b/android_webview/tools/webview_licenses.py
index 6b87fc7d..ebd46095 100755
--- a/android_webview/tools/webview_licenses.py
+++ b/android_webview/tools/webview_licenses.py
@@ -97,11 +97,14 @@
   if unknown:
     print 'The following files contain a third-party license but are not in ' \
           'a listed third-party directory and are not whitelisted. You must ' \
-          'add the following files to the whitelist.\n%s' % \
+          'add the following files to the whitelist.\n' \
+          '(Note that if the code you are adding does not actually contain ' \
+          'any third-party code, it may contain the word "copyright", which ' \
+          'should be masked out, e.g. by writing it as "copy-right")\n%s' % \
           '\n'.join(sorted(unknown))
   if missing:
     print 'The following files are whitelisted, but do not exist.\n%s' % \
-        '\n'.join(sorted(missing))
+          '\n'.join(sorted(missing))
   if stale:
     print 'The following files are whitelisted unnecessarily. You must ' \
           'remove the following files from the whitelist.\n%s' % \
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index 5a6dba78..6eb68a39 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -464,9 +464,7 @@
   wm::WindowState* window_state = wm::GetActiveWindowState();
   // Disable window snapping shortcut key for full screen window due to
   // http://crbug.com/135487.
-  return (window_state &&
-          (window_state->window()->type() == ui::wm::WINDOW_TYPE_NORMAL ||
-           window_state->window()->type() == ui::wm::WINDOW_TYPE_PANEL) &&
+  return (window_state && window_state->IsUserPositionable() &&
           !window_state->IsFullscreen());
 }
 
diff --git a/ash/accelerators/accelerator_filter_unittest.cc b/ash/accelerators/accelerator_filter_unittest.cc
index 1299136..a4e9c297 100644
--- a/ash/accelerators/accelerator_filter_unittest.cc
+++ b/ash/accelerators/accelerator_filter_unittest.cc
@@ -19,7 +19,6 @@
 #include "ui/aura/window.h"
 #include "ui/base/accelerators/accelerator_history.h"
 #include "ui/events/event.h"
-#include "ui/events/event_utils.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/gfx/geometry/rect.h"
 
@@ -135,34 +134,5 @@
 }
 #endif  // defined(OS_CHROMEOS)
 
-// Tests that pressing 'SEARCH' + LeftMouseClick, which will be rewritten as a
-// RightMouseClick, will not toggle the AppList.
-// This test will fail without the code to clear the current accelerator in
-// the accelerator history present in |AcceleratorFilter::OnMouseEvent()|.
-TEST_F(AcceleratorFilterTest, SearchClickDoesntToggleAppList) {
-  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
-
-  EXPECT_FALSE(ash::Shell::GetInstance()->GetAppListTargetVisibility());
-  generator.PressKey(ui::VKEY_LWIN, 0);
-  generator.ClickLeftButton();
-  generator.ReleaseKey(ui::VKEY_LWIN, 0);
-  EXPECT_FALSE(ash::Shell::GetInstance()->GetAppListTargetVisibility());
-}
-
-// Make sure that synthesized mouse events don't interfere with tracking
-// the key accelerators.
-TEST_F(AcceleratorFilterTest, SynthesizeMouseEventsAreIgnored) {
-  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
-  const gfx::Point origin(0, 0);
-
-  EXPECT_FALSE(ash::Shell::GetInstance()->GetAppListTargetVisibility());
-  generator.PressKey(ui::VKEY_LWIN, 0);
-  ui::MouseEvent mouse_event(ui::ET_MOUSE_MOVED, origin, origin,
-                             ui::EventTimeForNow(), ui::EF_IS_SYNTHESIZED, 0);
-  generator.Dispatch(&mouse_event);
-  generator.ReleaseKey(ui::VKEY_LWIN, 0);
-  EXPECT_TRUE(ash::Shell::GetInstance()->GetAppListTargetVisibility());
-}
-
 }  // namespace test
 }  // namespace ash
diff --git a/ash/content/display/screen_orientation_controller_chromeos.cc b/ash/content/display/screen_orientation_controller_chromeos.cc
index b0b28b3..0e63f65d 100644
--- a/ash/content/display/screen_orientation_controller_chromeos.cc
+++ b/ash/content/display/screen_orientation_controller_chromeos.cc
@@ -128,8 +128,10 @@
   }
 }
 
-void ScreenOrientationController::OnWindowActivated(aura::Window* gained_active,
-                                                    aura::Window* lost_active) {
+void ScreenOrientationController::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
   ApplyLockForActiveWindow();
 }
 
diff --git a/ash/content/display/screen_orientation_controller_chromeos.h b/ash/content/display/screen_orientation_controller_chromeos.h
index 93ac053..93a100dc 100644
--- a/ash/content/display/screen_orientation_controller_chromeos.h
+++ b/ash/content/display/screen_orientation_controller_chromeos.h
@@ -76,8 +76,10 @@
                           gfx::Display::RotationSource source);
 
   // aura::client::ActivationChangeObserver:
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
 
   // aura::WindowObserver:
   void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
diff --git a/ash/display/display_controller_unittest.cc b/ash/display/display_controller_unittest.cc
index 273b461..6b040774 100644
--- a/ash/display/display_controller_unittest.cc
+++ b/ash/display/display_controller_unittest.cc
@@ -114,8 +114,10 @@
   }
 
   // Overridden from aura::client::ActivationChangeObserver
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override {
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override {
     activation_changed_count_++;
   }
   void OnAttemptToReactivateWindow(aura::Window* request_active,
diff --git a/ash/display/projecting_observer_chromeos.cc b/ash/display/projecting_observer_chromeos.cc
index 0bf6af4..1e55cd2 100644
--- a/ash/display/projecting_observer_chromeos.cc
+++ b/ash/display/projecting_observer_chromeos.cc
@@ -17,6 +17,9 @@
       casting_session_count_(0),
       power_manager_client_(power_manager_client) {
   DCHECK(power_manager_client);
+#if defined(USE_OZONE)
+  is_initial_configuration_ = true;
+#endif
 }
 
 ProjectingObserver::~ProjectingObserver() {}
@@ -33,6 +36,13 @@
     }
   }
 
+#if defined(USE_OZONE)
+  if (is_initial_configuration_) {
+    is_initial_configuration_ = false;
+    return;
+  }
+#endif
+
   SetIsProjecting();
 }
 
diff --git a/ash/display/projecting_observer_chromeos.h b/ash/display/projecting_observer_chromeos.h
index 0c6b4d14..b9305dd 100644
--- a/ash/display/projecting_observer_chromeos.h
+++ b/ash/display/projecting_observer_chromeos.h
@@ -47,6 +47,14 @@
   // Weak pointer to the DBusClient PowerManagerClient;
   chromeos::PowerManagerClient* power_manager_client_;
 
+#if defined(USE_OZONE)
+  // TODO(dnicoara) Remove once merged to M43.
+  // Used to skip the first call to the power management during the initial
+  // display configuration to avoid changing power settings due to possibly
+  // invalid display configuration.
+  bool is_initial_configuration_;
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(ProjectingObserver);
 };
 
diff --git a/ash/display/projecting_observer_chromeos_unittest.cc b/ash/display/projecting_observer_chromeos_unittest.cc
index 06eb798..4196800 100644
--- a/ash/display/projecting_observer_chromeos_unittest.cc
+++ b/ash/display/projecting_observer_chromeos_unittest.cc
@@ -30,6 +30,14 @@
 
   ~ProjectingObserverTest() override {}
 
+#if defined(USE_OZONE)
+  void SetUp() override {
+    // First configuration event is ignored on Ozone to work around setting the
+    // wrong power state during startup.
+    observer_.OnDisplayModeChanged(std::vector<ui::DisplaySnapshot*>());
+  }
+#endif
+
  protected:
   chromeos::FakePowerManagerClient fake_power_client_;
   ProjectingObserver observer_;
diff --git a/ash/metrics/OWNERS b/ash/metrics/OWNERS
new file mode 100644
index 0000000..21cb7090
--- /dev/null
+++ b/ash/metrics/OWNERS
@@ -0,0 +1 @@
+tdanderson@chromium.org
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index c8a3aba4..3a5733ed 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -613,8 +613,7 @@
         GetContainer(kShellWindowId_DefaultContainer)->children();
     for (aura::Window::Windows::const_reverse_iterator iter = windows.rbegin();
          iter != windows.rend(); ++iter) {
-      if (((*iter)->type() == ui::wm::WINDOW_TYPE_NORMAL ||
-           (*iter)->type() == ui::wm::WINDOW_TYPE_PANEL) &&
+      if (wm::IsWindowUserPositionable(*iter) &&
           (*iter)->layer()->GetTargetVisibility()) {
         topmost_window = *iter;
         break;
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index e41b3490..75e273b3 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -529,8 +529,10 @@
   UpdateShelfVisibilityAfterLoginUIChange();
 }
 
-void ShelfLayoutManager::OnWindowActivated(aura::Window* gained_active,
-                                           aura::Window* lost_active) {
+void ShelfLayoutManager::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
   UpdateAutoHideStateNow();
 }
 
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index 240e765..40e1355e 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -176,8 +176,10 @@
   void OnLockStateChanged(bool locked) override;
 
   // Overriden from aura::client::ActivationChangeObserver:
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
 
   // Overridden from ash::LockStateObserver:
   void OnLockStateEvent(LockStateObserver::EventType event) override;
diff --git a/ash/shelf/shelf_window_watcher.cc b/ash/shelf/shelf_window_watcher.cc
index 3744687a..546d212 100644
--- a/ash/shelf/shelf_window_watcher.cc
+++ b/ash/shelf/shelf_window_watcher.cc
@@ -190,8 +190,10 @@
   RemoveShelfItem(window);
 }
 
-void ShelfWindowWatcher::OnWindowActivated(aura::Window* gained_active,
-                                           aura::Window* lost_active) {
+void ShelfWindowWatcher::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
   if (gained_active && HasShelfItemForWindow(gained_active))
     UpdateShelfItemStatus(gained_active, true);
   if (lost_active && HasShelfItemForWindow(lost_active))
diff --git a/ash/shelf/shelf_window_watcher.h b/ash/shelf/shelf_window_watcher.h
index 28c9b22..c9ffcbf 100644
--- a/ash/shelf/shelf_window_watcher.h
+++ b/ash/shelf/shelf_window_watcher.h
@@ -103,8 +103,10 @@
   void FinishObservingRemovedWindow(aura::Window* window);
 
   // aura::client::ActivationChangeObserver overrides:
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
 
   // aura::WindowObserver overrides:
   void OnWindowAdded(aura::Window* window) override;
diff --git a/ash/shell.cc b/ash/shell.cc
index fb61b55..8393cda6 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -1177,8 +1177,10 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Shell, aura::client::ActivationChangeObserver implementation:
 
-void Shell::OnWindowActivated(aura::Window* gained_active,
-                              aura::Window* lost_active) {
+void Shell::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
   if (gained_active)
     target_root_window_ = gained_active->GetRootWindow();
 }
diff --git a/ash/shell.h b/ash/shell.h
index 41af348..bba346ba 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -617,8 +617,10 @@
   void OnEvent(ui::Event* event) override;
 
   // Overridden from aura::client::ActivationChangeObserver:
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
 
   static Shell* instance_;
 
diff --git a/ash/shell/app_list.cc b/ash/shell/app_list.cc
index ec2071f..e2c9527fe 100644
--- a/ash/shell/app_list.cc
+++ b/ash/shell/app_list.cc
@@ -144,7 +144,7 @@
 WindowTypeShelfItem::WindowTypeShelfItem(const std::string& id, Type type)
     : app_list::AppListItem(id), type_(type) {
   std::string title(GetTitle(type));
-  SetIcon(GetIcon(type), false);
+  SetIcon(GetIcon(type));
   SetName(title);
 }
 
diff --git a/ash/shell/content_client/shell_content_browser_client.cc b/ash/shell/content_client/shell_content_browser_client.cc
index 51b0107d..5f2adc5 100644
--- a/ash/shell/content_client/shell_content_browser_client.cc
+++ b/ash/shell/content_client/shell_content_browser_client.cc
@@ -43,16 +43,17 @@
                                              request_interceptors.Pass());
 }
 
-void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
-    base::CommandLine* command_line,
-    int child_process_id) {
+void ShellContentBrowserClient::AppendMappedFileCommandLineSwitches(
+    base::CommandLine* command_line) {
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
   std::string process_type =
       command_line->GetSwitchValueASCII(switches::kProcessType);
   if (process_type != switches::kZygoteProcess) {
+    DCHECK(natives_fd_exists());
     command_line->AppendSwitch(::switches::kV8NativesPassedByFD);
-    command_line->AppendSwitch(::switches::kV8SnapshotPassedByFD);
+    if (snapshot_fd_exists())
+      command_line->AppendSwitch(::switches::kV8SnapshotPassedByFD);
   }
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
 #endif  // OS_POSIX && !OS_MACOSX
@@ -64,7 +65,7 @@
     int child_process_id,
     content::FileDescriptorInfo* mappings) {
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
-  if (v8_natives_fd_.get() == -1 || v8_snapshot_fd_.get() == -1) {
+  if (!natives_fd_exists()) {
     int v8_natives_fd = -1;
     int v8_snapshot_fd = -1;
     if (gin::V8Initializer::OpenV8FilesForChildProcesses(&v8_natives_fd,
@@ -73,7 +74,9 @@
       v8_snapshot_fd_.reset(v8_snapshot_fd);
     }
   }
-  DCHECK(v8_natives_fd_.get() != -1 && v8_snapshot_fd_.get() != -1);
+  // V8 can't start up without the source of the natives, but it can
+  // start up (slower) without the snapshot.
+  DCHECK(natives_fd_exists());
   mappings->Share(kV8NativesDataDescriptor, v8_natives_fd_.get());
   mappings->Share(kV8SnapshotDataDescriptor, v8_snapshot_fd_.get());
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
diff --git a/ash/shell/content_client/shell_content_browser_client.h b/ash/shell/content_client/shell_content_browser_client.h
index 9ee3373..432f45a5 100644
--- a/ash/shell/content_client/shell_content_browser_client.h
+++ b/ash/shell/content_client/shell_content_browser_client.h
@@ -33,8 +33,8 @@
       content::BrowserContext* browser_context,
       content::ProtocolHandlerMap* protocol_handlers,
       content::URLRequestInterceptorScopedVector request_interceptors) override;
-  void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
-                                      int child_process_id) override;
+  void AppendMappedFileCommandLineSwitches(
+      base::CommandLine* command_line) override;
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
   void GetAdditionalMappedFilesForChildProcess(
       const base::CommandLine& command_line,
@@ -46,6 +46,9 @@
 
  private:
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
+  bool natives_fd_exists() { return v8_natives_fd_.is_valid(); }
+  bool snapshot_fd_exists() { return v8_snapshot_fd_.is_valid(); }
+
   base::ScopedFD v8_natives_fd_;
   base::ScopedFD v8_snapshot_fd_;
 #endif
diff --git a/ash/shell/window_watcher.cc b/ash/shell/window_watcher.cc
index 990cef1e..f5b194c 100644
--- a/ash/shell/window_watcher.cc
+++ b/ash/shell/window_watcher.cc
@@ -13,6 +13,7 @@
 #include "ash/shell.h"
 #include "ash/shell/window_watcher_shelf_item_delegate.h"
 #include "ash/shell_window_ids.h"
+#include "ash/wm/window_util.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/gfx/display.h"
@@ -90,8 +91,7 @@
 
 // aura::WindowObserver overrides:
 void WindowWatcher::OnWindowAdded(aura::Window* new_window) {
-  if (new_window->type() != ui::wm::WINDOW_TYPE_NORMAL &&
-      new_window->type() != ui::wm::WINDOW_TYPE_PANEL)
+  if (!wm::IsWindowUserPositionable(new_window))
     return;
 
   static int image_count = 0;
diff --git a/ash/system/overview/overview_button_tray.cc b/ash/system/overview/overview_button_tray.cc
index edd5d67d..f5295b5 100644
--- a/ash/system/overview/overview_button_tray.cc
+++ b/ash/system/overview/overview_button_tray.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/overview/overview_button_tray.h"
 
+#include "ash/session/session_state_delegate.h"
 #include "ash/shelf/shelf_types.h"
 #include "ash/shell.h"
 #include "ash/system/tray/system_tray_delegate.h"
@@ -42,10 +43,13 @@
   tray_container()->AddChildView(icon_);
 
   Shell::GetInstance()->AddShellObserver(this);
+  Shell::GetInstance()->session_state_delegate()->AddSessionStateObserver(this);
 }
 
 OverviewButtonTray::~OverviewButtonTray() {
   Shell::GetInstance()->RemoveShellObserver(this);
+  Shell::GetInstance()->session_state_delegate()->RemoveSessionStateObserver(
+      this);
 }
 
 void OverviewButtonTray::UpdateAfterLoginStatusChange(
@@ -62,6 +66,11 @@
   return true;
 }
 
+void OverviewButtonTray::SessionStateChanged(
+    SessionStateDelegate::SessionState state) {
+  UpdateIconVisibility();
+}
+
 void OverviewButtonTray::OnMaximizeModeStarted() {
   UpdateIconVisibility();
 }
@@ -115,9 +124,22 @@
 }
 
 void OverviewButtonTray::UpdateIconVisibility() {
-  SetVisible(Shell::GetInstance()->maximize_mode_controller()->
-                 IsMaximizeModeWindowManagerEnabled() &&
-             Shell::GetInstance()->window_selector_controller()->CanSelect());
+  // The visibility of the OverviewButtonTray has diverge from
+  // WindowSelectorController::CanSelect. The visibility of the button should
+  // not change during transient times in which CanSelect is false. Such as when
+  // a modal dialog is present.
+  Shell* shell = Shell::GetInstance();
+  SessionStateDelegate* session_state_delegate =
+      shell->session_state_delegate();
+
+  SetVisible(
+      shell->maximize_mode_controller()->IsMaximizeModeWindowManagerEnabled() &&
+      session_state_delegate->IsActiveUserSessionStarted() &&
+      !session_state_delegate->IsScreenLocked() &&
+      session_state_delegate->GetSessionState() ==
+          SessionStateDelegate::SESSION_STATE_ACTIVE &&
+      shell->system_tray_delegate()->GetUserLoginStatus() !=
+          user::LOGGED_IN_KIOSK_APP);
 }
 
 }  // namespace ash
diff --git a/ash/system/overview/overview_button_tray.h b/ash/system/overview/overview_button_tray.h
index a58bae11..d3988be 100644
--- a/ash/system/overview/overview_button_tray.h
+++ b/ash/system/overview/overview_button_tray.h
@@ -6,9 +6,9 @@
 #define ASH_SYSTEM_OVERVIEW_OVERVIEW_BUTTON_TRAY_H_
 
 #include "ash/ash_export.h"
+#include "ash/session/session_state_observer.h"
 #include "ash/shell_observer.h"
 #include "ash/system/tray/tray_background_view.h"
-#include "ash/wm/overview/window_selector_controller.h"
 
 namespace views {
 class ImageView;
@@ -22,6 +22,7 @@
 // This tray will only be visible while in this state. This tray does not
 // provide any bubble view windows.
 class ASH_EXPORT OverviewButtonTray : public TrayBackgroundView,
+                                      public SessionStateObserver,
                                       public ShellObserver {
  public:
   explicit OverviewButtonTray(StatusAreaWidget* status_area_widget);
@@ -34,6 +35,9 @@
   // ActionableView:
   bool PerformAction(const ui::Event& event) override;
 
+  // SessionStateObserver:
+  void SessionStateChanged(SessionStateDelegate::SessionState state) override;
+
   // ShellObserver:
   void OnMaximizeModeStarted() override;
   void OnMaximizeModeEnded() override;
diff --git a/ash/system/overview/overview_button_tray_unittest.cc b/ash/system/overview/overview_button_tray_unittest.cc
index a7e6a3e..4468aae6 100644
--- a/ash/system/overview/overview_button_tray_unittest.cc
+++ b/ash/system/overview/overview_button_tray_unittest.cc
@@ -14,12 +14,16 @@
 #include "ash/system/status_area_widget.h"
 #include "ash/system/user/login_status.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test/ash_test_helper.h"
 #include "ash/test/status_area_widget_test_helper.h"
+#include "ash/test/test_session_state_delegate.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/overview/window_selector_controller.h"
 #include "base/command_line.h"
 #include "base/test/user_action_tester.h"
 #include "base/time/time.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/events/event.h"
 #include "ui/events/event_constants.h"
@@ -51,6 +55,8 @@
 
   void SetUp() override;
 
+  void NotifySessionStateChanged();
+
  protected:
   views::ImageView* GetImageView(OverviewButtonTray* tray) {
     return tray->icon_;
@@ -68,6 +74,11 @@
   AshTestBase::SetUp();
 }
 
+void OverviewButtonTrayTest::NotifySessionStateChanged() {
+  GetTray()->SessionStateChanged(
+      ash_test_helper()->GetTestSessionStateDelegate()->GetSessionState());
+}
+
 // Ensures that creation doesn't cause any crashes and adds the image icon.
 TEST_F(OverviewButtonTrayTest, BasicConstruction) {
   EXPECT_TRUE(GetImageView(GetTray()) != NULL);
@@ -178,6 +189,12 @@
   SetSessionStarted(true);
   Shell::GetInstance()->UpdateAfterLoginStatusChange(user::LOGGED_IN_USER);
   EXPECT_TRUE(GetTray()->visible());
+  SetUserAddingScreenRunning(true);
+  NotifySessionStateChanged();
+  EXPECT_FALSE(GetTray()->visible());
+  SetUserAddingScreenRunning(false);
+  NotifySessionStateChanged();
+  EXPECT_TRUE(GetTray()->visible());
   Shell::GetInstance()->maximize_mode_controller()->
       EnableMaximizeModeWindowManager(false);
 }
@@ -230,4 +247,28 @@
   EXPECT_FALSE(GetTray()->visible());
 }
 
+// Tests that the overview button becomes visible when the user enters
+// maximize mode with a system modal window open, and that it hides once
+// the user exits maximize mode.
+TEST_F(OverviewButtonTrayTest, VisibilityChangesForSystemModalWindow) {
+  // TODO(jonross): When CreateTestWindow*() have been unified, use the
+  // appropriate method to replace this setup. (crbug.com/483503)
+  scoped_ptr<aura::Window> window(new aura::Window(nullptr));
+  window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM);
+  window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
+  window->Init(ui::LAYER_TEXTURED);
+  window->Show();
+  ParentWindowInPrimaryRootWindow(window.get());
+
+  ASSERT_TRUE(Shell::GetInstance()->IsSystemModalWindowOpen());
+  Shell::GetInstance()
+      ->maximize_mode_controller()
+      ->EnableMaximizeModeWindowManager(true);
+  EXPECT_TRUE(GetTray()->visible());
+  Shell::GetInstance()
+      ->maximize_mode_controller()
+      ->EnableMaximizeModeWindowManager(false);
+  EXPECT_FALSE(GetTray()->visible());
+}
+
 }  // namespace ash
diff --git a/ash/test/test_activation_delegate.cc b/ash/test/test_activation_delegate.cc
index f583a05c..6f8caef 100644
--- a/ash/test/test_activation_delegate.cc
+++ b/ash/test/test_activation_delegate.cc
@@ -44,8 +44,10 @@
   return activate_;
 }
 
-void TestActivationDelegate::OnWindowActivated(aura::Window* gained_active,
-                                               aura::Window* lost_active) {
+void TestActivationDelegate::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
   DCHECK(window_ == gained_active || window_ == lost_active);
   if (window_ == gained_active) {
     activated_count_++;
diff --git a/ash/test/test_activation_delegate.h b/ash/test/test_activation_delegate.h
index 702e4f9..9c3ddbb 100644
--- a/ash/test/test_activation_delegate.h
+++ b/ash/test/test_activation_delegate.h
@@ -44,8 +44,10 @@
 
  private:
   // Overridden from aura::client::ActivationChangeObserver:
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
 
   aura::Window* window_;
   bool window_was_active_;
diff --git a/ash/utility/partial_screenshot_controller.cc b/ash/utility/partial_screenshot_controller.cc
index 210017f..18f8e4e 100644
--- a/ash/utility/partial_screenshot_controller.cc
+++ b/ash/utility/partial_screenshot_controller.cc
@@ -6,6 +6,7 @@
 
 #include <cmath>
 
+#include "ash/display/mouse_cursor_event_filter.h"
 #include "ash/screenshot_delegate.h"
 #include "ash/shell.h"
 #include "ash/shell_window_ids.h"
@@ -24,6 +25,13 @@
 // rectangles are drawn outside of the selected region.
 const int kInvalidateRegionAdditionalSize = 3;
 
+// This will prevent the user from taking a screenshot across multiple
+// monitors. it will stop the mouse at the any edge of the screen. must
+// swtich back on when the screenshot is complete.
+void EnableMouseWarp(bool enable) {
+  Shell::GetInstance()->mouse_cursor_filter()->set_mouse_warp_enabled(enable);
+}
+
 }  // namespace
 
 class PartialScreenshotController::PartialScreenshotLayer
@@ -143,6 +151,8 @@
 
   cursor_setter_.reset(new ScopedCursorSetter(
       Shell::GetInstance()->cursor_manager(), ui::kCursorCross));
+
+  EnableMouseWarp(false);
 }
 
 void PartialScreenshotController::MaybeStart(const ui::LocatedEvent& event) {
@@ -177,6 +187,7 @@
   Shell::GetScreen()->RemoveObserver(this);
   STLDeleteValues(&layers_);
   cursor_setter_.reset();
+  EnableMouseWarp(true);
 }
 
 void PartialScreenshotController::Update(const ui::LocatedEvent& event) {
diff --git a/ash/utility/partial_screenshot_controller_unittest.cc b/ash/utility/partial_screenshot_controller_unittest.cc
index 2caa9e80f..423eaf9 100644
--- a/ash/utility/partial_screenshot_controller_unittest.cc
+++ b/ash/utility/partial_screenshot_controller_unittest.cc
@@ -6,11 +6,14 @@
 
 #include "ash/display/cursor_window_controller.h"
 #include "ash/display/display_controller.h"
+#include "ash/display/mouse_cursor_event_filter.h"
 #include "ash/screenshot_delegate.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test/display_manager_test_api.h"
 #include "ash/test/mirror_window_test_api.h"
 #include "ash/test/test_screenshot_delegate.h"
+#include "ui/aura/env.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/base/cursor/cursor.h"
 #include "ui/events/test/event_generator.h"
@@ -28,6 +31,11 @@
     return Shell::GetInstance()->partial_screenshot_controller();
   }
 
+  bool TestIfMouseWarpsAt(const gfx::Point& point_in_screen) {
+    return test::DisplayManagerTestApi::TestIfMouseWarpsAt(GetEventGenerator(),
+                                                           point_in_screen);
+  }
+
   void StartPartialScreenshotSession() {
     partial_screenshot_controller()->StartPartialScreenshotSession(
         GetScreenshotDelegate());
@@ -142,7 +150,30 @@
   EXPECT_FALSE(IsActive());
 }
 
+// Make sure PartialScreenshotController doesn't allow taking screenshot
+// across multiple monitors
+// cursor. See http://crbug.com/462229
 #if defined(OS_CHROMEOS)
+TEST_F(PartialScreenshotControllerTest, MouseWarpTest) {
+  if (!SupportsMultipleDisplays())
+    return;
+
+  // Create two displays.
+  Shell* shell = Shell::GetInstance();
+  UpdateDisplay("500x500,500x500");
+  EXPECT_EQ(2U, shell->display_manager()->GetNumDisplays());
+
+  StartPartialScreenshotSession();
+  EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(499, 11)));
+  EXPECT_EQ("499,11",
+            aura::Env::GetInstance()->last_mouse_location().ToString());
+
+  Cancel();
+  EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(499, 11)));
+  EXPECT_EQ("501,11",
+            aura::Env::GetInstance()->last_mouse_location().ToString());
+}
+
 TEST_F(PartialScreenshotControllerTest, VisibilityTest) {
   aura::client::CursorClient* client = Shell::GetInstance()->cursor_manager();
 
diff --git a/ash/virtual_keyboard_controller.cc b/ash/virtual_keyboard_controller.cc
index 2f46e5c..d6fa180e 100644
--- a/ash/virtual_keyboard_controller.cc
+++ b/ash/virtual_keyboard_controller.cc
@@ -28,8 +28,7 @@
           keyboard::switches::kEnableVirtualKeyboard)) {
     return false;
   }
-  return !base::CommandLine::ForCurrentProcess()->HasSwitch(
-      keyboard::switches::kDisableSmartVirtualKeyboard);
+  return keyboard::IsSmartDeployEnabled();
 }
 
 }  // namespace
diff --git a/ash/virtual_keyboard_controller_unittest.cc b/ash/virtual_keyboard_controller_unittest.cc
index f7a59ef7..c31c6d04 100644
--- a/ash/virtual_keyboard_controller_unittest.cc
+++ b/ash/virtual_keyboard_controller_unittest.cc
@@ -51,8 +51,8 @@
   }
 
   void SetUp() override {
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        keyboard::switches::kDisableSmartVirtualKeyboard);
+    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+        keyboard::switches::kSmartVirtualKeyboard, "disabled");
     AshTestBase::SetUp();
     UpdateKeyboardDevices(std::vector<ui::KeyboardDevice>());
     UpdateTouchscreenDevices(std::vector<ui::TouchscreenDevice>());
diff --git a/ash/wm/default_state.cc b/ash/wm/default_state.cc
index 3364d29..953789ede 100644
--- a/ash/wm/default_state.cc
+++ b/ash/wm/default_state.cc
@@ -31,6 +31,11 @@
 // must be visible when the window is added to the workspace.
 const float kMinimumPercentOnScreenArea = 0.3f;
 
+// When a window that has restore bounds at least as large as a work area is
+// unmaximized, inset the bounds slightly so that they are not exactly the same.
+// This makes it easier to resize the window.
+const int kMaximizedWindowInset = 10;  // DIPs.
+
 bool IsMinimizedWindowState(const WindowStateType state_type) {
   return state_type == WINDOW_STATE_TYPE_MINIMIZED ||
          state_type == WINDOW_STATE_TYPE_DOCKED_MINIMIZED;
@@ -422,10 +427,8 @@
       // adjusted to have minimum visibility, because they are positioned by the
       // user and user should always be able to interact with them. Other
       // windows are positioned programmatically.
-      if (window_state->window()->type() != ui::wm::WINDOW_TYPE_NORMAL &&
-          window_state->window()->type() != ui::wm::WINDOW_TYPE_PANEL) {
+      if (!window_state->IsUserPositionable())
         return true;
-      }
 
       // Use entire display instead of workarea because the workarea can
       // be further shrunk by the docked area. The logic ensures 30%
@@ -645,10 +648,9 @@
         if (previous_state_type == WINDOW_STATE_TYPE_MAXIMIZED &&
             bounds_in_parent.width() >= work_area_in_parent.width() &&
             bounds_in_parent.height() >= work_area_in_parent.height()) {
-          // Inset the bounds slightly so that they are not exactly same as
-          // the work area bounds and it is easier to resize the window.
           bounds_in_parent = work_area_in_parent;
-          bounds_in_parent.Inset(10, 10, 10, 10);
+          bounds_in_parent.Inset(kMaximizedWindowInset, kMaximizedWindowInset,
+                                 kMaximizedWindowInset, kMaximizedWindowInset);
         }
       } else {
         bounds_in_parent = window->bounds();
diff --git a/ash/wm/dock/docked_window_layout_manager.cc b/ash/wm/dock/docked_window_layout_manager.cc
index 91fe6c8..9320a6f 100644
--- a/ash/wm/dock/docked_window_layout_manager.cc
+++ b/ash/wm/dock/docked_window_layout_manager.cc
@@ -210,8 +210,9 @@
           ::wm::GetTransientParent(window));
 }
 
-// Certain windows (minimized, hidden or popups) do not matter to docking.
-bool IsUsedByLayout(const aura::Window* window) {
+// Certain windows (minimized, hidden or popups) are not docked and are ignored
+// by layout logic even when they are children of a docked container.
+bool IsWindowDocked(const aura::Window* window) {
   return (window->IsVisible() &&
           !wm::GetWindowState(window)->IsMinimized() &&
           !IsPopupOrTransient(window));
@@ -479,8 +480,7 @@
           WindowResizer::kBoundsChangeDirection_Horizontal)) {
     for (size_t i = 0; i < dock_container_->children().size(); ++i) {
       aura::Window* window1(dock_container_->children()[i]);
-      if (IsUsedByLayout(window1) &&
-          window1 != dragged_window_ &&
+      if (IsWindowDocked(window1) && window1 != dragged_window_ &&
           window1->bounds().width() == docked_width_) {
         wm::GetWindowState(window1)->set_bounds_changed_by_user(false);
       }
@@ -745,6 +745,8 @@
     actual_new_bounds.set_height(
         std::max(min_size.height(), actual_new_bounds.height()));
   }
+  if (IsWindowDocked(child) && child != dragged_window_)
+    return;
   SnapToPixelLayoutManager::SetChildBounds(child, actual_new_bounds);
   if (IsPopupOrTransient(child))
     return;
@@ -902,8 +904,10 @@
 // DockedWindowLayoutManager, aura::client::ActivationChangeObserver
 // implementation:
 
-void DockedWindowLayoutManager::OnWindowActivated(aura::Window* gained_active,
-                                                  aura::Window* lost_active) {
+void DockedWindowLayoutManager::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
   if (gained_active && IsPopupOrTransient(gained_active))
     return;
   // Ignore if the window that is not managed by this was activated.
@@ -936,7 +940,7 @@
   aura::Window::Windows::const_reverse_iterator iter = children.rbegin();
   while (iter != children.rend()) {
     aura::Window* window(*iter++);
-    if (window == child || !IsUsedByLayout(window))
+    if (window == child || !IsWindowDocked(window))
       continue;
     int room_needed = GetWindowHeightCloseTo(window, 0) +
         (gap_needed ? kMinDockGap : 0);
@@ -1013,7 +1017,7 @@
     if (IsPopupOrTransient(window))
       continue;
     docked_all_count++;
-    if (!IsUsedByLayout(window))
+    if (!IsWindowDocked(window))
       continue;
     docked_visible_count++;
     if (window->type() == ui::wm::WINDOW_TYPE_PANEL)
@@ -1074,7 +1078,7 @@
   for (size_t i = 0; i < dock_container_->children().size(); ++i) {
     aura::Window* window(dock_container_->children()[i]);
 
-    if (!IsUsedByLayout(window) || window == dragged_window_)
+    if (!IsWindowDocked(window) || window == dragged_window_)
       continue;
 
     // If the shelf is currently hidden (full-screen mode), hide window until
@@ -1314,7 +1318,7 @@
   for (aura::Window::Windows::const_iterator it =
            dock_container_->children().begin();
        it != dock_container_->children().end(); ++it) {
-    if (!IsUsedByLayout(*it) ||
+    if (!IsWindowDocked(*it) ||
         ((*it) == dragged_window_ && !is_dragged_window_docked_)) {
       continue;
     }
diff --git a/ash/wm/dock/docked_window_layout_manager.h b/ash/wm/dock/docked_window_layout_manager.h
index c2a2afa..4fcad6b7 100644
--- a/ash/wm/dock/docked_window_layout_manager.h
+++ b/ash/wm/dock/docked_window_layout_manager.h
@@ -179,8 +179,10 @@
   void OnWindowDestroying(aura::Window* window) override;
 
   // aura::client::ActivationChangeObserver:
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
 
  private:
   class ShelfWindowObserver;
diff --git a/ash/wm/dock/docked_window_layout_manager_unittest.cc b/ash/wm/dock/docked_window_layout_manager_unittest.cc
index 0346758..80d6b91 100644
--- a/ash/wm/dock/docked_window_layout_manager_unittest.cc
+++ b/ash/wm/dock/docked_window_layout_manager_unittest.cc
@@ -237,6 +237,23 @@
   EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id());
 }
 
+// Tests that a docked window's bounds cannot be changed programmatically.
+TEST_P(DockedWindowLayoutManagerTest, DockedWindowBoundsDontChange) {
+  if (!SupportsHostWindowResize())
+    return;
+
+  gfx::Rect bounds(0, 0, 201, 201);
+  scoped_ptr<aura::Window> window(CreateTestWindow(bounds));
+  DragRelativeToEdge(DOCKED_EDGE_RIGHT, window.get(), 0);
+
+  // The window should be attached and docked at the right edge.
+  EXPECT_EQ(kShellWindowId_DockedContainer, window->parent()->id());
+
+  bounds = window->GetBoundsInScreen();
+  window->SetBounds(gfx::Rect(210, 210, 210, 210));
+  EXPECT_EQ(bounds.ToString(), window->GetBoundsInScreen().ToString());
+}
+
 // Tests that with a window docked on the left the auto-placing logic in
 // RearrangeVisibleWindowOnShow places windows flush with work area edges.
 TEST_P(DockedWindowLayoutManagerTest, AutoPlacingLeft) {
diff --git a/ash/wm/dock/docked_window_resizer.cc b/ash/wm/dock/docked_window_resizer.cc
index 91486c62..4f92f23 100644
--- a/ash/wm/dock/docked_window_resizer.cc
+++ b/ash/wm/dock/docked_window_resizer.cc
@@ -236,12 +236,11 @@
       window->SetBounds(bounds);
     }
   }
-  // If a window has restore bounds, update the restore origin and width but not
-  // the height (since the height is auto-calculated for the docked windows).
+  // If a window has restore bounds, update the restore origin but not the size.
+  // The size gets restored when a window is undocked.
   if (is_resized && is_docked_ && window_state_->HasRestoreBounds()) {
     gfx::Rect restore_bounds = window->GetBoundsInScreen();
-    restore_bounds.set_height(
-        window_state_->GetRestoreBoundsInScreen().height());
+    restore_bounds.set_size(window_state_->GetRestoreBoundsInScreen().size());
     window_state_->SetRestoreBoundsInScreen(restore_bounds);
   }
 
diff --git a/ash/wm/dock/docked_window_resizer_unittest.cc b/ash/wm/dock/docked_window_resizer_unittest.cc
index 63161766..6ace192b 100644
--- a/ash/wm/dock/docked_window_resizer_unittest.cc
+++ b/ash/wm/dock/docked_window_resizer_unittest.cc
@@ -1190,14 +1190,17 @@
             ScreenUtil::GetDisplayWorkAreaBoundsInParent(w1.get()).width());
 }
 
-// Dock a window, resize it and test that undocking it preserves the width.
-TEST_P(DockedWindowResizerTest, ResizingKeepsWidth) {
+// Dock a window, resize it and test that undocking it restores the pre-docked
+// size.
+TEST_P(DockedWindowResizerTest, ResizingKeepsSize) {
   if (!SupportsHostWindowResize())
     return;
 
   // Wider display to start since panels are limited to half the display width.
   UpdateDisplay("1000x600");
-  scoped_ptr<aura::Window> w1(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
+  const gfx::Size original_size(201, 201);
+  scoped_ptr<aura::Window> w1(
+      CreateTestWindow(gfx::Rect(gfx::Point(), original_size)));
 
   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20);
   // Window should be docked at the right edge.
@@ -1230,10 +1233,8 @@
 
   // Undock by dragging almost to the left edge.
   DragToVerticalPositionRelativeToEdge(DOCKED_EDGE_LEFT, w1.get(), 100, 20);
-  // Width should be preserved.
-  EXPECT_EQ(previous_width + kResizeSpan1, w1->bounds().width());
-  // Height should be restored to what it was originally.
-  EXPECT_EQ(201, w1->bounds().height());
+  // Size should be restored to what it was originally.
+  EXPECT_EQ(original_size.ToString(), w1->bounds().size().ToString());
 
   // Dock again.
   DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, w1.get(), 20);
@@ -1242,10 +1243,8 @@
 
   // Undock again by dragging left.
   DragToVerticalPositionRelativeToEdge(DOCKED_EDGE_LEFT, w1.get(), 100, 20);
-  // Width should be reset to what it was last time the window was not docked.
-  EXPECT_EQ(previous_width + kResizeSpan1, w1->bounds().width());
-  // Height should be restored to what it was originally.
-  EXPECT_EQ(201, w1->bounds().height());
+  // Size should be restored to what it was originally.
+  EXPECT_EQ(original_size.ToString(), w1->bounds().size().ToString());
 }
 
 // Dock a window, resize it and test that it stays docked.
diff --git a/ash/wm/drag_window_resizer.cc b/ash/wm/drag_window_resizer.cc
index 948137e..f6a714c2 100644
--- a/ash/wm/drag_window_resizer.cc
+++ b/ash/wm/drag_window_resizer.cc
@@ -216,10 +216,9 @@
 }
 
 bool DragWindowResizer::ShouldAllowMouseWarp() {
-  return (details().window_component == HTCAPTION) &&
-      !::wm::GetTransientParent(GetTarget()) &&
-      (GetTarget()->type() == ui::wm::WINDOW_TYPE_NORMAL ||
-       GetTarget()->type() == ui::wm::WINDOW_TYPE_PANEL);
+  return details().window_component == HTCAPTION &&
+         !::wm::GetTransientParent(GetTarget()) &&
+         wm::IsWindowUserPositionable(GetTarget());
 }
 
 }  // namespace ash
diff --git a/ash/wm/mru_window_tracker.cc b/ash/wm/mru_window_tracker.cc
index 2c38e0d6..00e1773 100644
--- a/ash/wm/mru_window_tracker.cc
+++ b/ash/wm/mru_window_tracker.cc
@@ -174,8 +174,10 @@
   mru_windows_.push_front(active_window);
 }
 
-void MruWindowTracker::OnWindowActivated(aura::Window* gained_active,
-                                         aura::Window* lost_active) {
+void MruWindowTracker::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
   if (!ignore_window_activations_)
     SetActiveWindow(gained_active);
 }
diff --git a/ash/wm/mru_window_tracker.h b/ash/wm/mru_window_tracker.h
index f32f708..06673a8 100644
--- a/ash/wm/mru_window_tracker.h
+++ b/ash/wm/mru_window_tracker.h
@@ -65,8 +65,10 @@
   void SetActiveWindow(aura::Window* active_window);
 
   // Overridden from aura::client::ActivationChangeObserver:
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
 
   // Overridden from WindowObserver:
   void OnWindowDestroyed(aura::Window* window) override;
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
index 91458cf..5e01d37 100644
--- a/ash/wm/overview/window_selector.cc
+++ b/ash/wm/overview/window_selector.cc
@@ -22,6 +22,7 @@
 #include "ash/wm/overview/window_selector_item.h"
 #include "ash/wm/panels/panel_layout_manager.h"
 #include "ash/wm/window_state.h"
+#include "ash/wm/window_util.h"
 #include "base/auto_reset.h"
 #include "base/command_line.h"
 #include "base/metrics/histogram.h"
@@ -224,8 +225,7 @@
       state->GetStateType() == wm::WINDOW_STATE_TYPE_DOCKED_MINIMIZED) {
     return false;
   }
-  return window->type() == ui::wm::WINDOW_TYPE_NORMAL ||
-         window->type() == ui::wm::WINDOW_TYPE_PANEL;
+  return state->IsUserPositionable();
 }
 
 WindowSelector::WindowSelector(WindowSelectorDelegate* delegate)
@@ -505,8 +505,10 @@
     restore_focus_window_ = nullptr;
 }
 
-void WindowSelector::OnWindowActivated(aura::Window* gained_active,
-                                       aura::Window* lost_active) {
+void WindowSelector::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
   if (ignore_activations_ ||
       !gained_active ||
       gained_active == text_filter_widget_->GetNativeWindow()) {
@@ -534,7 +536,9 @@
 
 void WindowSelector::OnAttemptToReactivateWindow(aura::Window* request_active,
                                                  aura::Window* actual_active) {
-  OnWindowActivated(request_active, actual_active);
+  OnWindowActivated(aura::client::ActivationChangeObserver::ActivationReason::
+                        ACTIVATION_CLIENT,
+                    request_active, actual_active);
 }
 
 void WindowSelector::ContentsChanged(views::Textfield* sender,
diff --git a/ash/wm/overview/window_selector.h b/ash/wm/overview/window_selector.h
index 7c783b8..06cfb1b 100644
--- a/ash/wm/overview/window_selector.h
+++ b/ash/wm/overview/window_selector.h
@@ -102,8 +102,10 @@
   void OnWindowDestroying(aura::Window* window) override;
 
   // aura::client::ActivationChangeObserver:
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
   void OnAttemptToReactivateWindow(aura::Window* request_active,
                                    aura::Window* actual_active) override;
 
diff --git a/ash/wm/panels/panel_layout_manager.cc b/ash/wm/panels/panel_layout_manager.cc
index 35219d5..11f2c1d9 100644
--- a/ash/wm/panels/panel_layout_manager.cc
+++ b/ash/wm/panels/panel_layout_manager.cc
@@ -513,8 +513,10 @@
 ////////////////////////////////////////////////////////////////////////////////
 // PanelLayoutManager, aura::client::ActivationChangeObserver implementation:
 
-void PanelLayoutManager::OnWindowActivated(aura::Window* gained_active,
-                                           aura::Window* lost_active) {
+void PanelLayoutManager::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
   // Ignore if the panel that is not managed by this was activated.
   if (gained_active && gained_active->type() == ui::wm::WINDOW_TYPE_PANEL &&
       gained_active->parent() == panel_container_) {
diff --git a/ash/wm/panels/panel_layout_manager.h b/ash/wm/panels/panel_layout_manager.h
index 1a2dadb..427e5f1 100644
--- a/ash/wm/panels/panel_layout_manager.h
+++ b/ash/wm/panels/panel_layout_manager.h
@@ -108,8 +108,10 @@
                                    wm::WindowStateType old_type) override;
 
   // Overridden from aura::client::ActivationChangeObserver
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
 
   // Overridden from DisplayController::Observer
   void OnDisplayConfigurationChanged() override;
diff --git a/ash/wm/session_state_animator_impl.cc b/ash/wm/session_state_animator_impl.cc
index babe3cc..ebaf312 100644
--- a/ash/wm/session_state_animator_impl.cc
+++ b/ash/wm/session_state_animator_impl.cc
@@ -389,6 +389,49 @@
   return true;
 }
 
+void GetContainersInRootWindow(int container_mask,
+                               aura::Window* root_window,
+                               aura::Window::Windows* containers) {
+  if (container_mask & SessionStateAnimator::ROOT_CONTAINER) {
+    containers->push_back(root_window);
+  }
+
+  if (container_mask & SessionStateAnimator::DESKTOP_BACKGROUND) {
+    containers->push_back(Shell::GetContainer(
+        root_window, kShellWindowId_DesktopBackgroundContainer));
+  }
+  if (container_mask & SessionStateAnimator::LAUNCHER) {
+    containers->push_back(Shell::GetContainer(
+        root_window, kShellWindowId_DesktopBackgroundContainer));
+  }
+  if (container_mask & SessionStateAnimator::NON_LOCK_SCREEN_CONTAINERS) {
+    // TODO(antrim): Figure out a way to eliminate a need to exclude launcher
+    // in such way.
+    aura::Window* non_lock_screen_containers = Shell::GetContainer(
+        root_window, kShellWindowId_NonLockScreenContainersContainer);
+    // |non_lock_screen_containers| may already be removed in some tests.
+    if (non_lock_screen_containers) {
+      for (aura::Window* window : non_lock_screen_containers->children()) {
+        if (window->id() == kShellWindowId_ShelfContainer)
+          continue;
+        containers->push_back(window);
+      }
+    }
+  }
+  if (container_mask & SessionStateAnimator::LOCK_SCREEN_BACKGROUND) {
+    containers->push_back(Shell::GetContainer(
+        root_window, kShellWindowId_LockScreenBackgroundContainer));
+  }
+  if (container_mask & SessionStateAnimator::LOCK_SCREEN_CONTAINERS) {
+    containers->push_back(Shell::GetContainer(
+        root_window, kShellWindowId_LockScreenContainersContainer));
+  }
+  if (container_mask & SessionStateAnimator::LOCK_SCREEN_RELATED_CONTAINERS) {
+    containers->push_back(Shell::GetContainer(
+        root_window, kShellWindowId_LockScreenRelatedContainersContainer));
+  }
+}
+
 }  // namespace
 
 // This observer is intended to use in cases when some action has to be taken
@@ -483,49 +526,13 @@
 }
 
 // Fills |containers| with the containers described by |container_mask|.
-void SessionStateAnimatorImpl::GetContainers(int container_mask,
+void SessionStateAnimatorImpl::GetContainers(
+    int container_mask,
     aura::Window::Windows* containers) {
-  aura::Window* root_window = Shell::GetPrimaryRootWindow();
   containers->clear();
 
-  if (container_mask & ROOT_CONTAINER) {
-    containers->push_back(Shell::GetPrimaryRootWindow());
-  }
-
-  if (container_mask & DESKTOP_BACKGROUND) {
-    containers->push_back(Shell::GetContainer(
-        root_window, kShellWindowId_DesktopBackgroundContainer));
-  }
-  if (container_mask & LAUNCHER) {
-    containers->push_back(
-        Shell::GetContainer(root_window, kShellWindowId_ShelfContainer));
-  }
-  if (container_mask & NON_LOCK_SCREEN_CONTAINERS) {
-    // TODO(antrim): Figure out a way to eliminate a need to exclude launcher
-    // in such way.
-    aura::Window* non_lock_screen_containers = Shell::GetContainer(
-        root_window, kShellWindowId_NonLockScreenContainersContainer);
-    // |non_lock_screen_containers| may already be removed in some tests.
-    if (non_lock_screen_containers) {
-      for (aura::Window* window : non_lock_screen_containers->children()) {
-        if (window->id() == kShellWindowId_ShelfContainer)
-          continue;
-        containers->push_back(window);
-      }
-    }
-  }
-  if (container_mask & LOCK_SCREEN_BACKGROUND) {
-    containers->push_back(Shell::GetContainer(
-        root_window, kShellWindowId_LockScreenBackgroundContainer));
-  }
-  if (container_mask & LOCK_SCREEN_CONTAINERS) {
-    containers->push_back(Shell::GetContainer(
-        root_window, kShellWindowId_LockScreenContainersContainer));
-  }
-  if (container_mask & LOCK_SCREEN_RELATED_CONTAINERS) {
-    containers->push_back(Shell::GetContainer(
-        root_window, kShellWindowId_LockScreenRelatedContainersContainer));
-  }
+  for (aura::Window* root_window : Shell::GetAllRootWindows())
+    GetContainersInRootWindow(container_mask, root_window, containers);
 
   // Some of containers may be null in some tests.
   containers->erase(
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index 94335cc..bf6bc22 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -143,6 +143,11 @@
          GetStateType() == WINDOW_STATE_TYPE_DOCKED_MINIMIZED;
 }
 
+bool WindowState::IsUserPositionable() const {
+  return (window()->type() == ui::wm::WINDOW_TYPE_NORMAL ||
+          window()->type() == ui::wm::WINDOW_TYPE_PANEL);
+}
+
 bool WindowState::CanMaximize() const {
   // Window must have the kCanMaximizeKey and have no maximum width or height.
   if (!window()->GetProperty(aura::client::kCanMaximizeKey))
diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h
index f74d9be..c42461c 100644
--- a/ash/wm/window_state.h
+++ b/ash/wm/window_state.h
@@ -108,6 +108,9 @@
   bool IsActive() const;
   bool IsDocked() const;
 
+  // Returns true if the window's location can be controlled by the user.
+  bool IsUserPositionable() const;
+
   // Checks if the window can change its state accordingly.
   bool CanMaximize() const;
   bool CanMinimize() const;
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc
index e05ae2fb..a0fb399 100644
--- a/ash/wm/window_util.cc
+++ b/ash/wm/window_util.cc
@@ -77,6 +77,10 @@
   return ash::wm::GetWindowState(window)->IsMinimized();
 }
 
+bool IsWindowUserPositionable(aura::Window* window) {
+  return GetWindowState(window)->IsUserPositionable();
+}
+
 void CenterWindow(aura::Window* window) {
   wm::WMEvent event(wm::WM_EVENT_CENTER);
   wm::GetWindowState(window)->OnWMEvent(&event);
diff --git a/ash/wm/window_util.h b/ash/wm/window_util.h
index 383c12f2..e1240ae 100644
--- a/ash/wm/window_util.h
+++ b/ash/wm/window_util.h
@@ -46,6 +46,9 @@
 // TODO(oshima): remove this.
 ASH_EXPORT bool IsWindowMinimized(aura::Window* window);
 
+// Returns true if |window|'s location can be controlled by the user.
+ASH_EXPORT bool IsWindowUserPositionable(aura::Window* window);
+
 // Moves the window to the center of the display.
 ASH_EXPORT void CenterWindow(aura::Window* window);
 
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index 63c4aed0e..6db10ec 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -245,8 +245,10 @@
 // WorkspaceLayoutManager,
 // aura::client::ActivationChangeObserver implementation:
 
-void WorkspaceLayoutManager::OnWindowActivated(aura::Window* gained_active,
-                                               aura::Window* lost_active) {
+void WorkspaceLayoutManager::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
   wm::WindowState* window_state = wm::GetWindowState(gained_active);
   if (window_state && window_state->IsMinimized() &&
       !gained_active->IsVisible()) {
diff --git a/ash/wm/workspace/workspace_layout_manager.h b/ash/wm/workspace/workspace_layout_manager.h
index 5570dd5..d5e57ec0 100644
--- a/ash/wm/workspace/workspace_layout_manager.h
+++ b/ash/wm/workspace/workspace_layout_manager.h
@@ -84,8 +84,10 @@
                              const gfx::Rect& new_bounds) override;
 
   // aura::client::ActivationChangeObserver overrides:
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
 
   // keyboard::KeyboardControllerObserver overrides:
   void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override;
diff --git a/base/BUILD.gn b/base/BUILD.gn
index d509c89a..ed510865 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1316,6 +1316,13 @@
     "//third_party/icu",
   ]
 
+  data = [
+    "test/data/",
+
+    # TODO(dpranke): Remove when icu declares this directly.
+    "$root_out_dir/icudtl.dat",
+  ]
+
   # Allow more direct string conversions on platforms with native utf8
   # strings
   if (is_mac || is_ios || is_chromeos) {
diff --git a/base/android/apk_assets.cc b/base/android/apk_assets.cc
index 431c75c3..bcdac6d 100644
--- a/base/android/apk_assets.cc
+++ b/base/android/apk_assets.cc
@@ -18,13 +18,15 @@
   return RegisterNativesImpl(env);
 }
 
-int OpenApkAsset(const std::string& filename,
+int OpenApkAsset(const std::string& file_path,
                  base::MemoryMappedFile::Region* region) {
+  // The AAssetManager API of the NDK is does not expose a method for accessing
+  // raw resources :(.
   JNIEnv* env = base::android::AttachCurrentThread();
-  ScopedJavaLocalRef<jlongArray> jarr = Java_ApkAssets_openAsset(
+  ScopedJavaLocalRef<jlongArray> jarr = Java_ApkAssets_open(
       env,
       base::android::GetApplicationContext(),
-      base::android::ConvertUTF8ToJavaString(env, filename).Release());
+      base::android::ConvertUTF8ToJavaString(env, file_path).Release());
   std::vector<jlong> results;
   base::android::JavaLongArrayToLongVector(env, jarr.obj(), &results);
   CHECK_EQ(3U, results.size());
@@ -35,10 +37,10 @@
 }
 
 bool RegisterApkAssetWithGlobalDescriptors(base::GlobalDescriptors::Key key,
-                                           const std::string& asset_filename) {
+                                           const std::string& file_path) {
   base::MemoryMappedFile::Region region =
       base::MemoryMappedFile::Region::kWholeFile;
-  int asset_fd = OpenApkAsset(asset_filename, &region);
+  int asset_fd = OpenApkAsset(file_path, &region);
   if (asset_fd != -1) {
     base::GlobalDescriptors::GetInstance()->Set(key, asset_fd, region);
   }
diff --git a/base/android/apk_assets.h b/base/android/apk_assets.h
index f5df35d..6eb5da3 100644
--- a/base/android/apk_assets.h
+++ b/base/android/apk_assets.h
@@ -20,17 +20,19 @@
 // Can be used from renderer process.
 // Fails if the asset is not stored uncompressed within the .apk.
 // Returns: The File Descriptor of the asset, or -1 upon failure.
+// Input arguments:
+// - |file_path|: Path to file within .apk. e.g.: assets/foo.pak
 // Output arguments:
 // - |region|: size & offset (in bytes) within the .apk of the asset.
 BASE_EXPORT int OpenApkAsset(
-    const std::string& filename,
+    const std::string& file_path,
     base::MemoryMappedFile::Region* region);
 
 // Registers an uncompressed asset from within the apk with GlobalDescriptors.
 // Returns: true in case of success, false otherwise.
 BASE_EXPORT bool RegisterApkAssetWithGlobalDescriptors(
     base::GlobalDescriptors::Key key,
-    const std::string& asset_filename);
+    const std::string& file_path);
 
 }  // namespace android
 }  // namespace base
diff --git a/base/android/application_status_listener.cc b/base/android/application_status_listener.cc
index 02178c4..3e6fbf833 100644
--- a/base/android/application_status_listener.cc
+++ b/base/android/application_status_listener.cc
@@ -10,29 +10,30 @@
 #include "base/observer_list_threadsafe.h"
 #include "jni/ApplicationStatus_jni.h"
 
+namespace base {
+namespace android {
+
 namespace {
+
 struct LeakyLazyObserverListTraits :
     base::internal::LeakyLazyInstanceTraits<
-        ObserverListThreadSafe<base::android::ApplicationStatusListener> > {
-  static ObserverListThreadSafe<base::android::ApplicationStatusListener>*
+        ObserverListThreadSafe<ApplicationStatusListener> > {
+  static ObserverListThreadSafe<ApplicationStatusListener>*
       New(void* instance) {
-    ObserverListThreadSafe<base::android::ApplicationStatusListener>* ret =
+    ObserverListThreadSafe<ApplicationStatusListener>* ret =
         base::internal::LeakyLazyInstanceTraits<ObserverListThreadSafe<
-            base::android::ApplicationStatusListener> >::New(instance);
+            ApplicationStatusListener>>::New(instance);
     // Leaky.
     ret->AddRef();
     return ret;
   }
 };
 
-base::LazyInstance<ObserverListThreadSafe<
-    base::android::ApplicationStatusListener>,
-        LeakyLazyObserverListTraits> g_observers = LAZY_INSTANCE_INITIALIZER;
+LazyInstance<ObserverListThreadSafe<ApplicationStatusListener>,
+             LeakyLazyObserverListTraits> g_observers =
+    LAZY_INSTANCE_INITIALIZER;
 
-} // namespace
-
-namespace base {
-namespace android {
+}  // namespace
 
 ApplicationStatusListener::ApplicationStatusListener(
     const ApplicationStatusListener::ApplicationStateChangeCallback& callback)
@@ -41,7 +42,7 @@
   g_observers.Get().AddObserver(this);
 
   Java_ApplicationStatus_registerThreadSafeNativeApplicationStateListener(
-      base::android::AttachCurrentThread());
+      AttachCurrentThread());
 }
 
 ApplicationStatusListener::~ApplicationStatusListener() {
diff --git a/base/android/java/src/org/chromium/base/ApkAssets.java b/base/android/java/src/org/chromium/base/ApkAssets.java
index 0b7bc32..329660f 100644
--- a/base/android/java/src/org/chromium/base/ApkAssets.java
+++ b/base/android/java/src/org/chromium/base/ApkAssets.java
@@ -21,11 +21,11 @@
     private static final String LOGTAG = "ApkAssets";
 
     @CalledByNative
-    public static long[] openAsset(Context context, String fileName) {
+    public static long[] open(Context context, String fileName) {
         AssetFileDescriptor afd = null;
         try {
             AssetManager manager = context.getAssets();
-            afd = manager.openFd(fileName);
+            afd = manager.openNonAssetFd(fileName);
             return new long[] { afd.getParcelFileDescriptor().detachFd(),
                                 afd.getStartOffset(),
                                 afd.getLength() };
diff --git a/base/ios/OWNERS b/base/ios/OWNERS
index 62564002..dc0be622 100644
--- a/base/ios/OWNERS
+++ b/base/ios/OWNERS
@@ -1,3 +1,4 @@
+droger@chromium.org
 qsr@chromium.org
 rohitrao@chromium.org
 stuartmorgan@chromium.org
diff --git a/base/ios/crb_protocol_observers.h b/base/ios/crb_protocol_observers.h
index 15d16569..8ff5878 100644
--- a/base/ios/crb_protocol_observers.h
+++ b/base/ios/crb_protocol_observers.h
@@ -13,6 +13,10 @@
 // protocol. The container forwards method invocations to its contained
 // observers, so that sending a message to all the observers is as simple as
 // sending the message to the container.
+// It is safe for an observer to remove itself or another observer while being
+// notified. It is also safe to add an other observer while being notified but
+// the newly added observer will not be notified as part of the current
+// notification dispatch.
 @interface CRBProtocolObservers : NSObject
 
 // The Objective-C protocol that the observers in this container conform to.
@@ -20,7 +24,7 @@
 
 // Returns a CRBProtocolObservers container for observers that conform to
 // |protocol|.
-+ (CRBProtocolObservers*)observersWithProtocol:(Protocol*)protocol;
++ (instancetype)observersWithProtocol:(Protocol*)protocol;
 
 // Adds |observer| to this container.
 - (void)addObserver:(id)observer;
@@ -28,6 +32,9 @@
 // Remove |observer| from this container.
 - (void)removeObserver:(id)observer;
 
+// Returns true if there are currently no observers.
+- (BOOL)empty;
+
 // Executes callback on every observer. |callback| cannot be nil.
 - (void)executeOnObservers:(ExecutionWithObserverBlock)callback;
 
diff --git a/base/ios/crb_protocol_observers.mm b/base/ios/crb_protocol_observers.mm
index ee9e23fc..90a277b 100644
--- a/base/ios/crb_protocol_observers.mm
+++ b/base/ios/crb_protocol_observers.mm
@@ -5,10 +5,69 @@
 #import "base/ios/crb_protocol_observers.h"
 
 #include <objc/runtime.h>
+#include <algorithm>
+#include <vector>
 
 #include "base/logging.h"
 #include "base/mac/scoped_nsobject.h"
 
+@interface CRBProtocolObservers () {
+  base::scoped_nsobject<Protocol> _protocol;
+  // ivars declared here are private to the implementation but must be
+  // public for allowing the C++ |Iterator| class access to those ivars.
+ @public
+  // vector of weak pointers to observers.
+  std::vector<__unsafe_unretained id> _observers;
+  // The nested level of observer iteration.
+  // A depth of 0 means nobody is currently iterating on the list of observers.
+  int _invocationDepth;
+}
+
+// Removes nil observers from the list and is called when the
+// |_invocationDepth| reaches 0.
+- (void)compact;
+
+@end
+
+namespace {
+
+class Iterator {
+ public:
+  explicit Iterator(CRBProtocolObservers* protocol_observers);
+  ~Iterator();
+  id GetNext();
+
+ private:
+  CRBProtocolObservers* protocol_observers_;
+  size_t index_;
+  size_t max_index_;
+};
+
+Iterator::Iterator(CRBProtocolObservers* protocol_observers)
+    : protocol_observers_(protocol_observers),
+      index_(0),
+      max_index_(protocol_observers->_observers.size()) {
+  DCHECK(protocol_observers_);
+  ++protocol_observers->_invocationDepth;
+}
+
+Iterator::~Iterator() {
+  if (protocol_observers_ && --protocol_observers_->_invocationDepth == 0)
+    [protocol_observers_ compact];
+}
+
+id Iterator::GetNext() {
+  if (!protocol_observers_)
+    return nil;
+  auto& observers = protocol_observers_->_observers;
+  // Skip nil elements.
+  size_t max_index = std::min(max_index_, observers.size());
+  while (index_ < max_index && !observers[index_])
+    ++index_;
+  return index_ < max_index ? observers[index_++] : nil;
+}
+}
+
 @interface CRBProtocolObservers ()
 
 // Designated initializer.
@@ -16,12 +75,9 @@
 
 @end
 
-@implementation CRBProtocolObservers {
-  base::scoped_nsobject<Protocol> _protocol;
-  base::scoped_nsobject<NSHashTable> _observers;
-}
+@implementation CRBProtocolObservers
 
-+ (CRBProtocolObservers*)observersWithProtocol:(Protocol*)protocol {
++ (instancetype)observersWithProtocol:(Protocol*)protocol {
   return [[[self alloc] initWithProtocol:protocol] autorelease];
 }
 
@@ -34,7 +90,6 @@
   self = [super init];
   if (self) {
     _protocol.reset([protocol retain]);
-    _observers.reset([[NSHashTable weakObjectsHashTable] retain]);
   }
   return self;
 }
@@ -44,12 +99,34 @@
 }
 
 - (void)addObserver:(id)observer {
+  DCHECK(observer);
   DCHECK([observer conformsToProtocol:self.protocol]);
-  [_observers addObject:observer];
+
+  if (std::find(_observers.begin(), _observers.end(), observer) !=
+      _observers.end())
+    return;
+
+  _observers.push_back(observer);
 }
 
 - (void)removeObserver:(id)observer {
-  [_observers removeObject:observer];
+  DCHECK(observer);
+  auto it = std::find(_observers.begin(), _observers.end(), observer);
+  if (it != _observers.end()) {
+    if (_invocationDepth)
+      *it = nil;
+    else
+      _observers.erase(it);
+  }
+}
+
+- (BOOL)empty {
+  int count = 0;
+  for (id observer : _observers) {
+    if (observer != nil)
+      ++count;
+  }
+  return count == 0;
 }
 
 #pragma mark - NSObject
@@ -80,9 +157,13 @@
 }
 
 - (void)forwardInvocation:(NSInvocation*)invocation {
+  DCHECK(invocation);
+  if (_observers.empty())
+    return;
   SEL selector = [invocation selector];
-  base::scoped_nsobject<NSArray> observers([[_observers allObjects] retain]);
-  for (id observer in observers.get()) {
+  Iterator it(self);
+  id observer;
+  while ((observer = it.GetNext()) != nil) {
     if ([observer respondsToSelector:selector])
       [invocation invokeWithTarget:observer];
   }
@@ -90,10 +171,20 @@
 
 - (void)executeOnObservers:(ExecutionWithObserverBlock)callback {
   DCHECK(callback);
-  base::scoped_nsobject<NSArray> observers([[_observers allObjects] retain]);
-  for (id observer in observers.get()) {
+  if (_observers.empty())
+    return;
+  Iterator it(self);
+  id observer;
+  while ((observer = it.GetNext()) != nil)
     callback(observer);
-  }
+}
+
+#pragma mark - Private
+
+- (void)compact {
+  DCHECK(!_invocationDepth);
+  _observers.erase(std::remove(_observers.begin(), _observers.end(), nil),
+                   _observers.end());
 }
 
 @end
diff --git a/base/ios/crb_protocol_observers_unittest.mm b/base/ios/crb_protocol_observers_unittest.mm
index d235c98..5f11051 100644
--- a/base/ios/crb_protocol_observers_unittest.mm
+++ b/base/ios/crb_protocol_observers_unittest.mm
@@ -18,6 +18,10 @@
 
 @optional
 - (void)optionalMethod;
+- (void)mutateByAddingObserver:(id<TestObserver>)observer;
+- (void)mutateByRemovingObserver:(id<TestObserver>)observer;
+- (void)nestedMutateByAddingObserver:(id<TestObserver>)observer;
+- (void)nestedMutateByRemovingObserver:(id<TestObserver>)observer;
 
 @end
 
@@ -31,6 +35,13 @@
 @property(nonatomic, readonly) BOOL optionalMethodInvoked;
 @end
 
+@interface TestMutateObserver : TestCompleteObserver
+
+- (instancetype)initWithObserver:(CRBProtocolObservers*)observer
+    NS_DESIGNATED_INITIALIZER;
+
+@end
+
 namespace {
 
 class CRBProtocolObserversTest : public PlatformTest {
@@ -50,11 +61,16 @@
     complete_observer_.reset([[TestCompleteObserver alloc] init]);
     EXPECT_FALSE([complete_observer_ requiredMethodInvoked]);
     EXPECT_FALSE([complete_observer_ optionalMethodInvoked]);
+
+    mutate_observer_.reset(
+        [[TestMutateObserver alloc] initWithObserver:observers_.get()]);
+    EXPECT_FALSE([mutate_observer_ requiredMethodInvoked]);
   }
 
   base::scoped_nsobject<id> observers_;
   base::scoped_nsobject<TestPartialObserver> partial_observer_;
   base::scoped_nsobject<TestCompleteObserver> complete_observer_;
+  base::scoped_nsobject<TestMutateObserver> mutate_observer_;
 };
 
 // Verifies basic functionality of -[CRBProtocolObservers addObserver:] and
@@ -119,6 +135,86 @@
   EXPECT_FALSE(weak_observer.get());
 }
 
+// Verifies that an observer can safely remove itself as observer while being
+// notified.
+TEST_F(CRBProtocolObserversTest, SelfMutateObservers) {
+  [observers_ addObserver:mutate_observer_];
+  EXPECT_FALSE([observers_ empty]);
+
+  [observers_ requiredMethod];
+  EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
+
+  [mutate_observer_ reset];
+
+  [observers_ nestedMutateByRemovingObserver:mutate_observer_];
+  EXPECT_FALSE([mutate_observer_ requiredMethodInvoked]);
+
+  [observers_ addObserver:partial_observer_];
+
+  [observers_ requiredMethod];
+  EXPECT_FALSE([mutate_observer_ requiredMethodInvoked]);
+  EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+
+  [observers_ removeObserver:partial_observer_];
+  EXPECT_TRUE([observers_ empty]);
+}
+
+// Verifies that - [CRBProtocolObservers addObserver:] and
+// - [CRBProtocolObservers removeObserver:] can be called while methods are
+// being forwarded.
+TEST_F(CRBProtocolObserversTest, MutateObservers) {
+  // Indirectly add an observer while forwarding an observer method.
+  [observers_ addObserver:mutate_observer_];
+
+  [observers_ mutateByAddingObserver:partial_observer_];
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+
+  // Check that methods are correctly forwared to the indirectly added observer.
+  [mutate_observer_ reset];
+  [observers_ requiredMethod];
+  EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
+  EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+
+  [mutate_observer_ reset];
+  [partial_observer_ reset];
+
+  // Indirectly remove an observer while forwarding an observer method.
+  [observers_ mutateByRemovingObserver:partial_observer_];
+
+  // Check that method is not forwared to the indirectly removed observer.
+  [observers_ requiredMethod];
+  EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+}
+
+// Verifies that - [CRBProtocolObservers addObserver:] and
+// - [CRBProtocolObservers removeObserver:] can be called while methods are
+// being forwarded with a nested invocation depth > 0.
+TEST_F(CRBProtocolObserversTest, NestedMutateObservers) {
+  // Indirectly add an observer while forwarding an observer method.
+  [observers_ addObserver:mutate_observer_];
+
+  [observers_ nestedMutateByAddingObserver:partial_observer_];
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+
+  // Check that methods are correctly forwared to the indirectly added observer.
+  [mutate_observer_ reset];
+  [observers_ requiredMethod];
+  EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
+  EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+
+  [mutate_observer_ reset];
+  [partial_observer_ reset];
+
+  // Indirectly remove an observer while forwarding an observer method.
+  [observers_ nestedMutateByRemovingObserver:partial_observer_];
+
+  // Check that method is not forwared to the indirectly removed observer.
+  [observers_ requiredMethod];
+  EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+}
+
 }  // namespace
 
 @implementation TestPartialObserver {
@@ -157,3 +253,33 @@
 }
 
 @end
+
+@implementation TestMutateObserver {
+  __weak id _observers;
+}
+
+- (instancetype)initWithObserver:(CRBProtocolObservers*)observers {
+  self = [super init];
+  if (self) {
+    _observers = observers;
+  }
+  return self;
+}
+
+- (void)mutateByAddingObserver:(id<TestObserver>)observer {
+  [_observers addObserver:observer];
+}
+
+- (void)mutateByRemovingObserver:(id<TestObserver>)observer {
+  [_observers removeObserver:observer];
+}
+
+- (void)nestedMutateByAddingObserver:(id<TestObserver>)observer {
+  [_observers mutateByAddingObserver:observer];
+}
+
+- (void)nestedMutateByRemovingObserver:(id<TestObserver>)observer {
+  [_observers mutateByRemovingObserver:observer];
+}
+
+@end
diff --git a/base/memory/memory_pressure_listener.cc b/base/memory/memory_pressure_listener.cc
index 6a8ed21..2a1be74e 100644
--- a/base/memory/memory_pressure_listener.cc
+++ b/base/memory/memory_pressure_listener.cc
@@ -8,31 +8,31 @@
 #include "base/observer_list_threadsafe.h"
 #include "base/trace_event/trace_event.h"
 
+namespace base {
+
 namespace {
 
 // ObserverListThreadSafe is RefCountedThreadSafe, this traits is needed
 // to ensure the LazyInstance will hold a reference to it.
 struct LeakyLazyObserverListTraits :
     base::internal::LeakyLazyInstanceTraits<
-        ObserverListThreadSafe<base::MemoryPressureListener> > {
-  static ObserverListThreadSafe<base::MemoryPressureListener>*
+        ObserverListThreadSafe<MemoryPressureListener> > {
+  static ObserverListThreadSafe<MemoryPressureListener>*
       New(void* instance) {
-    ObserverListThreadSafe<base::MemoryPressureListener>* ret =
+    ObserverListThreadSafe<MemoryPressureListener>* ret =
         base::internal::LeakyLazyInstanceTraits<
-            ObserverListThreadSafe<base::MemoryPressureListener> >::New(
-                instance);
+            ObserverListThreadSafe<MemoryPressureListener>>::New(instance);
     // Leaky.
     ret->AddRef();
     return ret;
   }
 };
 
-base::LazyInstance<
-    ObserverListThreadSafe<base::MemoryPressureListener>,
+LazyInstance<
+    ObserverListThreadSafe<MemoryPressureListener>,
     LeakyLazyObserverListTraits> g_observers = LAZY_INSTANCE_INITIALIZER;
-}  // namespace
 
-namespace base {
+}  // namespace
 
 MemoryPressureListener::MemoryPressureListener(
     const MemoryPressureListener::MemoryPressureCallback& callback)
diff --git a/base/memory/shared_memory_posix.cc b/base/memory/shared_memory_posix.cc
index 771f395..1ab05b2f 100644
--- a/base/memory/shared_memory_posix.cc
+++ b/base/memory/shared_memory_posix.cc
@@ -10,14 +10,11 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
-#include <vector>
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/histogram.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/process/process_metrics.h"
 #include "base/profiler/scoped_tracker.h"
@@ -27,7 +24,6 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/time/time.h"
 
 #if defined(OS_MACOSX)
 #include "base/mac/foundation_util.h"
@@ -44,7 +40,6 @@
 
 LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER;
 
-#if !defined(OS_ANDROID)
 struct ScopedPathUnlinkerTraits {
   static FilePath* InvalidValue() { return nullptr; }
 
@@ -62,39 +57,7 @@
 // Unlinks the FilePath when the object is destroyed.
 typedef ScopedGeneric<FilePath*, ScopedPathUnlinkerTraits> ScopedPathUnlinker;
 
-const char kSharedMemoryBatchCreate[] = "kSharedMemoryBatchCreate";
-const char kSharedMemoryCreateStrategy[] = "SharedMemoryCreateStrategy";
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-const int kBatchSize = 5;
-
-// This variable must only be accessed if |g_thread_lock_| is held.
-LazyInstance<std::vector<FILE*>>::Leaky g_file_pool_ =
-    LAZY_INSTANCE_INITIALIZER;
-#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
-
-// Whether to generate more than 1 shared memory handle at a time, and store
-// the results in a pool.
-bool ShouldBatchCreateSharedMemory() {
-#if !defined(OS_MACOSX) || defined(OS_IOS)
-  return false;
-#endif  // !defined(OS_MACOSX) || defined(OS_IOS)
-
-  g_thread_lock_.Get().AssertAcquired();
-
-  static bool has_determined_group = false;
-  static bool batch_create_shared_memory = false;
-
-  if (has_determined_group)
-    return batch_create_shared_memory;
-
-  const std::string group_name =
-      base::FieldTrialList::FindFullName(kSharedMemoryCreateStrategy);
-  batch_create_shared_memory = group_name == kSharedMemoryBatchCreate;
-  has_determined_group = true;
-  return batch_create_shared_memory;
-}
-
+#if !defined(OS_ANDROID)
 // Makes a temporary file, fdopens it, and then unlinks it. |fp| is populated
 // with the fdopened FILE. |readonly_fd| is populated with the opened fd if
 // options.share_read_only is true. |path| is populated with the location of
@@ -143,39 +106,6 @@
   }
   return true;
 }
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-// This method must only be called on OSX, since it assumes that
-// |options.executable| has no effect. It also doesn't fill in |path|, which is
-// only used for error logging when |options.share_read_only| is false.
-bool CreateAnonymousSharedMemoryFromBatch(
-    const SharedMemoryCreateOptions& options,
-    ScopedFILE* fp,
-    FilePath* path) {
-  DCHECK(!options.share_read_only);
-  g_thread_lock_.Get().AssertAcquired();
-  std::vector<FILE*>& file_pool = g_file_pool_.Get();
-
-  if (file_pool.empty()) {
-    for (int i = 0; i < kBatchSize; ++i) {
-      ScopedFILE temp_fp;
-      FilePath temp_path;
-      bool result =
-          CreateAnonymousSharedMemory(options, &temp_fp, NULL, &temp_path);
-      if (result)
-        file_pool.push_back(temp_fp.release());
-    }
-  }
-
-  if (file_pool.empty())
-    return false;
-
-  FILE* file = file_pool.back();
-  file_pool.pop_back();
-  fp->reset(file);
-  return true;
-}
-#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
 #endif  // !defined(OS_ANDROID)
 }
 
@@ -295,27 +225,10 @@
 
   FilePath path;
   if (options.name_deprecated == NULL || options.name_deprecated->empty()) {
-    AutoLock a(g_thread_lock_.Get());
-
-    Time start_time = base::Time::Now();
-    if (options.share_read_only || !ShouldBatchCreateSharedMemory()) {
-      bool result =
-          CreateAnonymousSharedMemory(options, &fp, &readonly_fd, &path);
-      if (!result)
-        return false;
-    } else {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-      bool result = CreateAnonymousSharedMemoryFromBatch(options, &fp, &path);
-      if (!result)
-        return false;
-#else
-      NOTREACHED();
-#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
-    }
-    if (!options.share_read_only) {
-      UMA_HISTOGRAM_TIMES("SharedMemory.TimeSpentMakingAnonymousMemory",
-                          Time::Now() - start_time);
-    }
+    bool result =
+        CreateAnonymousSharedMemory(options, &fp, &readonly_fd, &path);
+    if (!result)
+      return false;
   } else {
     if (!FilePathForMemoryName(*options.name_deprecated, &path))
       return false;
diff --git a/base/numerics/safe_conversions_impl.h b/base/numerics/safe_conversions_impl.h
index 504ce7e..4157067 100644
--- a/base/numerics/safe_conversions_impl.h
+++ b/base/numerics/safe_conversions_impl.h
@@ -148,10 +148,10 @@
                                       NUMERIC_RANGE_NOT_CONTAINED> {
   static RangeConstraint Check(Src value) {
     return std::numeric_limits<Dst>::is_iec559
-               ? GetRangeConstraint(value <= std::numeric_limits<Dst>::max(),
-                                    value >= -std::numeric_limits<Dst>::max())
-               : GetRangeConstraint(value <= std::numeric_limits<Dst>::max(),
-                                    value >= std::numeric_limits<Dst>::min());
+               ? GetRangeConstraint((value < std::numeric_limits<Dst>::max()),
+                                    (value > -std::numeric_limits<Dst>::max()))
+               : GetRangeConstraint((value < std::numeric_limits<Dst>::max()),
+                                    (value > std::numeric_limits<Dst>::min()));
   }
 };
 
@@ -163,7 +163,7 @@
                                       INTEGER_REPRESENTATION_UNSIGNED,
                                       NUMERIC_RANGE_NOT_CONTAINED> {
   static RangeConstraint Check(Src value) {
-    return GetRangeConstraint(value <= std::numeric_limits<Dst>::max(), true);
+    return GetRangeConstraint(value < std::numeric_limits<Dst>::max(), true);
   }
 };
 
@@ -178,7 +178,7 @@
     return sizeof(Dst) > sizeof(Src)
                ? RANGE_VALID
                : GetRangeConstraint(
-                     value <= static_cast<Src>(std::numeric_limits<Dst>::max()),
+                     value < static_cast<Src>(std::numeric_limits<Dst>::max()),
                      true);
   }
 };
@@ -195,7 +195,7 @@
     return (MaxExponent<Dst>::value >= MaxExponent<Src>::value)
                ? GetRangeConstraint(true, value >= static_cast<Src>(0))
                : GetRangeConstraint(
-                     value <= static_cast<Src>(std::numeric_limits<Dst>::max()),
+                     value < static_cast<Src>(std::numeric_limits<Dst>::max()),
                      value >= static_cast<Src>(0));
   }
 };
diff --git a/base/numerics/safe_numerics_unittest.cc b/base/numerics/safe_numerics_unittest.cc
index b8098c4..6f9a966 100644
--- a/base/numerics/safe_numerics_unittest.cc
+++ b/base/numerics/safe_numerics_unittest.cc
@@ -562,6 +562,8 @@
   double double_small = 1.0;
   double double_large = numeric_limits<double>::max();
   double double_infinity = numeric_limits<float>::infinity();
+  double double_large_int = numeric_limits<int>::max();
+  double double_small_int = numeric_limits<int>::min();
 
   // Just test that the casts compile, since the other tests cover logic.
   EXPECT_EQ(0, checked_cast<int>(static_cast<size_t>(0)));
@@ -594,5 +596,7 @@
   EXPECT_EQ(saturated_cast<int>(double_large), numeric_limits<int>::max());
   EXPECT_EQ(saturated_cast<float>(double_large), double_infinity);
   EXPECT_EQ(saturated_cast<float>(-double_large), -double_infinity);
+  EXPECT_EQ(numeric_limits<int>::min(), saturated_cast<int>(double_small_int));
+  EXPECT_EQ(numeric_limits<int>::max(), saturated_cast<int>(double_large_int));
 }
 
diff --git a/base/observer_list_threadsafe.h b/base/observer_list_threadsafe.h
index e8141ad..b9b4a62 100644
--- a/base/observer_list_threadsafe.h
+++ b/base/observer_list_threadsafe.h
@@ -270,7 +270,4 @@
 
 }  // namespace base
 
-// TODO(brettw) remove this when callers use the correct namespace.
-using base::ObserverListThreadSafe;
-
 #endif  // BASE_OBSERVER_LIST_THREADSAFE_H_
diff --git a/base/process/kill.h b/base/process/kill.h
index af00b03..dbd32e1 100644
--- a/base/process/kill.h
+++ b/base/process/kill.h
@@ -26,6 +26,10 @@
   TERMINATION_STATUS_PROCESS_WAS_KILLED,   // e.g. SIGKILL or task manager kill
   TERMINATION_STATUS_PROCESS_CRASHED,      // e.g. Segmentation fault
   TERMINATION_STATUS_STILL_RUNNING,        // child hasn't exited yet
+#if defined(OS_CHROMEOS)
+  // Used for the case when oom-killer kills a process on ChromeOS.
+  TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM,
+#endif
 #if defined(OS_ANDROID)
   // On Android processes are spawned from the system Zygote and we do not get
   // the termination status.  We can't know if the termination was a crash or an
diff --git a/base/process/kill_posix.cc b/base/process/kill_posix.cc
index 0e303c6..f0d2d44 100644
--- a/base/process/kill_posix.cc
+++ b/base/process/kill_posix.cc
@@ -50,8 +50,13 @@
       case SIGILL:
       case SIGSEGV:
         return TERMINATION_STATUS_PROCESS_CRASHED;
-      case SIGINT:
       case SIGKILL:
+#if defined(OS_CHROMEOS)
+        // On ChromeOS, only way a process gets kill by SIGKILL
+        // is by oom-killer.
+        return TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM;
+#endif
+      case SIGINT:
       case SIGTERM:
         return TERMINATION_STATUS_PROCESS_WAS_KILLED;
       default:
diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc
index 11d8874..1f7f1b2 100644
--- a/base/process/process_util_unittest.cc
+++ b/base/process/process_util_unittest.cc
@@ -75,6 +75,10 @@
 const char kSignalFileSlow[] = "SlowChildProcess.die";
 const char kSignalFileKill[] = "KilledChildProcess.die";
 
+#if defined(OS_POSIX)
+const char kSignalFileTerm[] = "TerminatedChildProcess.die";
+#endif
+
 #if defined(OS_WIN)
 const int kExpectedStillRunningExitCode = 0x102;
 const int kExpectedKilledExitCode = 1;
@@ -286,7 +290,16 @@
   return 1;
 }
 
-TEST_F(ProcessUtilTest, GetTerminationStatusKill) {
+#if defined(OS_POSIX)
+MULTIPROCESS_TEST_MAIN(TerminatedChildProcess) {
+  WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileTerm).c_str());
+  // Send a SIGTERM to this process.
+  ::kill(getpid(), SIGTERM);
+  return 1;
+}
+#endif
+
+TEST_F(ProcessUtilTest, GetTerminationStatusSigKill) {
   const std::string signal_file =
     ProcessUtilTest::GetSignalFilePath(kSignalFileKill);
   remove(signal_file.c_str());
@@ -302,7 +315,12 @@
   exit_code = 42;
   base::TerminationStatus status =
       WaitForChildTermination(process.Handle(), &exit_code);
+#if defined(OS_CHROMEOS)
+  EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM, status);
+#else
   EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
+#endif
+
 #if defined(OS_WIN)
   EXPECT_EQ(kExpectedKilledExitCode, exit_code);
 #elif defined(OS_POSIX)
@@ -314,6 +332,33 @@
   remove(signal_file.c_str());
 }
 
+#if defined(OS_POSIX)
+TEST_F(ProcessUtilTest, GetTerminationStatusSigTerm) {
+  const std::string signal_file =
+    ProcessUtilTest::GetSignalFilePath(kSignalFileTerm);
+  remove(signal_file.c_str());
+  base::Process process = SpawnChild("TerminatedChildProcess");
+  ASSERT_TRUE(process.IsValid());
+
+  int exit_code = 42;
+  EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
+            base::GetTerminationStatus(process.Handle(), &exit_code));
+  EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+  SignalChildren(signal_file.c_str());
+  exit_code = 42;
+  base::TerminationStatus status =
+      WaitForChildTermination(process.Handle(), &exit_code);
+  EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
+
+  int signaled = WIFSIGNALED(exit_code);
+  EXPECT_NE(0, signaled);
+  int signal = WTERMSIG(exit_code);
+  EXPECT_EQ(SIGTERM, signal);
+  remove(signal_file.c_str());
+}
+#endif
+
 #if defined(OS_WIN)
 // TODO(estade): if possible, port this test.
 TEST_F(ProcessUtilTest, GetAppOutput) {
diff --git a/base/trace_event/process_memory_dump_unittest.cc b/base/trace_event/process_memory_dump_unittest.cc
index c940a97..1e1fbc6 100644
--- a/base/trace_event/process_memory_dump_unittest.cc
+++ b/base/trace_event/process_memory_dump_unittest.cc
@@ -21,7 +21,7 @@
   pmd1->process_totals()->set_resident_set_bytes(42);
   pmd1->set_has_process_totals();
 
-  pmd1->process_mmaps()->AddVMRegion({0});
+  pmd1->process_mmaps()->AddVMRegion(ProcessMemoryMaps::VMRegion());
   pmd1->set_has_process_mmaps();
 
   pmd1->AddOwnershipEdge(MemoryAllocatorDumpGuid(42),
diff --git a/base/trace_event/process_memory_maps.cc b/base/trace_event/process_memory_maps.cc
index e2a1428..bb400de1 100644
--- a/base/trace_event/process_memory_maps.cc
+++ b/base/trace_event/process_memory_maps.cc
@@ -16,6 +16,18 @@
 const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite = 2;
 const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsExec = 1;
 
+ProcessMemoryMaps::VMRegion::VMRegion()
+    : start_address(0),
+      size_in_bytes(0),
+      protection_flags(0),
+      byte_stats_private_dirty_resident(0),
+      byte_stats_private_clean_resident(0),
+      byte_stats_shared_dirty_resident(0),
+      byte_stats_shared_clean_resident(0),
+      byte_stats_swapped(0),
+      byte_stats_proportional_resident(0) {
+}
+
 ProcessMemoryMaps::ProcessMemoryMaps() {
 }
 
@@ -38,10 +50,15 @@
     value->BeginDictionary("bs");  // byte stats
     value->SetString(
         "pss", StringPrintf(kHexFmt, region.byte_stats_proportional_resident));
-    value->SetString("prv",
-                     StringPrintf(kHexFmt, region.byte_stats_private_resident));
-    value->SetString("shr",
-                     StringPrintf(kHexFmt, region.byte_stats_shared_resident));
+    value->SetString(
+        "pd", StringPrintf(kHexFmt, region.byte_stats_private_dirty_resident));
+    value->SetString(
+        "pc", StringPrintf(kHexFmt, region.byte_stats_private_clean_resident));
+    value->SetString(
+        "sd", StringPrintf(kHexFmt, region.byte_stats_shared_dirty_resident));
+    value->SetString(
+        "sc", StringPrintf(kHexFmt, region.byte_stats_shared_clean_resident));
+    value->SetString("sw", StringPrintf(kHexFmt, region.byte_stats_swapped));
     value->EndDictionary();
 
     value->EndDictionary();
diff --git a/base/trace_event/process_memory_maps.h b/base/trace_event/process_memory_maps.h
index f38e134c..b06a850 100644
--- a/base/trace_event/process_memory_maps.h
+++ b/base/trace_event/process_memory_maps.h
@@ -19,19 +19,26 @@
 // Data model for process-wide memory stats.
 class BASE_EXPORT ProcessMemoryMaps {
  public:
-  struct VMRegion {
+  struct BASE_EXPORT VMRegion {
     static const uint32 kProtectionFlagsRead;
     static const uint32 kProtectionFlagsWrite;
     static const uint32 kProtectionFlagsExec;
 
+    VMRegion();
+
     uint64 start_address;
     uint64 size_in_bytes;
     uint32 protection_flags;
     std::string mapped_file;
 
-    // private_resident + shared_resident = resident set size.
-    uint64 byte_stats_private_resident;
-    uint64 byte_stats_shared_resident;
+    // private_dirty_resident + private_clean_resident + shared_dirty_resident +
+    // shared_clean_resident = resident set size.
+    uint64 byte_stats_private_dirty_resident;
+    uint64 byte_stats_private_clean_resident;
+    uint64 byte_stats_shared_dirty_resident;
+    uint64 byte_stats_shared_clean_resident;
+
+    uint64 byte_stats_swapped;
 
     // For multiprocess accounting.
     uint64 byte_stats_proportional_resident;
diff --git a/base/trace_event/process_memory_maps_dump_provider.cc b/base/trace_event/process_memory_maps_dump_provider.cc
index 680fa296..e0ae20d2 100644
--- a/base/trace_event/process_memory_maps_dump_provider.cc
+++ b/base/trace_event/process_memory_maps_dump_provider.cc
@@ -78,7 +78,7 @@
 uint32 ParseSmapsCounter(std::istream* smaps,
                          ProcessMemoryMaps::VMRegion* region) {
   // A smaps counter lines looks as follows: "RSS:  0 Kb\n"
-  uint32 res = 0;
+  uint32 res = 1;
   std::string counter_name;
   *smaps >> counter_name;
 
@@ -87,16 +87,18 @@
   // the case.
   if (counter_name == "Pss:") {
     region->byte_stats_proportional_resident = ReadCounterBytes(smaps);
-    res = 1;
-  } else if (counter_name == "Private_Dirty:" ||
-             counter_name == "Private_Clean:") {
-    // For Private and Shared counters keep the sum of the dirty + clean stats.
-    region->byte_stats_private_resident += ReadCounterBytes(smaps);
-    res = 1;
-  } else if (counter_name == "Shared_Dirty:" ||
-             counter_name == "Shared_Clean:") {
-    region->byte_stats_shared_resident += ReadCounterBytes(smaps);
-    res = 1;
+  } else if (counter_name == "Private_Dirty:") {
+    region->byte_stats_private_dirty_resident = ReadCounterBytes(smaps);
+  } else if (counter_name == "Private_Clean:") {
+    region->byte_stats_private_clean_resident = ReadCounterBytes(smaps);
+  } else if (counter_name == "Shared_Dirty:") {
+    region->byte_stats_shared_dirty_resident = ReadCounterBytes(smaps);
+  } else if (counter_name == "Shared_Clean:") {
+    region->byte_stats_shared_clean_resident = ReadCounterBytes(smaps);
+  } else if (counter_name == "Swap:") {
+    region->byte_stats_swapped = ReadCounterBytes(smaps);
+  } else {
+    res = 0;
   }
 
 #ifndef NDEBUG
@@ -117,7 +119,7 @@
   if (!smaps->good())
     return 0;
 
-  const uint32 kNumExpectedCountersPerRegion = 5;
+  const uint32 kNumExpectedCountersPerRegion = 6;
   uint32 counters_parsed_for_current_region = 0;
   uint32 num_valid_regions = 0;
   ProcessMemoryMaps::VMRegion region;
@@ -127,7 +129,7 @@
     if (next == std::ifstream::traits_type::eof() || next == '\n')
       break;
     if (isxdigit(next) && !isupper(next)) {
-      region = {0};
+      region = ProcessMemoryMaps::VMRegion();
       counters_parsed_for_current_region = 0;
       should_add_current_region = ParseSmapsHeader(smaps, &region);
     } else {
diff --git a/base/trace_event/process_memory_maps_dump_provider_unittest.cc b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
index e45d30a..5416e11 100644
--- a/base/trace_event/process_memory_maps_dump_provider_unittest.cc
+++ b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
@@ -29,7 +29,7 @@
     "Referenced:          296 kB\n"
     "Anonymous:            68 kB\n"
     "AnonHugePages:         0 kB\n"
-    "Swap:                  0 kB\n"
+    "Swap:                  4 kB\n"
     "KernelPageSize:        4 kB\n"
     "MMUPageSize:           4 kB\n"
     "Locked:                0 kB\n"
@@ -142,16 +142,22 @@
   EXPECT_EQ(kProtR | kProtX, regions_1[0].protection_flags);
   EXPECT_EQ("/file/1", regions_1[0].mapped_file);
   EXPECT_EQ(162 * 1024UL, regions_1[0].byte_stats_proportional_resident);
-  EXPECT_EQ((228 + 0) * 1024UL, regions_1[0].byte_stats_shared_resident);
-  EXPECT_EQ((0 + 68) * 1024UL, regions_1[0].byte_stats_private_resident);
+  EXPECT_EQ(228 * 1024UL, regions_1[0].byte_stats_shared_clean_resident);
+  EXPECT_EQ(0UL, regions_1[0].byte_stats_shared_dirty_resident);
+  EXPECT_EQ(0UL, regions_1[0].byte_stats_private_clean_resident);
+  EXPECT_EQ(68 * 1024UL, regions_1[0].byte_stats_private_dirty_resident);
+  EXPECT_EQ(4 * 1024UL, regions_1[0].byte_stats_swapped);
 
   EXPECT_EQ(0xff000000UL, regions_1[1].start_address);
   EXPECT_EQ(0xff800000UL - 0xff000000UL, regions_1[1].size_in_bytes);
   EXPECT_EQ(kProtW, regions_1[1].protection_flags);
   EXPECT_EQ("/file/name with space", regions_1[1].mapped_file);
   EXPECT_EQ(128 * 1024UL, regions_1[1].byte_stats_proportional_resident);
-  EXPECT_EQ((120 + 4) * 1024UL, regions_1[1].byte_stats_shared_resident);
-  EXPECT_EQ((60 + 8) * 1024UL, regions_1[1].byte_stats_private_resident);
+  EXPECT_EQ(120 * 1024UL, regions_1[1].byte_stats_shared_clean_resident);
+  EXPECT_EQ(4 * 1024UL, regions_1[1].byte_stats_shared_dirty_resident);
+  EXPECT_EQ(60 * 1024UL, regions_1[1].byte_stats_private_clean_resident);
+  EXPECT_EQ(8 * 1024UL, regions_1[1].byte_stats_private_dirty_resident);
+  EXPECT_EQ(0 * 1024UL, regions_1[1].byte_stats_swapped);
 
   // Parse the 2nd smaps file.
   ProcessMemoryDump pmd_2(nullptr /* session_state */);
@@ -166,8 +172,11 @@
   EXPECT_EQ(0U, regions_2[0].protection_flags);
   EXPECT_EQ("", regions_2[0].mapped_file);
   EXPECT_EQ(32 * 1024UL, regions_2[0].byte_stats_proportional_resident);
-  EXPECT_EQ((16 + 12) * 1024UL, regions_2[0].byte_stats_shared_resident);
-  EXPECT_EQ((8 + 4) * 1024UL, regions_2[0].byte_stats_private_resident);
+  EXPECT_EQ(16 * 1024UL, regions_2[0].byte_stats_shared_clean_resident);
+  EXPECT_EQ(12 * 1024UL, regions_2[0].byte_stats_shared_dirty_resident);
+  EXPECT_EQ(8 * 1024UL, regions_2[0].byte_stats_private_clean_resident);
+  EXPECT_EQ(4 * 1024UL, regions_2[0].byte_stats_private_dirty_resident);
+  EXPECT_EQ(0 * 1024UL, regions_2[0].byte_stats_swapped);
 }
 #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
 
diff --git a/base/trace_event/process_memory_totals.cc b/base/trace_event/process_memory_totals.cc
index cfa8f7e..1270924f 100644
--- a/base/trace_event/process_memory_totals.cc
+++ b/base/trace_event/process_memory_totals.cc
@@ -11,9 +11,20 @@
 namespace base {
 namespace trace_event {
 
+ProcessMemoryTotals::ProcessMemoryTotals()
+    : resident_set_bytes_(0),
+      peak_resident_set_bytes_(0),
+      is_peak_rss_resetable_(false) {
+}
+
 void ProcessMemoryTotals::AsValueInto(TracedValue* value) const {
   value->SetString("resident_set_bytes",
                    StringPrintf("%" PRIx64, resident_set_bytes_));
+  if (peak_resident_set_bytes_ > 0) {
+    value->SetString("peak_resident_set_bytes",
+                     StringPrintf("%" PRIx64, peak_resident_set_bytes_));
+    value->SetBoolean("is_peak_rss_resetable", is_peak_rss_resetable_);
+  }
 }
 
 void ProcessMemoryTotals::Clear() {
diff --git a/base/trace_event/process_memory_totals.h b/base/trace_event/process_memory_totals.h
index 29b518d..1bf8bdc 100644
--- a/base/trace_event/process_memory_totals.h
+++ b/base/trace_event/process_memory_totals.h
@@ -16,7 +16,7 @@
 // Data model for process-wide memory stats.
 class BASE_EXPORT ProcessMemoryTotals {
  public:
-  ProcessMemoryTotals() : resident_set_bytes_(0) {}
+  ProcessMemoryTotals();
 
   // Called at trace generation time to populate the TracedValue.
   void AsValueInto(TracedValue* value) const;
@@ -27,8 +27,22 @@
   uint64 resident_set_bytes() const { return resident_set_bytes_; }
   void set_resident_set_bytes(uint64 value) { resident_set_bytes_ = value; }
 
+  uint64 peak_resident_set_bytes() const { return peak_resident_set_bytes_; }
+  void set_peak_resident_set_bytes(uint64 value) {
+    peak_resident_set_bytes_ = value;
+  }
+
+  // On some platforms (recent linux kernels, see goo.gl/sMvAVz) the peak rss
+  // can be reset. When is_peak_rss_resettable == true, the peak refers to
+  // peak from the previous measurement. When false, it is the absolute peak
+  // since the start of the process.
+  bool is_peak_rss_resetable() const { return is_peak_rss_resetable_; }
+  void set_is_peak_rss_resetable(bool value) { is_peak_rss_resetable_ = value; }
+
  private:
   uint64 resident_set_bytes_;
+  uint64 peak_resident_set_bytes_;
+  bool is_peak_rss_resetable_;
 
   DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotals);
 };
diff --git a/base/trace_event/process_memory_totals_dump_provider.cc b/base/trace_event/process_memory_totals_dump_provider.cc
index 06b537c..37f9bed 100644
--- a/base/trace_event/process_memory_totals_dump_provider.cc
+++ b/base/trace_event/process_memory_totals_dump_provider.cc
@@ -8,6 +8,17 @@
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/process_memory_totals.h"
 
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#include <fcntl.h>
+
+#include "base/files/file_util.h"
+
+namespace {
+bool kernel_supports_rss_peak_reset = true;
+const char kClearPeakRssCommand[] = "5";
+}
+#endif
+
 namespace base {
 namespace trace_event {
 
@@ -47,8 +58,30 @@
                                ? rss_bytes_for_testing
                                : process_metrics_->GetWorkingSetSize();
 
+  uint64 peak_rss_bytes = 0;
+
+#if !defined(OS_IOS)
+  peak_rss_bytes = process_metrics_->GetPeakWorkingSetSize();
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  if (kernel_supports_rss_peak_reset) {
+    // TODO(ssid): Fix crbug.com/461788 to write to the file from sandboxed
+    // processes.
+    int clear_refs_fd = open("/proc/self/clear_refs", O_WRONLY);
+    if (clear_refs_fd > 0 &&
+        WriteFileDescriptor(clear_refs_fd, kClearPeakRssCommand,
+                            sizeof(kClearPeakRssCommand))) {
+      pmd->process_totals()->set_is_peak_rss_resetable(true);
+    } else {
+      kernel_supports_rss_peak_reset = false;
+    }
+    close(clear_refs_fd);
+  }
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+#endif  // !defined(OS_IOS)
+
   if (rss_bytes > 0) {
     pmd->process_totals()->set_resident_set_bytes(rss_bytes);
+    pmd->process_totals()->set_peak_resident_set_bytes(peak_rss_bytes);
     pmd->set_has_process_totals();
     return true;
   }
diff --git a/base/trace_event/trace_config.h b/base/trace_event/trace_config.h
index fe23c172..a9f830656 100644
--- a/base/trace_event/trace_config.h
+++ b/base/trace_event/trace_config.h
@@ -122,6 +122,7 @@
   void SetTraceRecordMode(TraceRecordMode mode) { record_mode_ = mode; }
   void EnableSampling() { enable_sampling_ = true; }
   void EnableSystrace() { enable_systrace_ = true; }
+  void EnableArgumentFilter() { enable_argument_filter_ = true; }
 
   // Writes the string representation of the TraceConfig. The string is JSON
   // formatted.
diff --git a/build/all.gyp b/build/all.gyp
index 36ca403..8da4abc3 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -95,8 +95,8 @@
             }],
             ['target_arch == "arm" or target_arch == "arm64"', {
               'dependencies': [
-                # The relocation packer only works on ARM or ARM64.
-                '../tools/relocation_packer/relocation_packer.gyp:relocation_packer_unittests#host',
+                # The relocation packer is currently used only for ARM or ARM64.
+                '../third_party/android_platform/relocation_packer.gyp:android_relocation_packer_unittests#host',
               ],
             }],
           ],
diff --git a/build/android/gyp/pack_arm_relocations.py b/build/android/gyp/pack_arm_relocations.py
index 517a22eb..02e4499 100755
--- a/build/android/gyp/pack_arm_relocations.py
+++ b/build/android/gyp/pack_arm_relocations.py
@@ -4,17 +4,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Pack ARM relative relocations in a library (or copy unchanged).
+"""Pack relocations in a library (or copy unchanged).
 
 If --enable-packing and --configuration-name=='Release', invoke the
 relocation_packer tool to pack the .rel.dyn or .rela.dyn section in the given
 library files.  This step is inserted after the libraries are stripped.
-Packing adds a new .android.rel.dyn or .android.rela.dyn section to the file
-and reduces the size of .rel.dyn or .rela.dyn accordingly.
 
-Currently packing only understands ARM32 shared libraries.  For all other
-architectures --enable-packing should be set to zero.  In this case the
-script copies files verbatim, with no attempt to pack relative relocations.
+If --enable-packing is zero, the script copies files verbatim, with no
+attempt to pack relocations.
 
 Any library listed in --exclude-packing-list is also copied verbatim,
 irrespective of any --enable-packing setting.  Typically this would be
@@ -30,32 +27,13 @@
 
 from util import build_utils
 
-def PackArmLibraryRelocations(android_pack_relocations,
-                              android_objcopy,
-                              has_relocations_with_addends,
-                              library_path,
-                              output_path):
-  # Select an appropriate name for the section we add.
-  if has_relocations_with_addends:
-    new_section = '.android.rela.dyn'
-  else:
-    new_section = '.android.rel.dyn'
-
-  # Copy and add a 'NULL' packed relocations section for the packing tool.
-  with tempfile.NamedTemporaryFile() as stream:
-    stream.write('NULL')
-    stream.flush()
-    objcopy_command = [android_objcopy,
-                       '--add-section', '%s=%s' % (new_section, stream.name),
-                       library_path, output_path]
-    build_utils.CheckOutput(objcopy_command)
-
-  # Pack R_ARM_RELATIVE relocations.
+def PackLibraryRelocations(android_pack_relocations, library_path, output_path):
+  shutil.copy(library_path, output_path)
   pack_command = [android_pack_relocations, output_path]
   build_utils.CheckOutput(pack_command)
 
 
-def CopyArmLibraryUnchanged(library_path, output_path):
+def CopyLibraryUnchanged(library_path, output_path):
   shutil.copy(library_path, output_path)
 
 
@@ -75,16 +53,11 @@
       choices=['0', '1'],
       help=('Pack relocations if 1 and configuration name is \'Release\','
             ' otherwise plain file copy'))
-  parser.add_option('--has-relocations-with-addends',
-      choices=['0', '1'],
-      help=('Pack into \'.android.rela.dyn\' if 1, else \'.android.rel.dyn\''))
   parser.add_option('--exclude-packing-list',
       default='',
       help='Names of any libraries explicitly not packed')
   parser.add_option('--android-pack-relocations',
-      help='Path to the ARM relocations packer binary')
-  parser.add_option('--android-objcopy',
-      help='Path to the toolchain\'s objcopy binary')
+      help='Path to the relocations packer binary')
   parser.add_option('--stripped-libraries-dir',
       help='Directory for stripped libraries')
   parser.add_option('--packed-libraries-dir',
@@ -96,7 +69,6 @@
   options, _ = parser.parse_args(args)
   enable_packing = (options.enable_packing == '1' and
                     options.configuration_name == 'Release')
-  has_relocations_with_addends = (options.has_relocations_with_addends == '1')
   exclude_packing_set = set(shlex.split(options.exclude_packing_list))
 
   libraries = []
@@ -114,13 +86,11 @@
         options.packed_libraries_dir, os.path.basename(library))
 
     if enable_packing and library not in exclude_packing_set:
-      PackArmLibraryRelocations(options.android_pack_relocations,
-                                options.android_objcopy,
-                                has_relocations_with_addends,
-                                library_path,
-                                output_path)
+      PackLibraryRelocations(options.android_pack_relocations,
+                             library_path,
+                             output_path)
     else:
-      CopyArmLibraryUnchanged(library_path, output_path)
+      CopyLibraryUnchanged(library_path, output_path)
 
   if options.depfile:
     build_utils.WriteDepfile(
diff --git a/build/android/gyp/package_resources.py b/build/android/gyp/package_resources.py
index a73d9d5..f2c2a6e 100755
--- a/build/android/gyp/package_resources.py
+++ b/build/android/gyp/package_resources.py
@@ -71,8 +71,8 @@
   parser = optparse.OptionParser()
   build_utils.AddDepfileOption(parser)
   parser.add_option('--android-sdk', help='path to the Android SDK folder')
-  parser.add_option('--android-sdk-tools',
-                    help='path to the Android SDK build tools folder')
+  parser.add_option('--aapt-path',
+                    help='path to the Android aapt tool')
 
   parser.add_option('--configuration-name',
                     help='Gyp\'s configuration name (Debug or Release).')
@@ -105,7 +105,7 @@
     parser.error('No positional arguments should be given.')
 
   # Check that required options have been provided.
-  required_options = ('android_sdk', 'android_sdk_tools', 'configuration_name',
+  required_options = ('android_sdk', 'aapt_path', 'configuration_name',
                       'android_manifest', 'version_code', 'version_name',
                       'apk_path')
 
@@ -187,7 +187,7 @@
 def main():
   options = ParseArgs()
   android_jar = os.path.join(options.android_sdk, 'android.jar')
-  aapt = os.path.join(options.android_sdk_tools, 'aapt')
+  aapt = options.aapt_path
 
   with build_utils.TempDir() as temp_dir:
     package_command = [aapt,
diff --git a/build/android/gyp/process_resources.py b/build/android/gyp/process_resources.py
index 8a2637d..d227954 100755
--- a/build/android/gyp/process_resources.py
+++ b/build/android/gyp/process_resources.py
@@ -38,8 +38,8 @@
   build_utils.AddDepfileOption(parser)
 
   parser.add_option('--android-sdk', help='path to the Android SDK folder')
-  parser.add_option('--android-sdk-tools',
-                    help='path to the Android SDK build tools folder')
+  parser.add_option('--aapt-path',
+                    help='path to the Android aapt tool')
   parser.add_option('--non-constant-id', action='store_true')
 
   parser.add_option('--android-manifest', help='AndroidManifest.xml path')
@@ -102,7 +102,7 @@
   # Check that required options have been provided.
   required_options = (
       'android_sdk',
-      'android_sdk_tools',
+      'aapt_path',
       'android_manifest',
       'dependencies_res_zips',
       'resource_dirs',
@@ -303,7 +303,7 @@
 
   options = ParseArgs(args)
   android_jar = os.path.join(options.android_sdk, 'android.jar')
-  aapt = os.path.join(options.android_sdk_tools, 'aapt')
+  aapt = options.aapt_path
 
   input_files = []
 
diff --git a/build/android/pack_arm_relocations.gypi b/build/android/pack_arm_relocations.gypi
index 5df1d7e..2c801576 100644
--- a/build/android/pack_arm_relocations.gypi
+++ b/build/android/pack_arm_relocations.gypi
@@ -3,7 +3,7 @@
 # found in the LICENSE file.
 
 # This file is meant to be included into an action to provide a rule that
-# packs ARM relative relocations in Release builds of native libraries.
+# packs relocations in Release builds of native libraries.
 #
 # To use this, create a gyp target with the following form:
 #  {
@@ -25,13 +25,6 @@
 {
   'variables': {
     'input_paths': [],
-    'conditions': [
-      ['target_arch == "arm64"', {
-        'has_relocations_with_addends': 1,
-      }, {
-        'has_relocations_with_addends': 0,
-      }],
-    ],
   },
   'inputs': [
     '<(DEPTH)/build/android/gyp/util/build_utils.py',
@@ -44,21 +37,19 @@
   ],
   'conditions': [
     ['enable_packing == 1', {
-      'message': 'Packing ARM relative relocations for <(_target_name)',
+      'message': 'Packing relocations for <(_target_name)',
       'dependencies': [
-        '<(DEPTH)/tools/relocation_packer/relocation_packer.gyp:relocation_packer#host',
+        '<(DEPTH)/third_party/android_platform/relocation_packer.gyp:android_relocation_packer#host',
       ],
       'inputs': [
-        '<(PRODUCT_DIR)/relocation_packer',
+        '<(PRODUCT_DIR)/android_relocation_packer',
       ],
       'action': [
         'python', '<(DEPTH)/build/android/gyp/pack_arm_relocations.py',
         '--configuration-name=<(CONFIGURATION_NAME)',
         '--enable-packing=1',
-        '--has-relocations-with-addends=<(has_relocations_with_addends)',
         '--exclude-packing-list=<@(exclude_packing_list)',
-        '--android-pack-relocations=<(PRODUCT_DIR)/relocation_packer',
-        '--android-objcopy=<(android_objcopy)',
+        '--android-pack-relocations=<(PRODUCT_DIR)/android_relocation_packer',
         '--stripped-libraries-dir=<(stripped_libraries_dir)',
         '--packed-libraries-dir=<(packed_libraries_dir)',
         '--libraries=@FileArg(<(ordered_libraries_file):libraries)',
diff --git a/build/android/package_resources_action.gypi b/build/android/package_resources_action.gypi
index cd6c59c..82615ca 100644
--- a/build/android/package_resources_action.gypi
+++ b/build/android/package_resources_action.gypi
@@ -45,7 +45,7 @@
   'action': [
     'python', '<(DEPTH)/build/android/gyp/package_resources.py',
     '--android-sdk', '<(android_sdk)',
-    '--android-sdk-tools', '<(android_sdk_tools)',
+    '--aapt-path', '<(android_aapt_path)',
     '--configuration-name', '<(CONFIGURATION_NAME)',
     '--android-manifest', '<(android_manifest_path)',
     '--version-code', '<(app_manifest_version_code)',
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
index 967809ff8..c8b4718 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -290,7 +290,7 @@
     if 'needs_su' in self._cache:
       del self._cache['needs_su']
     self.adb.Root()
-    self.adb.WaitForDevice()
+    self.WaitUntilFullyBooted()
 
   @decorators.WithTimeoutAndRetriesFromInstance()
   def IsUserBuild(self, timeout=None, retries=None):
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py
index 23a1a32..317e81e 100755
--- a/build/android/pylib/device/device_utils_test.py
+++ b/build/android/pylib/device/device_utils_test.py
@@ -140,6 +140,18 @@
         self.adb, default_timeout=10, default_retries=0)
     self.watchMethodCalls(self.call.adb, ignore=['GetDeviceSerial'])
 
+  def AdbCommandError(self, args=None, output=None, status=None, msg=None):
+    if args is None:
+      args = ['[unspecified]']
+    return mock.Mock(side_effect=device_errors.AdbCommandFailedError(
+        args, output, status, msg, str(self.device)))
+
+  def CommandError(self, msg=None):
+    if msg is None:
+      msg = 'Command failed'
+    return mock.Mock(side_effect=device_errors.CommandFailedError(
+        msg, str(self.device)))
+
   def ShellError(self, output=None, status=1):
     def action(cmd, *args, **kwargs):
       raise device_errors.AdbShellCommandFailedError(
@@ -154,12 +166,6 @@
     return mock.Mock(side_effect=device_errors.CommandTimeoutError(
         msg, str(self.device)))
 
-  def CommandError(self, msg=None):
-    if msg is None:
-      msg = 'Command failed'
-    return mock.Mock(side_effect=device_errors.CommandFailedError(
-        msg, str(self.device)))
-
 
 class DeviceUtilsEqTest(DeviceUtilsTest):
 
@@ -259,8 +265,8 @@
   def testEnableRoot_succeeds(self):
     with self.assertCalls(
         (self.call.device.IsUserBuild(), False),
-        self.call.adb.Root(),
-        self.call.adb.WaitForDevice()):
+         self.call.adb.Root(),
+         self.call.device.WaitUntilFullyBooted()):
       self.device.EnableRoot()
 
   def testEnableRoot_userBuild(self):
@@ -362,6 +368,27 @@
          'stuff\nWi-Fi is enabled\nmore stuff\n')):
       self.device.WaitUntilFullyBooted(wifi=True)
 
+  def testWaitUntilFullyBooted_deviceNotInitiallyAvailable(self):
+    with self.assertCalls(
+        self.call.adb.WaitForDevice(),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
+        # sd_card_ready
+        (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+        (self.call.adb.Shell('test -d /fake/storage/path'), ''),
+        # pm_ready
+        (self.call.device.GetApplicationPath('android'),
+         'package:/some/fake/path'),
+        # boot_completed
+        (self.call.device.GetProp('sys.boot_completed'), '1')):
+      self.device.WaitUntilFullyBooted(wifi=False)
+
   def testWaitUntilFullyBooted_sdCardReadyFails_noPath(self):
     with self.assertCalls(
         self.call.adb.WaitForDevice(),
diff --git a/build/android/pylib/gtest/filter/webkit_unit_tests_disabled b/build/android/pylib/gtest/filter/webkit_unit_tests_disabled
index 50292aa..1ffa325 100644
--- a/build/android/pylib/gtest/filter/webkit_unit_tests_disabled
+++ b/build/android/pylib/gtest/filter/webkit_unit_tests_disabled
@@ -23,6 +23,3 @@
 
 # crbug.com/320005
 CoreAnimationCompositorAnimationsTest.ConvertTimingForCompositorIterationCount
-
-# crbug.com/412145
-TouchActionTest.Pan
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index b71f805..52de8fd 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -1026,8 +1026,7 @@
     logging.exception('Error occurred.')
     if e.is_infra_error:
       return constants.INFRA_EXIT_CODE
-    else:
-      return constants.ERROR_EXIT_CODE
+    return constants.ERROR_EXIT_CODE
   except: # pylint: disable=W0702
     logging.exception('Unrecognized error occurred.')
     return constants.ERROR_EXIT_CODE
diff --git a/build/common.gypi b/build/common.gypi
index c8b9092..0b32d449 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -85,6 +85,11 @@
           # Enable top chrome material design.
           'enable_topchrome_md%' : 0,
 
+          # Force building against pre-built sysroot image on linux.  By default
+          # the sysroot image is only used for Official builds  or when cross
+          # compiling to arm or mips.
+          'use_sysroot%': 0,
+
           # Override buildtype to select the desired build flavor.
           # Dev - everyday build for development/testing
           # Official - release build (generally implies additional processing)
@@ -177,7 +182,6 @@
 
         # The system root for cross-compiles. Default: none.
         'sysroot%': '',
-        'use_sysroot%': 0,
         'chroot_cmd%': '',
 
         # The system libdir used for this ABI.
@@ -243,7 +247,7 @@
             'enable_app_list%': 0,
           }],
 
-          ['use_aura==1 or (OS!="win" and OS!="mac" and OS!="ios" and OS!="android")', {
+          ['use_aura==1 and OS!="android"', {
             'use_default_render_theme%': 1,
           }, {
             'use_default_render_theme%': 0,
@@ -282,6 +286,27 @@
           ['target_arch=="mipsel"', {
             'mips_arch_variant%': 'r1',
           }],
+
+          ['OS=="linux" and target_arch=="arm" and chromeos==0', {
+            # sysroot needs to be an absolute path otherwise it generates
+            # incorrect results when passed to pkg-config
+            'sysroot%': '<!(cd <(DEPTH) && pwd -P)/chrome/installer/linux/debian_wheezy_arm-sysroot',
+          }], # OS=="linux" and target_arch=="arm" and chromeos==0
+
+          ['OS=="linux" and ((branding=="Chrome" and buildtype=="Official" and chromeos==0) or use_sysroot==1)' , {
+            'conditions': [
+              ['target_arch=="x64"', {
+                'sysroot%': '<!(cd <(DEPTH) && pwd -P)/chrome/installer/linux/debian_wheezy_amd64-sysroot',
+              }],
+              ['target_arch=="ia32"', {
+                'sysroot%': '<!(cd <(DEPTH) && pwd -P)/chrome/installer/linux/debian_wheezy_i386-sysroot',
+              }],
+          ],
+          }], # OS=="linux" and branding=="Chrome" and buildtype=="Official" and chromeos==0
+
+          ['OS=="linux" and target_arch=="mipsel"', {
+            'sysroot%': '<!(cd <(DEPTH) && pwd -P)/mipsel-sysroot/sysroot',
+          }],
         ],
       },
 
@@ -933,28 +958,6 @@
           'enable_settings_app%': 0,
         }],
 
-        ['OS=="linux" and target_arch=="arm" and chromeos==0', {
-          # sysroot needs to be an absolute path otherwise it generates
-          # incorrect results when passed to pkg-config
-          'sysroot%': '<!(cd <(DEPTH) && pwd -P)/chrome/installer/linux/debian_wheezy_arm-sysroot',
-        }], # OS=="linux" and target_arch=="arm" and chromeos==0
-
-        ['OS=="linux" and ((branding=="Chrome" and buildtype=="Official" and chromeos==0) or use_sysroot==1)' , {
-          'conditions': [
-            ['target_arch=="x64"', {
-              'sysroot%': '<!(cd <(DEPTH) && pwd -P)/chrome/installer/linux/debian_wheezy_amd64-sysroot',
-            }],
-            ['target_arch=="ia32"', {
-              'sysroot%': '<!(cd <(DEPTH) && pwd -P)/chrome/installer/linux/debian_wheezy_i386-sysroot',
-            }],
-        ],
-        }], # OS=="linux" and branding=="Chrome" and buildtype=="Official" and chromeos==0
-
-        ['OS=="linux" and target_arch=="mipsel"', {
-          'sysroot%': '<!(cd <(DEPTH) && pwd -P)/mipsel-sysroot/sysroot',
-          'CXX%': '<!(cd <(DEPTH) && pwd -P)/mipsel-sysroot/bin/mipsel-linux-gnu-gcc',
-        }],
-
         # Whether tests targets should be run, archived or just have the
         # dependencies verified. All the tests targets have the '_run' suffix,
         # e.g. base_unittests_run runs the target base_unittests. The test
@@ -1009,6 +1012,12 @@
         }, {
           'sas_dll_path%': '<(DEPTH)/third_party/platformsdk_win7/files/redist/x86',
         }],
+
+        ['sysroot!=""', {
+          'pkg-config': '<(DEPTH)/build/linux/pkg-config-wrapper "<(sysroot)" "<(target_arch)" "<(system_libdir)"',
+        }, {
+          'pkg-config': 'pkg-config'
+        }],
       ],
 
       # Setting this to '0' will cause V8's startup snapshot to be
@@ -1109,7 +1118,7 @@
     'chromecast%': '<(chromecast)',
     'enable_viewport%': '<(enable_viewport)',
     'enable_hidpi%': '<(enable_hidpi)',
-	'enable_topchrome_md%': '<(enable_topchrome_md)',
+    'enable_topchrome_md%': '<(enable_topchrome_md)',
     'image_loader_extension%': '<(image_loader_extension)',
     'fastbuild%': '<(fastbuild)',
     'dont_embed_build_metadata%': '<(dont_embed_build_metadata)',
@@ -1120,6 +1129,7 @@
     'arm_neon%': '<(arm_neon)',
     'arm_neon_optional%': '<(arm_neon_optional)',
     'sysroot%': '<(sysroot)',
+    'pkg-config%': '<(pkg-config)',
     'chroot_cmd%': '<(chroot_cmd)',
     'system_libdir%': '<(system_libdir)',
     'component%': '<(component)',
@@ -1598,10 +1608,6 @@
             'nacl_untrusted_build%': 0,
             'use_allocator%': 'none',
           }],
-          ['OS=="linux" and target_arch=="mipsel"', {
-            'sysroot%': '<(sysroot)',
-            'CXX%': '<(CXX)',
-          }],
           # Use a 64-bit linker to avoid running out of address space. The
           # buildbots should have a 64-bit kernel and a 64-bit libc installed.
           ['host_arch=="ia32" and target_arch=="ia32"', {
@@ -1692,7 +1698,7 @@
           'host_os%': '<(host_os)',
 
           'android_sdk%': '<(android_sdk_root)/platforms/android-<(android_sdk_version)',
-          # Android SDK build tools (e.g. dx, aapt, aidl)
+          # Android SDK build tools (e.g. dx, aidl)
           'android_sdk_tools%': '<(android_sdk_root)/build-tools/<(android_sdk_build_tools_version)',
 
           # Android API level 16 is JB (Android 4.1) which is the minimum
@@ -1761,6 +1767,7 @@
         'android_ndk_include': '<(android_ndk_sysroot)/usr/include',
         'android_ndk_lib': '<(android_ndk_sysroot)/<(android_ndk_lib_dir)',
         'android_sdk_tools%': '<(android_sdk_tools)',
+        'android_aapt_path%': '<(android_sdk_tools)/aapt',
         'android_sdk%': '<(android_sdk)',
         'android_sdk_jar%': '<(android_sdk)/android.jar',
 
@@ -1974,7 +1981,7 @@
         'use_cups%': 0,
       }],
 
-      ['enable_plugins==1 and (OS=="linux" or OS=="mac" or OS=="win")', {
+      ['enable_plugins==1 and (OS=="linux" or OS=="mac" or OS=="win") and chromecast==0', {
         'enable_pepper_cdms%': 1,
       }, {
         'enable_pepper_cdms%': 0,
@@ -3888,17 +3895,6 @@
                       '-fuse-ld=gold',
                     ],
                   }],
-                  # Install packages have started cropping up with
-                  # different headers between the 32-bit and 64-bit
-                  # versions, so we have to shadow those differences off
-                  # and make sure a 32-bit-on-64-bit build picks up the
-                  # right files.
-                  # For android build, use NDK headers instead of host headers
-                  ['host_arch!="ia32" and OS!="android"', {
-                    'include_dirs+': [
-                      '/usr/include32',
-                    ],
-                  }],
                 ],
               }],
             ],
@@ -4167,6 +4163,9 @@
                           ['OS=="android"', {
                             'cflags': [ '-target mipsel-linux-android', '-march=mipsel', '-mcpu=mips32r2'],
                             'ldflags': [ '-target mipsel-linux-android', ],
+                          }, {
+                            'cflags': [ '-target mipsel-linux-gnu', '-march=mipsel', '-mcpu=mips32r2'],
+                            'ldflags': [ '-target mipsel-linux-gnu', ],
                           }],
                          ],
                       }, { # clang==0
@@ -4181,6 +4180,9 @@
                           ['OS=="android"', {
                             'cflags': [ '-target mipsel-linux-android', '-march=mipsel', '-mcpu=mips32'],
                             'ldflags': [ '-target mipsel-linux-android', ],
+                          }, {
+                            'cflags': [ '-target mipsel-linux-gnu', '-march=mipsel', '-mcpu=mips32'],
+                            'ldflags': [ '-target mipsel-linux-gnu', ],
                           }],
                         ],
                       }, { # clang==0
@@ -4196,6 +4198,10 @@
                     'cflags': [
                       # TODO(gordanac) Enable integrated-as.
                       '-no-integrated-as',
+                    ],
+                  }],
+                  ['clang==1 and OS=="android"', {
+                    'cflags': [
                       '-B<(android_toolchain)',  # Else /usr/bin/as gets picked up.
                     ],
                     'ldflags': [
@@ -5942,7 +5948,7 @@
         ['CXX.host', '<(host_cxx)'],
       ],
     }],
-    ['OS=="linux" and target_arch=="mipsel"', {
+    ['OS=="linux" and target_arch=="mipsel" and clang==0', {
       'make_global_settings': [
         ['CC', '<(sysroot)/../bin/mipsel-linux-gnu-gcc'],
         ['CXX', '<(sysroot)/../bin/mipsel-linux-gnu-g++'],
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 72ad8dfa..d3d54f1c 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -13,6 +13,7 @@
 
 android_sdk_jar = "$android_sdk/android.jar"
 rebased_android_sdk_jar = rebase_path(android_sdk_jar, root_build_dir)
+android_aapt_path = "$rebased_android_sdk_build_tools/aapt"
 
 template("android_lint") {
   set_sources_assignment_filter([])
@@ -635,8 +636,8 @@
       rebase_path(depfile, root_build_dir),
       "--android-sdk",
       rebased_android_sdk,
-      "--android-sdk-tools",
-      rebased_android_sdk_build_tools,
+      "--aapt-path",
+      android_aapt_path,
       "--configuration-name=$_configuration_name",
       "--android-manifest",
       rebase_path(_android_manifest, root_build_dir),
@@ -1264,8 +1265,8 @@
       rebase_path(depfile, root_build_dir),
       "--android-sdk",
       rebase_path(android_sdk, root_build_dir),
-      "--android-sdk-tools",
-      rebase_path(android_sdk_build_tools, root_build_dir),
+      "--aapt-path",
+      android_aapt_path,
       "--android-manifest",
       rebase_path(android_manifest, root_build_dir),
       "--resource-dirs=$rebase_resource_dirs",
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 67d2b5d..0c135b3 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -5,8 +5,8 @@
 import("//base/android/linker/config.gni")
 import("//build/config/android/config.gni")
 import("//build/config/android/internal_rules.gni")
+import("//third_party/android_platform/config.gni")
 import("//tools/grit/grit_rule.gni")
-import("//tools/relocation_packer/config.gni")
 
 assert(is_android)
 
@@ -746,7 +746,7 @@
   build_config = base_path + ".build_config"
 
   build_config_target_name = "${target_name}__build_config"
-  zip_target_name ="${target_name}__zip" 
+  zip_target_name = "${target_name}__zip"
   final_target_name = target_name
 
   write_build_config(build_config_target_name) {
@@ -1572,12 +1572,9 @@
         "--depfile",
         rebase_path(depfile, root_build_dir),
         "--enable-packing=$enable_packing_arg",
-        "--has-relocations-with-addends=$relocations_have_addends",
         "--exclude-packing-list=$skip_packing_list",
         "--android-pack-relocations",
         rebase_path(relocation_packer_exe, root_build_dir),
-        "--android-objcopy",
-        rebase_path(android_objcopy, root_build_dir),
         "--stripped-libraries-dir",
         rebase_path(root_build_dir, root_build_dir),
         "--packed-libraries-dir",
@@ -1967,6 +1964,7 @@
 #   create_native_executable_dist("foo_dist") {
 #     dist_dir = "$root_build_dir/foo_dist"
 #     binary = "$root_build_dir/exe.stripped/foo"
+#     deps = [ ":the_thing_that_makes_foo" ]
 #   }
 template("create_native_executable_dist") {
   set_sources_assignment_filter([])
@@ -2015,6 +2013,9 @@
       "--readelf",
       rebase_path(android_readelf, root_build_dir),
     ]
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
   }
 
   copy_ex(copy_target_name) {
@@ -2036,6 +2037,9 @@
     deps = [
       ":$find_deps_target_name",
     ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
   }
 
   group(template_name) {
diff --git a/build/config/ui.gni b/build/config/ui.gni
index 6788053..bee5f48 100644
--- a/build/config/ui.gni
+++ b/build/config/ui.gni
@@ -56,7 +56,7 @@
 # with the Aura window manager.
 ui_compositor_image_transport = use_aura && is_linux
 
-use_default_render_theme = use_aura || is_linux
+use_default_render_theme = use_aura && !is_android
 
 # Indicates if the UI toolkit depends on X11.
 use_x11 = is_linux && !use_ozone
diff --git a/build/filename_rules.gypi b/build/filename_rules.gypi
index 48c8027..f67287fa 100644
--- a/build/filename_rules.gypi
+++ b/build/filename_rules.gypi
@@ -97,14 +97,7 @@
       'sources/': [ ['exclude', '_ashwin\\.(h|cc)$'] ]
     }],
     ['<(use_ozone)==0 or >(nacl_untrusted_build)==1', {
-      'sources/': [ ['exclude', '_ozone(_browsertest|_unittest)?\\.(h|cc)$'],
-                    ['exclude', '(^|/)ozone/'],
-      ]
-    }],
-    ['<(use_ozone_evdev)==0 or >(nacl_untrusted_build)==1', {
-      'sources/': [ ['exclude', '_evdev(_browsertest|_unittest)?\\.(h|cc)$'],
-                    ['exclude', '(^|/)evdev/'],
-      ]
+      'sources/': [ ['exclude', '_ozone(_browsertest|_unittest)?\\.(h|cc)$'] ]
     }],
     ['<(use_pango)==0', {
       'sources/': [ ['exclude', '(^|_)pango(_util|_browsertest|_unittest)?\\.(h|cc)$'], ],
diff --git a/build/gyp_chromium b/build/gyp_chromium
index 704b561..9dac8710 100755
--- a/build/gyp_chromium
+++ b/build/gyp_chromium
@@ -32,6 +32,7 @@
 sys.path.insert(1, os.path.join(chrome_src, 'build', 'android', 'gyp'))
 sys.path.insert(1, os.path.join(chrome_src, 'chrome', 'tools', 'build'))
 sys.path.insert(1, os.path.join(chrome_src, 'chromecast', 'tools', 'build'))
+sys.path.insert(1, os.path.join(chrome_src, 'ios', 'chrome', 'tools', 'build'))
 sys.path.insert(1, os.path.join(chrome_src, 'native_client', 'build'))
 sys.path.insert(1, os.path.join(chrome_src, 'native_client_sdk', 'src',
     'build_tools'))
diff --git a/build/java.gypi b/build/java.gypi
index 75c1829e..cee70e5 100644
--- a/build/java.gypi
+++ b/build/java.gypi
@@ -176,7 +176,7 @@
           'action': [
             'python', '<(DEPTH)/build/android/gyp/process_resources.py',
             '--android-sdk', '<(android_sdk)',
-            '--android-sdk-tools', '<(android_sdk_tools)',
+            '--aapt-path', '<(android_aapt_path)',
             '--non-constant-id',
 
             '--android-manifest', '<(android_manifest)',
diff --git a/build/java_aidl.gypi b/build/java_aidl.gypi
index 8f111fd..dda28942 100644
--- a/build/java_aidl.gypi
+++ b/build/java_aidl.gypi
@@ -35,6 +35,7 @@
 
 {
   'variables': {
+    'aidl_path%': '<(android_sdk_tools)/aidl',
     'intermediate_dir': '<(SHARED_INTERMEDIATE_DIR)/<(_target_name)/aidl',
     'aidl_import_include%': '',
     'additional_aidl_arguments': [],
@@ -66,7 +67,7 @@
         '<(intermediate_dir)/<(RULE_INPUT_ROOT).java',
       ],
       'action': [
-        '<(android_sdk_tools)/aidl',
+        '<(aidl_path)',
         '-p<(android_sdk)/framework.aidl',
         '-p<(aidl_interface_file)',
         '<@(additional_aidl_arguments)',
diff --git a/build/java_apk.gypi b/build/java_apk.gypi
index 0543156..976c90e 100644
--- a/build/java_apk.gypi
+++ b/build/java_apk.gypi
@@ -768,7 +768,7 @@
       'action': [
         'python', '<(DEPTH)/build/android/gyp/process_resources.py',
         '--android-sdk', '<(android_sdk)',
-        '--android-sdk-tools', '<(android_sdk_tools)',
+        '--aapt-path', '<(android_aapt_path)',
 
         '--android-manifest', '<(android_manifest_path)',
         '--dependencies-res-zips', '>(dependencies_res_zip_paths)',
diff --git a/build/linux/system.gyp b/build/linux/system.gyp
index 476476e..a1d6bf0 100644
--- a/build/linux/system.gyp
+++ b/build/linux/system.gyp
@@ -4,14 +4,6 @@
 
 {
   'variables': {
-    'conditions': [
-      ['sysroot!=""', {
-        'pkg-config': '<(chroot_cmd) ./pkg-config-wrapper "<(sysroot)" "<(target_arch)" "<(system_libdir)"',
-      }, {
-        'pkg-config': 'pkg-config',
-      }],
-    ],
-
     # If any of the linux_link_FOO below are set to 1, then the corresponding
     # target will be linked against the FOO library (either dynamically or
     # statically, depending on the pkg-config files), as opposed to loading the
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index ae839cc3..ace6075 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -141,9 +141,6 @@
 // http://crbug.com/285242
 "race:media::PulseAudioOutputStream::SetVolume\n"
 
-// http://crbug.com/296883
-"race:net::URLFetcherCore::Stop\n"
-
 // http://crbug.com/308590
 "race:CustomThreadWatcher::~CustomThreadWatcher\n"
 
@@ -288,9 +285,6 @@
 // http://crbug.com/490856
 "deadlock:content::TracingControllerImpl::SetEnabledOnFileThread\n"
 
-// http://crbug.com/425057
-"deadlock:webrtc::ViEChannelManagerScoped::ViEChannelManagerScoped\n"
-
 // http://crbug.com/417193
 // Suppressing both AudioContext.{cpp,h}.
 "race:modules/webaudio/AudioContext\n"
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 58540a9..22df7d0f 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -403,7 +403,6 @@
     "resources/priority_calculator.cc",
     "resources/priority_calculator.h",
     "resources/release_callback.h",
-    "resources/resource.cc",
     "resources/resource.h",
     "resources/resource_format.cc",
     "resources/resource_format.h",
@@ -532,6 +531,13 @@
     "trees/tree_synchronizer.h",
   ]
 
+  if (target_cpu == "x86" || target_cpu == "x64") {
+    sources += [
+      "raster/texture_compressor_etc1_sse.cc",
+      "raster/texture_compressor_etc1_sse.h",
+    ]
+  }
+
   # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
@@ -542,7 +548,6 @@
   deps = [
     "//base",
     "//base/third_party/dynamic_annotations",
-    "//cc:cc_opts",
     "//cc/surfaces:surface_id",
     "//gpu",
     "//gpu/command_buffer/client:gles2_interface",
@@ -560,36 +565,6 @@
   }
 }
 
-source_set("cc_opts") {
-  public_deps = [
-    "//cc:cc_opts_sse",
-  ]
-}
-
-source_set("cc_opts_sse") {
-  if (target_cpu == "x86" || target_cpu == "x64") {
-    deps = [
-      "//base",
-    ]
-
-    defines = [ "CC_IMPLEMENTATION=1" ]
-
-    if (!is_debug && (is_win || is_android)) {
-      configs -= [ "//build/config/compiler:optimize" ]
-      configs += [ "//build/config/compiler:optimize_max" ]
-    }
-
-    sources = [
-      "raster/texture_compressor.h",
-      "raster/texture_compressor_etc1.h",
-      "raster/texture_compressor_etc1_sse.cc",
-      "raster/texture_compressor_etc1_sse.h",
-    ]
-
-    cflags = [ "-msse2" ]
-  }
-}
-
 source_set("test_support") {
   testonly = true
   sources = [
@@ -772,6 +747,7 @@
     "animation/transform_operations_unittest.cc",
     "base/float_quad_unittest.cc",
     "base/histograms_unittest.cc",
+    "base/list_container_unittest.cc",
     "base/math_util_unittest.cc",
     "base/region_unittest.cc",
     "base/rolling_time_delta_history_unittest.cc",
@@ -837,7 +813,6 @@
     "playback/pixel_ref_map_unittest.cc",
     "playback/recording_source_unittest.cc",
     "quads/draw_quad_unittest.cc",
-    "quads/list_container_unittest.cc",
     "quads/render_pass_unittest.cc",
     "raster/scoped_gpu_raster_unittest.cc",
     "raster/task_graph_runner_unittest.cc",
diff --git a/cc/base/list_container.cc b/cc/base/list_container.cc
index df21a5b..ef4d08c 100644
--- a/cc/base/list_container.cc
+++ b/cc/base/list_container.cc
@@ -53,6 +53,7 @@
       --capacity;
     }
 
+    bool IsEmpty() const { return !size; }
     bool IsFull() { return capacity == size; }
     size_t NumElementsAvailable() const { return capacity - size; }
 
@@ -62,6 +63,11 @@
       return LastElement();
     }
 
+    void RemoveLast() {
+      DCHECK(!IsEmpty());
+      --size;
+    }
+
     char* Begin() const { return data.get(); }
     char* End() const { return data.get() + size * step; }
     char* LastElement() const { return data.get() + (size - 1) * step; }
@@ -74,32 +80,41 @@
   explicit ListContainerCharAllocator(size_t element_size)
       : element_size_(element_size),
         size_(0),
-        list_count_(0),
+        last_list_index_(0),
         last_list_(NULL) {
     AllocateNewList(kDefaultNumElementTypesToReserve);
+    last_list_ = storage_[last_list_index_];
   }
 
   ListContainerCharAllocator(size_t element_size, size_t element_count)
       : element_size_(element_size),
         size_(0),
-        list_count_(0),
+        last_list_index_(0),
         last_list_(NULL) {
     AllocateNewList(element_count > 0 ? element_count
                                       : kDefaultNumElementTypesToReserve);
+    last_list_ = storage_[last_list_index_];
   }
 
   ~ListContainerCharAllocator() {}
 
   void* Allocate() {
-    if (last_list_->IsFull())
-      AllocateNewList(last_list_->capacity * 2);
+    if (last_list_->IsFull()) {
+      // Only allocate a new list if there isn't a spare one still there from
+      // previous usage.
+      if (last_list_index_ + 1 >= storage_.size())
+        AllocateNewList(last_list_->capacity * 2);
+
+      ++last_list_index_;
+      last_list_ = storage_[last_list_index_];
+    }
 
     ++size_;
     return last_list_->AddElement();
   }
 
   size_t element_size() const { return element_size_; }
-  size_t list_count() const { return list_count_; }
+  size_t list_count() const { return storage_.size(); }
   size_t size() const { return size_; }
   bool IsEmpty() const { return size() == 0; }
 
@@ -115,10 +130,25 @@
   void Clear() {
     size_t initial_allocation_size = storage_.front()->capacity;
     storage_.clear();
-    list_count_ = 0;
     last_list_ = NULL;
+    last_list_index_ = 0;
     size_ = 0;
     AllocateNewList(initial_allocation_size);
+    last_list_ = storage_[last_list_index_];
+  }
+
+  void RemoveLast() {
+    DCHECK(!IsEmpty());
+    last_list_->RemoveLast();
+    if (last_list_->IsEmpty() && last_list_index_ > 0) {
+      --last_list_index_;
+      last_list_ = storage_[last_list_index_];
+
+      // If there are now two empty inner lists, free one of them.
+      if (last_list_index_ + 2 < storage_.size())
+        storage_.pop_back();
+    }
+    --size_;
   }
 
   void Erase(PositionInListContainerCharAllocator position) {
@@ -129,7 +159,7 @@
   }
 
   InnerList* InnerListById(size_t id) const {
-    DCHECK_LT(id, list_count_);
+    DCHECK_LT(id, storage_.size());
     return storage_[id];
   }
 
@@ -147,33 +177,37 @@
     // |size_| > 0 means that at least one vector in |storage_| will be
     // non-empty.
     DCHECK_GT(size_, 0u);
-    size_t id = list_count_ - 1;
+    size_t id = storage_.size() - 1;
     while (storage_[id]->size == 0)
       --id;
     return id;
   }
 
-  void AllocateNewList(size_t list_size) {
-    ++list_count_;
-    scoped_ptr<InnerList> new_list(new InnerList);
-    storage_.push_back(new_list.Pass());
-    last_list_ = storage_.back();
-    InnerList* list = last_list_;
-    list->capacity = list_size;
-    list->size = 0;
-    list->step = element_size_;
-    list->data.reset(new char[list->capacity * list->step]);
-  }
-
   size_t NumAvailableElementsInLastList() const {
     return last_list_->NumElementsAvailable();
   }
 
  private:
+  void AllocateNewList(size_t list_size) {
+    scoped_ptr<InnerList> new_list(new InnerList);
+    new_list->capacity = list_size;
+    new_list->size = 0;
+    new_list->step = element_size_;
+    new_list->data.reset(new char[list_size * element_size_]);
+    storage_.push_back(new_list.Pass());
+  }
+
   ScopedPtrVector<InnerList> storage_;
   const size_t element_size_;
+
+  // The number of elements in the list.
   size_t size_;
-  size_t list_count_;
+
+  // The index of the last list to have had elements added to it, or the only
+  // list if the container has not had elements added since being cleared.
+  size_t last_list_index_;
+
+  // This is equivalent to |storage_[last_list_index_]|.
   InnerList* last_list_;
 
   DISALLOW_COPY_AND_ASSIGN(ListContainerCharAllocator);
@@ -275,6 +309,10 @@
 ListContainerBase::~ListContainerBase() {
 }
 
+void ListContainerBase::RemoveLast() {
+  data_->RemoveLast();
+}
+
 void ListContainerBase::EraseAndInvalidateAllPointers(
     ListContainerBase::Iterator position) {
   data_->Erase(position);
diff --git a/cc/base/list_container.h b/cc/base/list_container.h
index 2ed69c2..0c3772b 100644
--- a/cc/base/list_container.h
+++ b/cc/base/list_container.h
@@ -5,6 +5,7 @@
 #ifndef CC_BASE_LIST_CONTAINER_H_
 #define CC_BASE_LIST_CONTAINER_H_
 
+#include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "cc/base/cc_export.h"
@@ -141,8 +142,8 @@
     size_t index_;
   };
 
-  // Unlike the ListContainer method, this one does not invoke element
-  // destructors.
+  // Unlike the ListContainer methods, these do not invoke element destructors.
+  void RemoveLast();
   void EraseAndInvalidateAllPointers(Iterator position);
 
   ConstReverseIterator crbegin() const;
@@ -209,6 +210,14 @@
   class ReverseIterator;
   class ConstReverseIterator;
 
+  // Removes the last element of the list and makes its space available for
+  // allocation.
+  void RemoveLast() {
+    DCHECK(!empty());
+    back()->~BaseElementType();
+    ListContainerBase::RemoveLast();
+  }
+
   // When called, all raw pointers that have been handed out are no longer
   // valid. Use with caution.
   // This function does not deallocate memory.
diff --git a/cc/base/list_container_unittest.cc b/cc/base/list_container_unittest.cc
new file mode 100644
index 0000000..cfe593b
--- /dev/null
+++ b/cc/base/list_container_unittest.cc
@@ -0,0 +1,712 @@
+// 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 "cc/base/list_container.h"
+
+#include <vector>
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+// Element class having derived classes.
+class DerivedElement {
+ public:
+  virtual ~DerivedElement() {}
+
+ protected:
+  bool bool_values[1];
+  char char_values[1];
+  int int_values[1];
+  long long_values[1];
+};
+
+class DerivedElement1 : public DerivedElement {
+ protected:
+  bool bool_values1[1];
+  char char_values1[1];
+  int int_values1[1];
+  long long_values1[1];
+};
+
+class DerivedElement2 : public DerivedElement {
+ protected:
+  bool bool_values2[2];
+  char char_values2[2];
+  int int_values2[2];
+  long long_values2[2];
+};
+
+class DerivedElement3 : public DerivedElement {
+ protected:
+  bool bool_values3[3];
+  char char_values3[3];
+  int int_values3[3];
+  long long_values3[3];
+};
+
+const size_t kLargestDerivedElementSize = sizeof(DerivedElement3);
+
+size_t LargestDerivedElementSize() {
+  static_assert(sizeof(DerivedElement1) <= kLargestDerivedElementSize,
+                "Largest Derived Element size needs update. DerivedElement1 is "
+                "currently largest.");
+  static_assert(sizeof(DerivedElement2) <= kLargestDerivedElementSize,
+                "Largest Derived Element size needs update. DerivedElement2 is "
+                "currently largest.");
+
+  return kLargestDerivedElementSize;
+}
+
+// Element class having no derived classes.
+class NonDerivedElement {
+ public:
+  NonDerivedElement() {}
+  ~NonDerivedElement() {}
+
+  int int_values[1];
+};
+
+bool isConstNonDerivedElementPointer(const NonDerivedElement* ptr) {
+  return true;
+}
+
+bool isConstNonDerivedElementPointer(NonDerivedElement* ptr) {
+  return false;
+}
+
+const int kMagicNumberToUseForSimpleDerivedElementOne = 42;
+const int kMagicNumberToUseForSimpleDerivedElementTwo = 314;
+
+class SimpleDerivedElement : public DerivedElement {
+ public:
+  ~SimpleDerivedElement() override {}
+  void set_value(int val) { value = val; }
+  int get_value() { return value; }
+
+ private:
+  int value;
+};
+
+class SimpleDerivedElementConstructMagicNumberOne
+    : public SimpleDerivedElement {
+ public:
+  SimpleDerivedElementConstructMagicNumberOne() : SimpleDerivedElement() {
+    set_value(kMagicNumberToUseForSimpleDerivedElementOne);
+  }
+};
+
+class SimpleDerivedElementConstructMagicNumberTwo
+    : public SimpleDerivedElement {
+ public:
+  SimpleDerivedElementConstructMagicNumberTwo() : SimpleDerivedElement() {
+    set_value(kMagicNumberToUseForSimpleDerivedElementTwo);
+  }
+};
+
+class MockDerivedElement : public SimpleDerivedElementConstructMagicNumberOne {
+ public:
+  ~MockDerivedElement() override { Destruct(); }
+  MOCK_METHOD0(Destruct, void());
+};
+
+class MockDerivedElementSubclass : public MockDerivedElement {
+ public:
+  MockDerivedElementSubclass() {
+    set_value(kMagicNumberToUseForSimpleDerivedElementTwo);
+  }
+};
+
+const size_t kCurrentLargestDerivedElementSize =
+    std::max(LargestDerivedElementSize(), sizeof(MockDerivedElementSubclass));
+
+TEST(ListContainerTest, ConstructorCalledInAllocateAndConstruct) {
+  ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+
+  size_t size = 2;
+  SimpleDerivedElementConstructMagicNumberOne* de_1 =
+      list.AllocateAndConstruct<SimpleDerivedElementConstructMagicNumberOne>();
+  SimpleDerivedElementConstructMagicNumberTwo* de_2 =
+      list.AllocateAndConstruct<SimpleDerivedElementConstructMagicNumberTwo>();
+
+  EXPECT_EQ(size, list.size());
+  EXPECT_EQ(de_1, list.front());
+  EXPECT_EQ(de_2, list.back());
+
+  EXPECT_EQ(kMagicNumberToUseForSimpleDerivedElementOne, de_1->get_value());
+  EXPECT_EQ(kMagicNumberToUseForSimpleDerivedElementTwo, de_2->get_value());
+}
+
+TEST(ListContainerTest, DestructorCalled) {
+  ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+
+  size_t size = 1;
+  MockDerivedElement* de_1 = list.AllocateAndConstruct<MockDerivedElement>();
+
+  EXPECT_CALL(*de_1, Destruct());
+  EXPECT_EQ(size, list.size());
+  EXPECT_EQ(de_1, list.front());
+}
+
+TEST(ListContainerTest, DestructorCalledOnceWhenClear) {
+  ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+  size_t size = 1;
+  MockDerivedElement* de_1 = list.AllocateAndConstruct<MockDerivedElement>();
+
+  EXPECT_EQ(size, list.size());
+  EXPECT_EQ(de_1, list.front());
+
+  // Make sure destructor is called once during clear, and won't be called
+  // again.
+  testing::MockFunction<void()> separator;
+  {
+    testing::InSequence s;
+    EXPECT_CALL(*de_1, Destruct());
+    EXPECT_CALL(separator, Call());
+    EXPECT_CALL(*de_1, Destruct()).Times(0);
+  }
+
+  list.clear();
+  separator.Call();
+}
+
+TEST(ListContainerTest, ReplaceExistingElement) {
+  ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+  size_t size = 1;
+  MockDerivedElement* de_1 = list.AllocateAndConstruct<MockDerivedElement>();
+
+  EXPECT_EQ(size, list.size());
+  EXPECT_EQ(de_1, list.front());
+
+  // Make sure destructor is called once during clear, and won't be called
+  // again.
+  testing::MockFunction<void()> separator;
+  {
+    testing::InSequence s;
+    EXPECT_CALL(*de_1, Destruct());
+    EXPECT_CALL(separator, Call());
+    EXPECT_CALL(*de_1, Destruct()).Times(0);
+  }
+
+  list.ReplaceExistingElement<MockDerivedElementSubclass>(list.begin());
+  EXPECT_EQ(kMagicNumberToUseForSimpleDerivedElementTwo, de_1->get_value());
+  separator.Call();
+
+  EXPECT_CALL(*de_1, Destruct());
+  list.clear();
+}
+
+TEST(ListContainerTest, DestructorCalledOnceWhenErase) {
+  ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+  size_t size = 1;
+  MockDerivedElement* de_1 = list.AllocateAndConstruct<MockDerivedElement>();
+
+  EXPECT_EQ(size, list.size());
+  EXPECT_EQ(de_1, list.front());
+
+  // Make sure destructor is called once during clear, and won't be called
+  // again.
+  testing::MockFunction<void()> separator;
+  {
+    testing::InSequence s;
+    EXPECT_CALL(*de_1, Destruct());
+    EXPECT_CALL(separator, Call());
+    EXPECT_CALL(*de_1, Destruct()).Times(0);
+  }
+
+  list.EraseAndInvalidateAllPointers(list.begin());
+  separator.Call();
+}
+
+TEST(ListContainerTest, SimpleIndexAccessNonDerivedElement) {
+  ListContainer<NonDerivedElement> list;
+
+  size_t size = 3;
+  NonDerivedElement* nde_1 = list.AllocateAndConstruct<NonDerivedElement>();
+  NonDerivedElement* nde_2 = list.AllocateAndConstruct<NonDerivedElement>();
+  NonDerivedElement* nde_3 = list.AllocateAndConstruct<NonDerivedElement>();
+
+  EXPECT_EQ(size, list.size());
+  EXPECT_EQ(nde_1, list.front());
+  EXPECT_EQ(nde_3, list.back());
+  EXPECT_EQ(list.front(), list.ElementAt(0));
+  EXPECT_EQ(nde_2, list.ElementAt(1));
+  EXPECT_EQ(list.back(), list.ElementAt(2));
+}
+
+TEST(ListContainerTest, SimpleInsertionNonDerivedElement) {
+  ListContainer<NonDerivedElement> list;
+
+  size_t size = 3;
+  NonDerivedElement* nde_1 = list.AllocateAndConstruct<NonDerivedElement>();
+  list.AllocateAndConstruct<NonDerivedElement>();
+  NonDerivedElement* nde_3 = list.AllocateAndConstruct<NonDerivedElement>();
+
+  EXPECT_EQ(size, list.size());
+  EXPECT_EQ(nde_1, list.front());
+  EXPECT_EQ(nde_3, list.back());
+}
+
+TEST(ListContainerTest, SimpleInsertionAndClearNonDerivedElement) {
+  ListContainer<NonDerivedElement> list;
+  EXPECT_TRUE(list.empty());
+  EXPECT_EQ(0u, list.size());
+
+  size_t size = 3;
+  NonDerivedElement* nde_1 = list.AllocateAndConstruct<NonDerivedElement>();
+  list.AllocateAndConstruct<NonDerivedElement>();
+  NonDerivedElement* nde_3 = list.AllocateAndConstruct<NonDerivedElement>();
+
+  EXPECT_EQ(size, list.size());
+  EXPECT_EQ(nde_1, list.front());
+  EXPECT_EQ(nde_3, list.back());
+  EXPECT_FALSE(list.empty());
+
+  list.clear();
+  EXPECT_TRUE(list.empty());
+  EXPECT_EQ(0u, list.size());
+}
+
+TEST(ListContainerTest, SimpleInsertionClearAndInsertAgainNonDerivedElement) {
+  ListContainer<NonDerivedElement> list;
+  EXPECT_TRUE(list.empty());
+  EXPECT_EQ(0u, list.size());
+
+  size_t size = 2;
+  NonDerivedElement* nde_front = list.AllocateAndConstruct<NonDerivedElement>();
+  NonDerivedElement* nde_back = list.AllocateAndConstruct<NonDerivedElement>();
+
+  EXPECT_EQ(size, list.size());
+  EXPECT_EQ(nde_front, list.front());
+  EXPECT_EQ(nde_back, list.back());
+  EXPECT_FALSE(list.empty());
+
+  list.clear();
+  EXPECT_TRUE(list.empty());
+  EXPECT_EQ(0u, list.size());
+
+  size = 3;
+  nde_front = list.AllocateAndConstruct<NonDerivedElement>();
+  list.AllocateAndConstruct<NonDerivedElement>();
+  nde_back = list.AllocateAndConstruct<NonDerivedElement>();
+
+  EXPECT_EQ(size, list.size());
+  EXPECT_EQ(nde_front, list.front());
+  EXPECT_EQ(nde_back, list.back());
+  EXPECT_FALSE(list.empty());
+}
+
+// This test is used to test when there is more than one allocation needed
+// for, ListContainer can still perform like normal vector.
+TEST(ListContainerTest,
+     SimpleInsertionTriggerMoreThanOneAllocationNonDerivedElement) {
+  ListContainer<NonDerivedElement> list(sizeof(NonDerivedElement), 2);
+  std::vector<NonDerivedElement*> nde_list;
+  size_t size = 10;
+  for (size_t i = 0; i < size; ++i) {
+    nde_list.push_back(list.AllocateAndConstruct<NonDerivedElement>());
+  }
+  EXPECT_EQ(size, list.size());
+
+  ListContainer<NonDerivedElement>::Iterator iter = list.begin();
+  for (std::vector<NonDerivedElement*>::const_iterator nde_iter =
+           nde_list.begin();
+       nde_iter != nde_list.end(); ++nde_iter) {
+    EXPECT_EQ(*nde_iter, *iter);
+    ++iter;
+  }
+}
+
+TEST(ListContainerTest,
+     CorrectAllocationSizeForMoreThanOneAllocationNonDerivedElement) {
+  // Constructor sets the allocation size to 2. Every time ListContainer needs
+  // to allocate again, it doubles allocation size. In this test, 10 elements is
+  // needed, thus ListContainerShould allocate spaces 2, 4 and 8 elements.
+  ListContainer<NonDerivedElement> list(sizeof(NonDerivedElement), 2);
+  std::vector<NonDerivedElement*> nde_list;
+  size_t size = 10;
+  for (size_t i = 0; i < size; ++i) {
+    // Before asking for a new element, space available without another
+    // allocation follows.
+    switch (i) {
+      case 2:
+      case 6:
+        EXPECT_EQ(0u, list.AvailableSizeWithoutAnotherAllocationForTesting());
+        break;
+      case 1:
+      case 5:
+        EXPECT_EQ(1u, list.AvailableSizeWithoutAnotherAllocationForTesting());
+        break;
+      case 0:
+      case 4:
+        EXPECT_EQ(2u, list.AvailableSizeWithoutAnotherAllocationForTesting());
+        break;
+      case 3:
+        EXPECT_EQ(3u, list.AvailableSizeWithoutAnotherAllocationForTesting());
+        break;
+      case 9:
+        EXPECT_EQ(5u, list.AvailableSizeWithoutAnotherAllocationForTesting());
+        break;
+      case 8:
+        EXPECT_EQ(6u, list.AvailableSizeWithoutAnotherAllocationForTesting());
+        break;
+      case 7:
+        EXPECT_EQ(7u, list.AvailableSizeWithoutAnotherAllocationForTesting());
+        break;
+      default:
+        break;
+    }
+    nde_list.push_back(list.AllocateAndConstruct<NonDerivedElement>());
+    // After asking for a new element, space available without another
+    // allocation follows.
+    switch (i) {
+      case 1:
+      case 5:
+        EXPECT_EQ(0u, list.AvailableSizeWithoutAnotherAllocationForTesting());
+        break;
+      case 0:
+      case 4:
+        EXPECT_EQ(1u, list.AvailableSizeWithoutAnotherAllocationForTesting());
+        break;
+      case 3:
+        EXPECT_EQ(2u, list.AvailableSizeWithoutAnotherAllocationForTesting());
+        break;
+      case 2:
+        EXPECT_EQ(3u, list.AvailableSizeWithoutAnotherAllocationForTesting());
+        break;
+      case 9:
+        EXPECT_EQ(4u, list.AvailableSizeWithoutAnotherAllocationForTesting());
+        break;
+      case 8:
+        EXPECT_EQ(5u, list.AvailableSizeWithoutAnotherAllocationForTesting());
+        break;
+      case 7:
+        EXPECT_EQ(6u, list.AvailableSizeWithoutAnotherAllocationForTesting());
+        break;
+      case 6:
+        EXPECT_EQ(7u, list.AvailableSizeWithoutAnotherAllocationForTesting());
+        break;
+      default:
+        break;
+    }
+  }
+  EXPECT_EQ(size, list.size());
+
+  ListContainer<NonDerivedElement>::Iterator iter = list.begin();
+  for (std::vector<NonDerivedElement*>::const_iterator nde_iter =
+           nde_list.begin();
+       nde_iter != nde_list.end(); ++nde_iter) {
+    EXPECT_EQ(*nde_iter, *iter);
+    ++iter;
+  }
+}
+
+TEST(ListContainerTest, SimpleIterationNonDerivedElement) {
+  ListContainer<NonDerivedElement> list;
+  std::vector<NonDerivedElement*> nde_list;
+  size_t size = 10;
+  for (size_t i = 0; i < size; ++i) {
+    nde_list.push_back(list.AllocateAndConstruct<NonDerivedElement>());
+  }
+  EXPECT_EQ(size, list.size());
+
+  size_t num_iters_in_list = 0;
+  {
+    std::vector<NonDerivedElement*>::const_iterator nde_iter = nde_list.begin();
+    for (ListContainer<NonDerivedElement>::Iterator iter = list.begin();
+         iter != list.end(); ++iter) {
+      EXPECT_EQ(*nde_iter, *iter);
+      ++num_iters_in_list;
+      ++nde_iter;
+    }
+  }
+
+  size_t num_iters_in_vector = 0;
+  {
+    ListContainer<NonDerivedElement>::Iterator iter = list.begin();
+    for (std::vector<NonDerivedElement*>::const_iterator nde_iter =
+             nde_list.begin();
+         nde_iter != nde_list.end(); ++nde_iter) {
+      EXPECT_EQ(*nde_iter, *iter);
+      ++num_iters_in_vector;
+      ++iter;
+    }
+  }
+
+  EXPECT_EQ(num_iters_in_vector, num_iters_in_list);
+}
+
+TEST(ListContainerTest, SimpleConstIteratorIterationNonDerivedElement) {
+  ListContainer<NonDerivedElement> list;
+  std::vector<const NonDerivedElement*> nde_list;
+  size_t size = 10;
+  for (size_t i = 0; i < size; ++i) {
+    nde_list.push_back(list.AllocateAndConstruct<NonDerivedElement>());
+  }
+  EXPECT_EQ(size, list.size());
+
+  {
+    std::vector<const NonDerivedElement*>::const_iterator nde_iter =
+        nde_list.begin();
+    for (ListContainer<NonDerivedElement>::ConstIterator iter = list.begin();
+         iter != list.end(); ++iter) {
+      EXPECT_TRUE(isConstNonDerivedElementPointer(*iter));
+      EXPECT_EQ(*nde_iter, *iter);
+      ++nde_iter;
+    }
+  }
+
+  {
+    std::vector<const NonDerivedElement*>::const_iterator nde_iter =
+        nde_list.begin();
+    for (ListContainer<NonDerivedElement>::Iterator iter = list.begin();
+         iter != list.end(); ++iter) {
+      EXPECT_FALSE(isConstNonDerivedElementPointer(*iter));
+      EXPECT_EQ(*nde_iter, *iter);
+      ++nde_iter;
+    }
+  }
+
+  {
+    ListContainer<NonDerivedElement>::ConstIterator iter = list.begin();
+    for (std::vector<const NonDerivedElement*>::const_iterator nde_iter =
+             nde_list.begin();
+         nde_iter != nde_list.end(); ++nde_iter) {
+      EXPECT_EQ(*nde_iter, *iter);
+      ++iter;
+    }
+  }
+}
+
+TEST(ListContainerTest, SimpleReverseInsertionNonDerivedElement) {
+  ListContainer<NonDerivedElement> list;
+  std::vector<NonDerivedElement*> nde_list;
+  size_t size = 10;
+  for (size_t i = 0; i < size; ++i) {
+    nde_list.push_back(list.AllocateAndConstruct<NonDerivedElement>());
+  }
+  EXPECT_EQ(size, list.size());
+
+  {
+    std::vector<NonDerivedElement*>::const_reverse_iterator nde_iter =
+        nde_list.rbegin();
+    for (ListContainer<NonDerivedElement>::ReverseIterator iter = list.rbegin();
+         iter != list.rend(); ++iter) {
+      EXPECT_EQ(*nde_iter, *iter);
+      ++nde_iter;
+    }
+  }
+
+  {
+    ListContainer<NonDerivedElement>::ReverseIterator iter = list.rbegin();
+    for (std::vector<NonDerivedElement*>::reverse_iterator nde_iter =
+             nde_list.rbegin();
+         nde_iter != nde_list.rend(); ++nde_iter) {
+      EXPECT_EQ(*nde_iter, *iter);
+      ++iter;
+    }
+  }
+}
+
+TEST(ListContainerTest, SimpleDeletion) {
+  ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+  std::vector<SimpleDerivedElement*> sde_list;
+  size_t size = 10;
+  for (size_t i = 0; i < size; ++i) {
+    sde_list.push_back(list.AllocateAndConstruct<SimpleDerivedElement>());
+    sde_list.back()->set_value(i);
+  }
+  EXPECT_EQ(size, list.size());
+
+  list.EraseAndInvalidateAllPointers(list.begin());
+  --size;
+  EXPECT_EQ(size, list.size());
+  int i = 1;
+  for (ListContainer<DerivedElement>::Iterator iter = list.begin();
+       iter != list.end(); ++iter) {
+    EXPECT_EQ(i, static_cast<SimpleDerivedElement*>(*iter)->get_value());
+    ++i;
+  }
+}
+
+TEST(ListContainerTest, DeletionAllInAllocation) {
+  const size_t kReserve = 10;
+  ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize,
+                                     kReserve);
+  std::vector<SimpleDerivedElement*> sde_list;
+  // Add enough elements to cause another allocation.
+  for (size_t i = 0; i < kReserve + 1; ++i) {
+    sde_list.push_back(list.AllocateAndConstruct<SimpleDerivedElement>());
+    sde_list.back()->set_value(static_cast<int>(i));
+  }
+  EXPECT_EQ(kReserve + 1, list.size());
+
+  // Remove everything in the first allocation.
+  for (size_t i = 0; i < kReserve; ++i)
+    list.EraseAndInvalidateAllPointers(list.begin());
+  EXPECT_EQ(1u, list.size());
+
+  // The last element is left.
+  SimpleDerivedElement* de = static_cast<SimpleDerivedElement*>(*list.begin());
+  EXPECT_EQ(static_cast<int>(kReserve), de->get_value());
+
+  // Remove the element from the 2nd allocation.
+  list.EraseAndInvalidateAllPointers(list.begin());
+  EXPECT_EQ(0u, list.size());
+}
+
+TEST(ListContainerTest, DeletionAllInAllocationReversed) {
+  const size_t kReserve = 10;
+  ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize,
+                                     kReserve);
+  std::vector<SimpleDerivedElement*> sde_list;
+  // Add enough elements to cause another allocation.
+  for (size_t i = 0; i < kReserve + 1; ++i) {
+    sde_list.push_back(list.AllocateAndConstruct<SimpleDerivedElement>());
+    sde_list.back()->set_value(static_cast<int>(i));
+  }
+  EXPECT_EQ(kReserve + 1, list.size());
+
+  // Remove everything in the 2nd allocation.
+  auto it = list.begin();
+  for (size_t i = 0; i < kReserve; ++i)
+    ++it;
+  list.EraseAndInvalidateAllPointers(it);
+
+  // The 2nd-last element is next, and the rest of the elements exist.
+  size_t i = kReserve - 1;
+  for (auto it = list.rbegin(); it != list.rend(); ++it) {
+    SimpleDerivedElement* de = static_cast<SimpleDerivedElement*>(*it);
+    EXPECT_EQ(static_cast<int>(i), de->get_value());
+    --i;
+  }
+
+  // Can forward iterate too.
+  i = 0;
+  for (auto it = list.begin(); it != list.end(); ++it) {
+    SimpleDerivedElement* de = static_cast<SimpleDerivedElement*>(*it);
+    EXPECT_EQ(static_cast<int>(i), de->get_value());
+    ++i;
+  }
+
+  // Remove the last thing from the 1st allocation.
+  it = list.begin();
+  for (size_t i = 0; i < kReserve - 1; ++i)
+    ++it;
+  list.EraseAndInvalidateAllPointers(it);
+
+  // The 2nd-last element is next, and the rest of the elements exist.
+  i = kReserve - 2;
+  for (auto it = list.rbegin(); it != list.rend(); ++it) {
+    SimpleDerivedElement* de = static_cast<SimpleDerivedElement*>(*it);
+    EXPECT_EQ(static_cast<int>(i), de->get_value());
+    --i;
+  }
+
+  // Can forward iterate too.
+  i = 0;
+  for (auto it = list.begin(); it != list.end(); ++it) {
+    SimpleDerivedElement* de = static_cast<SimpleDerivedElement*>(*it);
+    EXPECT_EQ(static_cast<int>(i), de->get_value());
+    ++i;
+  }
+}
+
+TEST(ListContainerTest, SimpleIterationAndManipulation) {
+  ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+  std::vector<SimpleDerivedElement*> sde_list;
+  size_t size = 10;
+  for (size_t i = 0; i < size; ++i) {
+    SimpleDerivedElement* simple_dq =
+        list.AllocateAndConstruct<SimpleDerivedElement>();
+    sde_list.push_back(simple_dq);
+  }
+  EXPECT_EQ(size, list.size());
+
+  ListContainer<DerivedElement>::Iterator iter = list.begin();
+  for (int i = 0; i < 10; ++i) {
+    static_cast<SimpleDerivedElement*>(*iter)->set_value(i);
+    ++iter;
+  }
+
+  int i = 0;
+  for (std::vector<SimpleDerivedElement*>::const_iterator sde_iter =
+           sde_list.begin();
+       sde_iter < sde_list.end(); ++sde_iter) {
+    EXPECT_EQ(i, (*sde_iter)->get_value());
+    ++i;
+  }
+}
+
+TEST(ListContainerTest, SimpleManipulationWithIndexSimpleDerivedElement) {
+  ListContainer<DerivedElement> list(kCurrentLargestDerivedElementSize);
+  std::vector<SimpleDerivedElement*> de_list;
+  size_t size = 10;
+  for (size_t i = 0; i < size; ++i) {
+    de_list.push_back(list.AllocateAndConstruct<SimpleDerivedElement>());
+  }
+  EXPECT_EQ(size, list.size());
+
+  for (size_t i = 0; i < size; ++i) {
+    static_cast<SimpleDerivedElement*>(list.ElementAt(i))->set_value(i);
+  }
+
+  int i = 0;
+  for (std::vector<SimpleDerivedElement*>::const_iterator
+           de_iter = de_list.begin();
+       de_iter != de_list.end(); ++de_iter, ++i) {
+    EXPECT_EQ(i, (*de_iter)->get_value());
+  }
+}
+
+TEST(ListContainerTest,
+     SimpleManipulationWithIndexMoreThanOneAllocationSimpleDerivedElement) {
+  ListContainer<DerivedElement> list(LargestDerivedElementSize(), 2);
+  std::vector<SimpleDerivedElement*> de_list;
+  size_t size = 10;
+  for (size_t i = 0; i < size; ++i) {
+    de_list.push_back(list.AllocateAndConstruct<SimpleDerivedElement>());
+  }
+  EXPECT_EQ(size, list.size());
+
+  for (size_t i = 0; i < size; ++i) {
+    static_cast<SimpleDerivedElement*>(list.ElementAt(i))->set_value(i);
+  }
+
+  int i = 0;
+  for (std::vector<SimpleDerivedElement*>::const_iterator
+           de_iter = de_list.begin();
+       de_iter != de_list.end(); ++de_iter, ++i) {
+    EXPECT_EQ(i, (*de_iter)->get_value());
+  }
+}
+
+TEST(ListContainerTest,
+     SimpleIterationAndReverseIterationWithIndexNonDerivedElement) {
+  ListContainer<NonDerivedElement> list;
+  std::vector<NonDerivedElement*> nde_list;
+  size_t size = 10;
+  for (size_t i = 0; i < size; ++i) {
+    nde_list.push_back(list.AllocateAndConstruct<NonDerivedElement>());
+  }
+  EXPECT_EQ(size, list.size());
+
+  size_t i = 0;
+  for (ListContainer<NonDerivedElement>::Iterator iter = list.begin();
+       iter != list.end(); ++iter) {
+    EXPECT_EQ(i, iter.index());
+    ++i;
+  }
+
+  i = 0;
+  for (ListContainer<NonDerivedElement>::ReverseIterator iter = list.rbegin();
+       iter != list.rend(); ++iter) {
+    EXPECT_EQ(i, iter.index());
+    ++i;
+  }
+}
+
+}  // namespace
+}  // namespace cc
diff --git a/cc/base/sidecar_list_container.h b/cc/base/sidecar_list_container.h
index 52deaf4..842795fa 100644
--- a/cc/base/sidecar_list_container.h
+++ b/cc/base/sidecar_list_container.h
@@ -29,6 +29,10 @@
   using SidecarDestroyer = void (*)(void* sidecar);
   using Iterator = typename ListContainer<BaseElementType>::Iterator;
   using ConstIterator = typename ListContainer<BaseElementType>::ConstIterator;
+  using ReverseIterator =
+      typename ListContainer<BaseElementType>::ReverseIterator;
+  using ConstReverseIterator =
+      typename ListContainer<BaseElementType>::ConstReverseIterator;
 
   explicit SidecarListContainer(size_t max_size_for_derived_class,
                                 size_t max_size_for_sidecar,
@@ -60,6 +64,11 @@
     list_.clear();
   }
 
+  void RemoveLast() {
+    destroyer_(GetSidecar(*list_.rbegin()));
+    list_.RemoveLast();
+  }
+
   // This permits a client to exchange a pointer to an element to a pointer to
   // its corresponding sidecar.
   void* GetSidecar(BaseElementType* element) {
diff --git a/cc/base/sidecar_list_container_unittest.cc b/cc/base/sidecar_list_container_unittest.cc
index d8fc9ef..0012014 100644
--- a/cc/base/sidecar_list_container_unittest.cc
+++ b/cc/base/sidecar_list_container_unittest.cc
@@ -182,5 +182,17 @@
   EXPECT_EQ(container.end(), container.begin());
 }
 
+TEST(SidecarListContainerTest, RemoveLast) {
+  // We need only ensure that the sidecar is also destroyed on RemoveLast.
+  // The rest is logic already present in ListContainer.
+  bool sidecar_destroyed = false;
+  TestContainer container;
+  TestElement* element = container.AllocateAndConstruct<TestElement>();
+  new (container.GetSidecar(element)) TestSidecar(&sidecar_destroyed);
+  ASSERT_FALSE(sidecar_destroyed);
+  container.RemoveLast();
+  ASSERT_TRUE(sidecar_destroyed);
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/cc.gyp b/cc/cc.gyp
index e374c47..bd2ae27 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -20,7 +20,6 @@
         '<(DEPTH)/ui/events/events.gyp:events_base',
         '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
         '<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry',
-        'cc_opts',
       ],
       'variables': {
         'optimize': 'max',
@@ -461,7 +460,6 @@
         'resources/priority_calculator.cc',
         'resources/priority_calculator.h',
         'resources/release_callback.h',
-        'resources/resource.cc',
         'resources/resource.h',
         'resources/resource_format.cc',
         'resources/resource_format.h',
@@ -594,6 +592,14 @@
       ],
       # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
       'msvs_disabled_warnings': [ 4267, ],
+      'conditions': [
+        ['target_arch == "ia32" or target_arch == "x64"', {
+          'sources': [
+            'raster/texture_compressor_etc1_sse.cc',
+            'raster/texture_compressor_etc1_sse.h',
+          ],
+        }],
+      ],
     },
     {
       # GN version: //cc/surfaces
@@ -643,41 +649,5 @@
         '../build/android/increase_size_for_speed.gypi',
       ],
     },
-    {
-      'target_name': 'cc_opts',
-      'type': 'static_library',
-      'conditions': [
-        ['target_arch == "ia32" or target_arch == "x64"', {
-          'defines': [
-            'CC_IMPLEMENTATION=1',
-          ],
-          'dependencies': [
-            'cc_opts_sse',
-          ]          
-        }],
-      ],  
-    },    
-    {
-      'target_name': 'cc_opts_sse',
-      'type': 'static_library',
-      'dependencies': [
-        '<(DEPTH)/base/base.gyp:base',
-      ],
-      'conditions': [
-        ['target_arch == "ia32" or target_arch == "x64"', {
-          'defines': [
-            'CC_IMPLEMENTATION=1',
-          ],
-          'sources': [
-            # Conditional compilation for SSE2 code on x86 and x64 machines
-            'raster/texture_compressor_etc1_sse.cc',
-            'raster/texture_compressor_etc1_sse.h',
-          ],
-          'cflags': [
-            '-msse2',
-          ],
-        }],
-      ],
-    },    
   ],
 }
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 98997ce..c1e456a7 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -16,6 +16,7 @@
       'base/delayed_unique_notifier_unittest.cc',
       'base/float_quad_unittest.cc',
       'base/histograms_unittest.cc',
+      'base/list_container_unittest.cc',
       'base/math_util_unittest.cc',
       'base/region_unittest.cc',
       'base/rolling_time_delta_history_unittest.cc',
@@ -85,7 +86,6 @@
       'playback/recording_source_unittest.cc',
       'quads/draw_polygon_unittest.cc',
       'quads/draw_quad_unittest.cc',
-      'quads/list_container_unittest.cc',
       'quads/render_pass_unittest.cc',
       'raster/scoped_gpu_raster_unittest.cc',
       'raster/task_graph_runner_unittest.cc',
diff --git a/cc/debug/frame_timing_tracker.cc b/cc/debug/frame_timing_tracker.cc
index 50aa92b..38977ee6 100644
--- a/cc/debug/frame_timing_tracker.cc
+++ b/cc/debug/frame_timing_tracker.cc
@@ -8,9 +8,13 @@
 #include <limits>
 
 #include "base/metrics/histogram.h"
+#include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/proxy.h"
 
 namespace cc {
+namespace {
+int kSendTimingIntervalMS = 200;
+}
 
 FrameTimingTracker::CompositeTimingEvent::CompositeTimingEvent(
     int _frame_id,
@@ -32,11 +36,19 @@
 }
 
 // static
-scoped_ptr<FrameTimingTracker> FrameTimingTracker::Create() {
-  return make_scoped_ptr(new FrameTimingTracker);
+scoped_ptr<FrameTimingTracker> FrameTimingTracker::Create(
+    LayerTreeHostImpl* layer_tree_host_impl) {
+  return make_scoped_ptr(new FrameTimingTracker(layer_tree_host_impl));
 }
 
-FrameTimingTracker::FrameTimingTracker() {
+FrameTimingTracker::FrameTimingTracker(LayerTreeHostImpl* layer_tree_host_impl)
+    : layer_tree_host_impl_(layer_tree_host_impl),
+      post_events_notifier_(
+          layer_tree_host_impl_->proxy()->HasImplThread()
+              ? layer_tree_host_impl_->proxy()->ImplThreadTaskRunner()
+              : layer_tree_host_impl_->proxy()->MainThreadTaskRunner(),
+          base::Bind(&FrameTimingTracker::PostEvents, base::Unretained(this)),
+          base::TimeDelta::FromMilliseconds(kSendTimingIntervalMS)) {
 }
 
 FrameTimingTracker::~FrameTimingTracker() {
@@ -51,6 +63,8 @@
     (*composite_events_)[pair.second].push_back(
         CompositeTimingEvent(pair.first, timestamp));
   }
+  if (!post_events_notifier_.HasPendingNotification())
+    post_events_notifier_.Schedule();
 }
 
 void FrameTimingTracker::SaveMainFrameTimeStamps(
@@ -65,6 +79,8 @@
     events.push_back(
         MainFrameTimingEvent(source_frame_number, main_frame_time, end_time));
   }
+  if (!post_events_notifier_.HasPendingNotification())
+    post_events_notifier_.Schedule();
 }
 
 scoped_ptr<FrameTimingTracker::CompositeTimingSet>
@@ -95,4 +111,9 @@
   return main_frame_events_.Pass();
 }
 
+void FrameTimingTracker::PostEvents() {
+  layer_tree_host_impl_->PostFrameTimingEvents(GroupCompositeCountsByRectId(),
+                                               GroupMainFrameCountsByRectId());
+}
+
 }  // namespace cc
diff --git a/cc/debug/frame_timing_tracker.h b/cc/debug/frame_timing_tracker.h
index 33649931..7b638d7 100644
--- a/cc/debug/frame_timing_tracker.h
+++ b/cc/debug/frame_timing_tracker.h
@@ -13,9 +13,12 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/time/time.h"
 #include "cc/base/cc_export.h"
+#include "cc/base/delayed_unique_notifier.h"
 
 namespace cc {
 
+class LayerTreeHostImpl;
+
 // This class maintains a history of timestamps and rect IDs to communicate
 // frame events back to Blink
 // TODO(mpb): Start using this. crbug.com/442554
@@ -30,7 +33,7 @@
   };
 
   using CompositeTimingSet =
-      base::hash_map<int, std::vector<CompositeTimingEvent>>;
+      base::hash_map<int64_t, std::vector<CompositeTimingEvent>>;
 
   struct CC_EXPORT MainFrameTimingEvent {
     MainFrameTimingEvent(int frame_id,
@@ -44,9 +47,10 @@
   };
 
   using MainFrameTimingSet =
-      base::hash_map<int, std::vector<MainFrameTimingEvent>>;
+      base::hash_map<int64_t, std::vector<MainFrameTimingEvent>>;
 
-  static scoped_ptr<FrameTimingTracker> Create();
+  static scoped_ptr<FrameTimingTracker> Create(
+      LayerTreeHostImpl* layer_tree_host_impl);
 
   ~FrameTimingTracker();
 
@@ -74,11 +78,16 @@
                                int source_frame_number);
 
  private:
-  FrameTimingTracker();
+  explicit FrameTimingTracker(LayerTreeHostImpl* layer_tree_host_impl);
+
+  void PostEvents();
 
   scoped_ptr<CompositeTimingSet> composite_events_;
   scoped_ptr<MainFrameTimingSet> main_frame_events_;
 
+  LayerTreeHostImpl* layer_tree_host_impl_;
+  DelayedUniqueNotifier post_events_notifier_;
+
   DISALLOW_COPY_AND_ASSIGN(FrameTimingTracker);
 };
 
diff --git a/cc/debug/frame_timing_tracker_unittest.cc b/cc/debug/frame_timing_tracker_unittest.cc
index b5574435..2b5f941c 100644
--- a/cc/debug/frame_timing_tracker_unittest.cc
+++ b/cc/debug/frame_timing_tracker_unittest.cc
@@ -9,6 +9,9 @@
 #include "base/trace_event/trace_event_argument.h"
 #include "base/values.h"
 #include "cc/debug/frame_timing_tracker.h"
+#include "cc/test/fake_impl_proxy.h"
+#include "cc/test/fake_layer_tree_host_impl.h"
+#include "cc/test/test_shared_bitmap_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cc {
@@ -70,7 +73,12 @@
 }
 
 TEST(FrameTimingTrackerTest, DefaultTrackerIsEmpty) {
-  scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+  FakeImplProxy proxy;
+  TestSharedBitmapManager shared_bitmap_manager;
+  FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
+
+  scoped_ptr<FrameTimingTracker> tracker(
+      FrameTimingTracker::Create(&host_impl));
   EXPECT_EQ("{\"values\":[]}",
             CompositeToString(tracker->GroupCompositeCountsByRectId()));
   EXPECT_EQ("{\"values\":[]}",
@@ -78,7 +86,12 @@
 }
 
 TEST(FrameTimingTrackerTest, NoFrameIdsIsEmpty) {
-  scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+  FakeImplProxy proxy;
+  TestSharedBitmapManager shared_bitmap_manager;
+  FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
+
+  scoped_ptr<FrameTimingTracker> tracker(
+      FrameTimingTracker::Create(&host_impl));
   std::vector<std::pair<int, int64_t>> ids;
   tracker->SaveTimeStamps(base::TimeTicks::FromInternalValue(100), ids);
   EXPECT_EQ("{\"values\":[]}",
@@ -86,7 +99,12 @@
 }
 
 TEST(FrameTimingTrackerTest, NoRectIdsYieldsNoMainFrameEvents) {
-  scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+  FakeImplProxy proxy;
+  TestSharedBitmapManager shared_bitmap_manager;
+  FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
+
+  scoped_ptr<FrameTimingTracker> tracker(
+      FrameTimingTracker::Create(&host_impl));
   tracker->SaveMainFrameTimeStamps(std::vector<int64_t>(),
                                    base::TimeTicks::FromInternalValue(100),
                                    base::TimeTicks::FromInternalValue(110), 1);
@@ -95,7 +113,12 @@
 }
 
 TEST(FrameTimingTrackerTest, OneFrameId) {
-  scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+  FakeImplProxy proxy;
+  TestSharedBitmapManager shared_bitmap_manager;
+  FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
+
+  scoped_ptr<FrameTimingTracker> tracker(
+      FrameTimingTracker::Create(&host_impl));
   std::vector<std::pair<int, int64_t>> ids;
   ids.push_back(std::make_pair(1, 2));
   tracker->SaveTimeStamps(base::TimeTicks::FromInternalValue(100), ids);
@@ -106,7 +129,12 @@
 }
 
 TEST(FrameTimingTrackerTest, OneMainFrameRect) {
-  scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+  FakeImplProxy proxy;
+  TestSharedBitmapManager shared_bitmap_manager;
+  FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
+
+  scoped_ptr<FrameTimingTracker> tracker(
+      FrameTimingTracker::Create(&host_impl));
   std::vector<int64_t> rect_ids;
   rect_ids.push_back(1);
   tracker->SaveMainFrameTimeStamps(rect_ids,
@@ -119,7 +147,12 @@
 }
 
 TEST(FrameTimingTrackerTest, UnsortedTimestampsIds) {
-  scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+  FakeImplProxy proxy;
+  TestSharedBitmapManager shared_bitmap_manager;
+  FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
+
+  scoped_ptr<FrameTimingTracker> tracker(
+      FrameTimingTracker::Create(&host_impl));
   std::vector<std::pair<int, int64_t>> ids;
   ids.push_back(std::make_pair(1, 2));
   tracker->SaveTimeStamps(base::TimeTicks::FromInternalValue(200), ids);
@@ -134,7 +167,12 @@
 }
 
 TEST(FrameTimingTrackerTest, MainFrameUnsortedTimestamps) {
-  scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+  FakeImplProxy proxy;
+  TestSharedBitmapManager shared_bitmap_manager;
+  FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
+
+  scoped_ptr<FrameTimingTracker> tracker(
+      FrameTimingTracker::Create(&host_impl));
   std::vector<int64_t> rect_ids;
   rect_ids.push_back(2);
   tracker->SaveMainFrameTimeStamps(rect_ids,
@@ -155,7 +193,12 @@
 }
 
 TEST(FrameTimingTrackerTest, MultipleFrameIds) {
-  scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+  FakeImplProxy proxy;
+  TestSharedBitmapManager shared_bitmap_manager;
+  FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
+
+  scoped_ptr<FrameTimingTracker> tracker(
+      FrameTimingTracker::Create(&host_impl));
 
   std::vector<std::pair<int, int64_t>> ids200;
   ids200.push_back(std::make_pair(1, 2));
@@ -187,7 +230,12 @@
 }
 
 TEST(FrameTimingTrackerTest, MultipleMainFrameEvents) {
-  scoped_ptr<FrameTimingTracker> tracker(FrameTimingTracker::Create());
+  FakeImplProxy proxy;
+  TestSharedBitmapManager shared_bitmap_manager;
+  FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
+
+  scoped_ptr<FrameTimingTracker> tracker(
+      FrameTimingTracker::Create(&host_impl));
 
   std::vector<int64_t> rect_ids200;
   rect_ids200.push_back(2);
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.cc b/cc/debug/rasterize_and_record_benchmark_impl.cc
index 8f8a71d..9a9d241e6 100644
--- a/cc/debug/rasterize_and_record_benchmark_impl.cc
+++ b/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -91,8 +91,8 @@
     return base_client_->GetPendingOrActiveTwinTiling(tiling);
   }
 
-  TilePriority::PriorityBin GetMaxTilePriorityBin() const override {
-    return base_client_->GetMaxTilePriorityBin();
+  bool HasValidTilePriorities() const override {
+    return base_client_->HasValidTilePriorities();
   }
 
   bool RequiresHighResToDraw() const override {
diff --git a/cc/layers/delegated_renderer_layer_impl_unittest.cc b/cc/layers/delegated_renderer_layer_impl_unittest.cc
index d5ab06b..cc5f03d 100644
--- a/cc/layers/delegated_renderer_layer_impl_unittest.cc
+++ b/cc/layers/delegated_renderer_layer_impl_unittest.cc
@@ -407,21 +407,26 @@
   gfx::Transform transform;
   transform.Translate(4.0, 4.0);
   EXPECT_TRANSFORMATION_MATRIX_EQ(
-      transform, frame.render_passes[3]->quad_list.front()->quadTransform());
+      transform, frame.render_passes[3]
+                     ->quad_list.front()
+                     ->shared_quad_state->content_to_target_transform);
 
   // Quads from non-root RenderPasses should not be shifted though.
   ASSERT_EQ(2u, frame.render_passes[2]->quad_list.size());
 
   EXPECT_TRANSFORMATION_MATRIX_EQ(
-      gfx::Transform(),
-      frame.render_passes[2]->quad_list.front()->quadTransform());
+      gfx::Transform(), frame.render_passes[2]
+                            ->quad_list.front()
+                            ->shared_quad_state->content_to_target_transform);
   EXPECT_TRANSFORMATION_MATRIX_EQ(
-      gfx::Transform(),
-      frame.render_passes[2]->quad_list.ElementAt(1)->quadTransform());
+      gfx::Transform(), frame.render_passes[2]
+                            ->quad_list.ElementAt(1)
+                            ->shared_quad_state->content_to_target_transform);
   ASSERT_EQ(1u, frame.render_passes[1]->quad_list.size());
   EXPECT_TRANSFORMATION_MATRIX_EQ(
-      gfx::Transform(),
-      frame.render_passes[1]->quad_list.front()->quadTransform());
+      gfx::Transform(), frame.render_passes[1]
+                            ->quad_list.front()
+                            ->shared_quad_state->content_to_target_transform);
 
   host_impl_->DrawLayers(&frame);
   host_impl_->DidDrawAllLayers(frame);
@@ -582,22 +587,26 @@
   // Because the DelegatedRendererLayer owns a RenderSurfaceImpl, its root
   // RenderPass' quads do not need to be translated at all.
   EXPECT_TRANSFORMATION_MATRIX_EQ(
-      gfx::Transform(),
-      frame.render_passes[3]->quad_list.front()->quadTransform());
+      gfx::Transform(), frame.render_passes[3]
+                            ->quad_list.front()
+                            ->shared_quad_state->content_to_target_transform);
 
   // Quads from non-root RenderPasses should not be shifted either.
   ASSERT_EQ(2u, frame.render_passes[2]->quad_list.size());
 
   EXPECT_TRANSFORMATION_MATRIX_EQ(
-      gfx::Transform(),
-      frame.render_passes[2]->quad_list.front()->quadTransform());
+      gfx::Transform(), frame.render_passes[2]
+                            ->quad_list.front()
+                            ->shared_quad_state->content_to_target_transform);
   EXPECT_TRANSFORMATION_MATRIX_EQ(
-      gfx::Transform(),
-      frame.render_passes[2]->quad_list.ElementAt(1)->quadTransform());
+      gfx::Transform(), frame.render_passes[2]
+                            ->quad_list.ElementAt(1)
+                            ->shared_quad_state->content_to_target_transform);
   ASSERT_EQ(1u, frame.render_passes[1]->quad_list.size());
   EXPECT_TRANSFORMATION_MATRIX_EQ(
-      gfx::Transform(),
-      frame.render_passes[1]->quad_list.front()->quadTransform());
+      gfx::Transform(), frame.render_passes[1]
+                            ->quad_list.front()
+                            ->shared_quad_state->content_to_target_transform);
 
   host_impl_->DrawLayers(&frame);
   host_impl_->DidDrawAllLayers(frame);
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index d795670..af3fc674 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -1150,7 +1150,7 @@
 
   // TODO(enne): This is needed because CDP does this.  Once main thread CDP
   // goes away, content scale / bounds can be removed.
-  if (layer_tree_host()->settings().impl_side_painting) {
+  if (layer_tree_host()->using_only_property_trees()) {
     layer->SetContentsScale(1.f, 1.f);
     layer->SetContentBounds(bounds());
   } else {
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index c6c8d66..88cf1fb 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -650,12 +650,6 @@
   return twin_layer->tilings_->FindTilingWithScale(tiling->contents_scale());
 }
 
-TilePriority::PriorityBin PictureLayerImpl::GetMaxTilePriorityBin() const {
-  if (!HasValidTilePriorities())
-    return TilePriority::EVENTUALLY;
-  return TilePriority::NOW;
-}
-
 bool PictureLayerImpl::RequiresHighResToDraw() const {
   return layer_tree_impl()->RequiresHighResToDraw();
 }
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index 119b0d4..a23dbba6 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -61,7 +61,7 @@
   const Region* GetPendingInvalidation() override;
   const PictureLayerTiling* GetPendingOrActiveTwinTiling(
       const PictureLayerTiling* tiling) const override;
-  TilePriority::PriorityBin GetMaxTilePriorityBin() const override;
+  bool HasValidTilePriorities() const override;
   bool RequiresHighResToDraw() const override;
   gfx::Rect GetEnclosingRectInTargetSpace() const override;
 
@@ -93,8 +93,6 @@
   // Functions used by tile manager.
   PictureLayerImpl* GetPendingOrActiveTwinLayer() const;
   bool IsOnActiveOrPendingTree() const;
-  // Virtual for testing.
-  virtual bool HasValidTilePriorities() const;
 
   // Used for benchmarking
   RasterSource* GetRasterSource() const { return raster_source_.get(); }
diff --git a/cc/layers/solid_color_layer_impl_unittest.cc b/cc/layers/solid_color_layer_impl_unittest.cc
index 5035ec7..9cfd2efd 100644
--- a/cc/layers/solid_color_layer_impl_unittest.cc
+++ b/cc/layers/solid_color_layer_impl_unittest.cc
@@ -99,7 +99,7 @@
   ASSERT_EQ(render_pass->quad_list.size(), 1U);
   EXPECT_EQ(opacity,
             SolidColorDrawQuad::MaterialCast(render_pass->quad_list.front())
-                ->opacity());
+                ->shared_quad_state->opacity);
 }
 
 TEST(SolidColorLayerImplTest, VerifyCorrectBlendModeInQuad) {
diff --git a/cc/layers/surface_layer.cc b/cc/layers/surface_layer.cc
index dc88810..e186230 100644
--- a/cc/layers/surface_layer.cc
+++ b/cc/layers/surface_layer.cc
@@ -94,15 +94,8 @@
   SurfaceLayerImpl* layer_impl = static_cast<SurfaceLayerImpl*>(layer);
 
   layer_impl->SetSurfaceId(surface_id_);
-}
-
-void SurfaceLayer::CalculateContentsScale(float ideal_contents_scale,
-                                          float* contents_scale_x,
-                                          float* contents_scale_y,
-                                          gfx::Size* content_bounds) {
-  *content_bounds = surface_size_;
-  *contents_scale_x = surface_scale_;
-  *contents_scale_y = surface_scale_;
+  layer_impl->SetSurfaceSize(surface_size_);
+  layer_impl->SetSurfaceScale(surface_scale_);
 }
 
 void SurfaceLayer::CreateNewDestroySequence() {
diff --git a/cc/layers/surface_layer.h b/cc/layers/surface_layer.h
index d30d3085..e62d6a2 100644
--- a/cc/layers/surface_layer.h
+++ b/cc/layers/surface_layer.h
@@ -37,10 +37,6 @@
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
   void SetLayerTreeHost(LayerTreeHost* host) override;
   void PushPropertiesTo(LayerImpl* layer) override;
-  void CalculateContentsScale(float ideal_contents_scale,
-                              float* contents_scale_x,
-                              float* contents_scale_y,
-                              gfx::Size* content_bounds) override;
 
  protected:
   SurfaceLayer(const LayerSettings& settings,
diff --git a/cc/layers/surface_layer_impl.cc b/cc/layers/surface_layer_impl.cc
index 966112d..f029335 100644
--- a/cc/layers/surface_layer_impl.cc
+++ b/cc/layers/surface_layer_impl.cc
@@ -12,7 +12,7 @@
 namespace cc {
 
 SurfaceLayerImpl::SurfaceLayerImpl(LayerTreeImpl* tree_impl, int id)
-    : LayerImpl(tree_impl, id) {
+    : LayerImpl(tree_impl, id), surface_scale_(0.f) {
 }
 
 SurfaceLayerImpl::~SurfaceLayerImpl() {}
@@ -30,26 +30,44 @@
   NoteLayerPropertyChanged();
 }
 
+void SurfaceLayerImpl::SetSurfaceScale(float scale) {
+  if (surface_scale_ == scale)
+    return;
+
+  surface_scale_ = scale;
+  NoteLayerPropertyChanged();
+}
+
+void SurfaceLayerImpl::SetSurfaceSize(const gfx::Size& size) {
+  if (surface_size_ == size)
+    return;
+
+  surface_size_ = size;
+  NoteLayerPropertyChanged();
+}
+
 void SurfaceLayerImpl::PushPropertiesTo(LayerImpl* layer) {
   LayerImpl::PushPropertiesTo(layer);
   SurfaceLayerImpl* layer_impl = static_cast<SurfaceLayerImpl*>(layer);
 
   layer_impl->SetSurfaceId(surface_id_);
+  layer_impl->SetSurfaceSize(surface_size_);
+  layer_impl->SetSurfaceScale(surface_scale_);
 }
 
 void SurfaceLayerImpl::AppendQuads(RenderPass* render_pass,
                                    AppendQuadsData* append_quads_data) {
   SharedQuadState* shared_quad_state =
       render_pass->CreateAndAppendSharedQuadState();
-  PopulateSharedQuadState(shared_quad_state);
+  PopulateScaledSharedQuadState(shared_quad_state, surface_scale_);
 
-  AppendDebugBorderQuad(
-      render_pass, content_bounds(), shared_quad_state, append_quads_data);
+  AppendDebugBorderQuad(render_pass, surface_size_, shared_quad_state,
+                        append_quads_data);
 
   if (surface_id_.is_null())
     return;
 
-  gfx::Rect quad_rect(content_bounds());
+  gfx::Rect quad_rect(surface_size_);
   gfx::Rect visible_quad_rect =
       draw_properties().occlusion_in_content_space.GetUnoccludedContentRect(
           quad_rect);
diff --git a/cc/layers/surface_layer_impl.h b/cc/layers/surface_layer_impl.h
index 90c0f456..b190b3a 100644
--- a/cc/layers/surface_layer_impl.h
+++ b/cc/layers/surface_layer_impl.h
@@ -20,6 +20,8 @@
   ~SurfaceLayerImpl() override;
 
   void SetSurfaceId(SurfaceId surface_id);
+  void SetSurfaceScale(float scale);
+  void SetSurfaceSize(const gfx::Size& size);
 
   // LayerImpl overrides.
   scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
@@ -36,6 +38,8 @@
   const char* LayerTypeAsString() const override;
 
   SurfaceId surface_id_;
+  gfx::Size surface_size_;
+  float surface_scale_;
 
   DISALLOW_COPY_AND_ASSIGN(SurfaceLayerImpl);
 };
diff --git a/cc/layers/surface_layer_impl_unittest.cc b/cc/layers/surface_layer_impl_unittest.cc
index 74543a8..39577a3 100644
--- a/cc/layers/surface_layer_impl_unittest.cc
+++ b/cc/layers/surface_layer_impl_unittest.cc
@@ -23,6 +23,8 @@
   surface_layer_impl->SetDrawsContent(true);
   SurfaceId surface_id(9);
   surface_layer_impl->SetSurfaceId(surface_id);
+  surface_layer_impl->SetSurfaceScale(1.f);
+  surface_layer_impl->SetSurfaceSize(layer_size);
 
   impl.CalcDrawProps(viewport_size);
 
diff --git a/cc/layers/surface_layer_unittest.cc b/cc/layers/surface_layer_unittest.cc
index 5b656a5..74fa2dd 100644
--- a/cc/layers/surface_layer_unittest.cc
+++ b/cc/layers/surface_layer_unittest.cc
@@ -116,36 +116,6 @@
   EXPECT_EQ(2u, required_seq.size());
 }
 
-static void CalcDrawProps(FakeLayerTreeHost* host, float device_scale_factor) {
-  RenderSurfaceLayerList render_surface_layer_list;
-  LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
-      host->root_layer(), gfx::Size(500, 500), &render_surface_layer_list);
-  inputs.device_scale_factor = device_scale_factor;
-  LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-}
-
-// Check that setting content scale on the surface works.
-TEST_F(SurfaceLayerTest, ScaleSurface) {
-  SurfaceSequence blank_change;
-  SurfaceId required_id;
-  std::set<SurfaceSequence> required_seq;
-  scoped_refptr<SurfaceLayer> layer(SurfaceLayer::Create(
-      layer_settings_, base::Bind(&SatisfyCallback, &blank_change),
-      base::Bind(&RequireCallback, &required_id, &required_seq)));
-  gfx::Size surface_size(10, 15);
-  layer->SetSurfaceId(SurfaceId(1), 2.f, surface_size);
-  layer->SetBounds(gfx::Size(25, 45));
-  layer_tree_host_->SetRootLayer(layer);
-
-  CalcDrawProps(layer_tree_host_.get(), 5.f);
-  EXPECT_EQ(2.f, layer->contents_scale_x());
-  EXPECT_EQ(2.f, layer->contents_scale_y());
-  EXPECT_EQ(surface_size.ToString(), layer->content_bounds().ToString());
-
-  layer_tree_host_->SetRootLayer(nullptr);
-  layer_tree_host_.reset();
-}
-
 // Check that SurfaceSequence is sent through swap promise.
 class SurfaceLayerSwapPromise : public LayerTreeTest {
  public:
diff --git a/cc/layers/video_layer_impl_unittest.cc b/cc/layers/video_layer_impl_unittest.cc
index 088560c..56d43a7 100644
--- a/cc/layers/video_layer_impl_unittest.cc
+++ b/cc/layers/video_layer_impl_unittest.cc
@@ -178,8 +178,12 @@
 
   gfx::Point3F p1(0, impl.quad_list().front()->rect.height(), 0);
   gfx::Point3F p2(impl.quad_list().front()->rect.width(), 0, 0);
-  impl.quad_list().front()->quadTransform().TransformPoint(&p1);
-  impl.quad_list().front()->quadTransform().TransformPoint(&p2);
+  impl.quad_list()
+      .front()
+      ->shared_quad_state->content_to_target_transform.TransformPoint(&p1);
+  impl.quad_list()
+      .front()
+      ->shared_quad_state->content_to_target_transform.TransformPoint(&p2);
   EXPECT_EQ(gfx::Point3F(0, 50, 0), p1);
   EXPECT_EQ(gfx::Point3F(100, 0, 0), p2);
 }
@@ -214,8 +218,12 @@
 
   gfx::Point3F p1(0, impl.quad_list().front()->rect.height(), 0);
   gfx::Point3F p2(impl.quad_list().front()->rect.width(), 0, 0);
-  impl.quad_list().front()->quadTransform().TransformPoint(&p1);
-  impl.quad_list().front()->quadTransform().TransformPoint(&p2);
+  impl.quad_list()
+      .front()
+      ->shared_quad_state->content_to_target_transform.TransformPoint(&p1);
+  impl.quad_list()
+      .front()
+      ->shared_quad_state->content_to_target_transform.TransformPoint(&p2);
   EXPECT_EQ(gfx::Point3F(0, 0, 0), p1);
   EXPECT_EQ(gfx::Point3F(100, 50, 0), p2);
 }
@@ -250,8 +258,12 @@
 
   gfx::Point3F p1(0, impl.quad_list().front()->rect.height(), 0);
   gfx::Point3F p2(impl.quad_list().front()->rect.width(), 0, 0);
-  impl.quad_list().front()->quadTransform().TransformPoint(&p1);
-  impl.quad_list().front()->quadTransform().TransformPoint(&p2);
+  impl.quad_list()
+      .front()
+      ->shared_quad_state->content_to_target_transform.TransformPoint(&p1);
+  impl.quad_list()
+      .front()
+      ->shared_quad_state->content_to_target_transform.TransformPoint(&p2);
   EXPECT_EQ(gfx::Point3F(100, 0, 0), p1);
   EXPECT_EQ(gfx::Point3F(0, 50, 0), p2);
 }
@@ -286,8 +298,12 @@
 
   gfx::Point3F p1(0, impl.quad_list().front()->rect.height(), 0);
   gfx::Point3F p2(impl.quad_list().front()->rect.width(), 0, 0);
-  impl.quad_list().front()->quadTransform().TransformPoint(&p1);
-  impl.quad_list().front()->quadTransform().TransformPoint(&p2);
+  impl.quad_list()
+      .front()
+      ->shared_quad_state->content_to_target_transform.TransformPoint(&p1);
+  impl.quad_list()
+      .front()
+      ->shared_quad_state->content_to_target_transform.TransformPoint(&p2);
   EXPECT_EQ(gfx::Point3F(100, 50, 0), p1);
   EXPECT_EQ(gfx::Point3F(0, 0, 0), p2);
 }
diff --git a/cc/output/bsp_walk_action.cc b/cc/output/bsp_walk_action.cc
index 9ffc299..ddf39f3b 100644
--- a/cc/output/bsp_walk_action.cc
+++ b/cc/output/bsp_walk_action.cc
@@ -27,7 +27,9 @@
 void BspWalkActionDrawPolygon::operator()(DrawPolygon* item) {
   gfx::Transform inverse_transform;
   bool invertible =
-      item->original_ref()->quadTransform().GetInverse(&inverse_transform);
+      item->original_ref()
+          ->shared_quad_state->content_to_target_transform.GetInverse(
+              &inverse_transform);
   DCHECK(invertible);
   item->TransformToLayerSpace(inverse_transform);
   renderer_->DoDrawPolygon(*item, frame_, render_pass_scissor_,
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index 10bba297..39158169 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -309,8 +309,8 @@
   if (render_pass_scissor.IsEmpty())
     return true;
 
-  if (quad.isClipped()) {
-    gfx::Rect r = quad.clipRect();
+  if (quad.shared_quad_state->is_clipped) {
+    gfx::Rect r = quad.shared_quad_state->clip_rect;
     r.Intersect(render_pass_scissor);
     return r.IsEmpty();
   }
@@ -325,12 +325,12 @@
     bool use_render_pass_scissor) {
   if (use_render_pass_scissor) {
     gfx::Rect quad_scissor_rect = render_pass_scissor;
-    if (quad.isClipped())
-      quad_scissor_rect.Intersect(quad.clipRect());
+    if (quad.shared_quad_state->is_clipped)
+      quad_scissor_rect.Intersect(quad.shared_quad_state->clip_rect);
     SetScissorTestRectInDrawSpace(frame, quad_scissor_rect);
     return;
-  } else if (quad.isClipped()) {
-    SetScissorTestRectInDrawSpace(frame, quad.clipRect());
+  } else if (quad.shared_quad_state->is_clipped) {
+    SetScissorTestRectInDrawSpace(frame, quad.shared_quad_state->clip_rect);
     return;
   }
 
@@ -460,8 +460,10 @@
     // This layer is in a 3D sorting context so we add it to the list of
     // polygons to go into the BSP tree.
     if (quad.shared_quad_state->sorting_context_id != 0) {
-      scoped_ptr<DrawPolygon> new_polygon(new DrawPolygon(
-          *it, quad.visible_rect, quad.quadTransform(), next_polygon_id++));
+      scoped_ptr<DrawPolygon> new_polygon(
+          new DrawPolygon(*it, quad.visible_rect,
+                          quad.shared_quad_state->content_to_target_transform,
+                          next_polygon_id++));
       if (new_polygon->points().size() > 2u) {
         poly_list.push_back(new_polygon.Pass());
       }
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 50dac6cb..faf6bbb 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -597,12 +597,10 @@
 
   gl_->Uniform1f(program->fragment_shader().frequency_location(), frequency);
 
-  SetShaderOpacity(quad->opacity(),
+  SetShaderOpacity(quad->shared_quad_state->opacity,
                    program->fragment_shader().alpha_location());
-  DrawQuadGeometry(frame,
-                   quad->quadTransform(),
-                   quad->rect,
-                   program->vertex_shader().matrix_location());
+  DrawQuadGeometry(frame, quad->shared_quad_state->content_to_target_transform,
+                   quad->rect, program->vertex_shader().matrix_location());
 }
 
 // This function does not handle 3D sorting right now, since the debug border
@@ -621,7 +619,9 @@
   // partial swaps.
   gfx::Rect layer_rect = quad->rect;
   gfx::Transform render_matrix;
-  QuadRectTransform(&render_matrix, quad->quadTransform(), layer_rect);
+  QuadRectTransform(&render_matrix,
+                    quad->shared_quad_state->content_to_target_transform,
+                    layer_rect);
   GLRenderer::ToGLMatrix(&gl_matrix[0],
                          frame->projection_matrix * render_matrix);
   gl_->UniformMatrix4fv(program->vertex_shader().matrix_location(), 1, false,
@@ -931,7 +931,9 @@
   DCHECK(contents_texture->id());
 
   gfx::Transform quad_rect_matrix;
-  QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect);
+  QuadRectTransform(&quad_rect_matrix,
+                    quad->shared_quad_state->content_to_target_transform,
+                    quad->rect);
   gfx::Transform contents_device_transform =
       frame->window_matrix * frame->projection_matrix * quad_rect_matrix;
   contents_device_transform.FlattenTo2d();
@@ -1242,10 +1244,10 @@
     }
   }
 
-  SetShaderOpacity(quad->opacity(), locations.alpha);
+  SetShaderOpacity(quad->shared_quad_state->opacity, locations.alpha);
   SetShaderQuadF(surface_quad, locations.quad);
-  DrawQuadGeometry(
-      frame, quad->quadTransform(), quad->rect, locations.matrix);
+  DrawQuadGeometry(frame, quad->shared_quad_state->content_to_target_transform,
+                   quad->rect, locations.matrix);
 
   // Flush the compositor context before the filter bitmap goes out of
   // scope, so the draw gets processed before the filter texture gets deleted.
@@ -1429,8 +1431,9 @@
   // crbug.com/429702
   if (!is_render_pass_quad && !quad->IsEdge())
     return false;
-  gfx::RectF content_rect =
-      is_render_pass_quad ? QuadVertexRect() : quad->visibleContentRect();
+  gfx::RectF content_rect = is_render_pass_quad
+                                ? QuadVertexRect()
+                                : quad->shared_quad_state->visible_content_rect;
 
   bool clipped = false;
   gfx::QuadF device_layer_quad =
@@ -1466,9 +1469,10 @@
     local_clip_region = &rotated_clip;
   }
 
-  gfx::QuadF content_rect = is_render_pass_quad
-                                ? gfx::QuadF(QuadVertexRect())
-                                : gfx::QuadF(quad->visibleContentRect());
+  gfx::QuadF content_rect =
+      is_render_pass_quad
+          ? gfx::QuadF(QuadVertexRect())
+          : gfx::QuadF(quad->shared_quad_state->visible_content_rect);
   if (!use_aa) {
     if (local_clip_region) {
       if (!is_render_pass_quad) {
@@ -1532,7 +1536,7 @@
   gfx::Rect tile_rect = quad->visible_rect;
 
   SkColor color = quad->color;
-  float opacity = quad->opacity();
+  float opacity = quad->shared_quad_state->opacity;
   float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
 
   // Early out if alpha is small enough that quad doesn't contribute to output.
@@ -1541,7 +1545,8 @@
     return;
 
   gfx::Transform device_transform =
-      frame->window_matrix * frame->projection_matrix * quad->quadTransform();
+      frame->window_matrix * frame->projection_matrix *
+      quad->shared_quad_state->content_to_target_transform;
   device_transform.FlattenTo2d();
   if (!device_transform.IsInvertible())
     return;
@@ -1594,8 +1599,8 @@
   gfx::RectF centered_rect(
       gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()),
       tile_rect.size());
-  DrawQuadGeometry(
-      frame, quad->quadTransform(), centered_rect, uniforms.matrix_location);
+  DrawQuadGeometry(frame, quad->shared_quad_state->content_to_target_transform,
+                   centered_rect, uniforms.matrix_location);
 }
 
 struct TileProgramUniforms {
@@ -1637,7 +1642,8 @@
                                  ResourceId resource_id,
                                  const gfx::QuadF* clip_region) {
   gfx::Transform device_transform =
-      frame->window_matrix * frame->projection_matrix * quad->quadTransform();
+      frame->window_matrix * frame->projection_matrix *
+      quad->shared_quad_state->content_to_target_transform;
   device_transform.FlattenTo2d();
 
   bool use_aa = settings_->allow_antialiasing &&
@@ -1758,7 +1764,7 @@
   // Normalize to tile_rect.
   local_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height());
 
-  SetShaderOpacity(quad->opacity(), uniforms.alpha_location);
+  SetShaderOpacity(quad->shared_quad_state->opacity, uniforms.alpha_location);
   SetShaderQuadF(local_quad, uniforms.quad_location);
 
   // The transform and vertex data are used to figure out the extents that the
@@ -1768,8 +1774,8 @@
   gfx::RectF centered_rect(
       gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()),
       tile_rect.size());
-  DrawQuadGeometry(
-      frame, quad->quadTransform(), centered_rect, uniforms.matrix_location);
+  DrawQuadGeometry(frame, quad->shared_quad_state->content_to_target_transform,
+                   centered_rect, uniforms.matrix_location);
 }
 
 void GLRenderer::DrawContentQuadNoAA(const DrawingFrame* frame,
@@ -1783,11 +1789,12 @@
       quad->rect.height() / quad->tex_coord_rect.height();
 
   bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f);
-  GLenum filter =
-      (scaled || !quad->quadTransform().IsIdentityOrIntegerTranslation()) &&
-              !quad->nearest_neighbor
-          ? GL_LINEAR
-          : GL_NEAREST;
+  GLenum filter = (scaled ||
+                   !quad->shared_quad_state->content_to_target_transform
+                        .IsIdentityOrIntegerTranslation()) &&
+                          !quad->nearest_neighbor
+                      ? GL_LINEAR
+                      : GL_NEAREST;
 
   ResourceProvider::ScopedSamplerGL quad_resource_lock(
       resource_provider_, resource_id, filter);
@@ -1840,7 +1847,7 @@
 
   SetBlendEnabled(quad->ShouldDrawWithBlending());
 
-  SetShaderOpacity(quad->opacity(), uniforms.alpha_location);
+  SetShaderOpacity(quad->shared_quad_state->opacity, uniforms.alpha_location);
 
   // Pass quad coordinates to the uniform in the same order as GeometryBinding
   // does, then vertices will match the texture mapping in the vertex buffer.
@@ -1881,7 +1888,9 @@
   gl_->Uniform2fv(uniforms.quad_location, 4, gl_quad);
 
   static float gl_matrix[16];
-  ToGLMatrix(&gl_matrix[0], frame->projection_matrix * quad->quadTransform());
+  ToGLMatrix(&gl_matrix[0],
+             frame->projection_matrix *
+                 quad->shared_quad_state->content_to_target_transform);
   gl_->UniformMatrix4fv(uniforms.matrix_location, 1, false, &gl_matrix[0]);
 
   gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
@@ -2087,17 +2096,20 @@
   gl_->UniformMatrix3fv(yuv_matrix_location, 1, 0, yuv_to_rgb);
   gl_->Uniform3fv(yuv_adj_location, 1, yuv_adjust);
 
-  SetShaderOpacity(quad->opacity(), alpha_location);
+  SetShaderOpacity(quad->shared_quad_state->opacity, alpha_location);
   if (!clip_region) {
-    DrawQuadGeometry(frame, quad->quadTransform(), tile_rect, matrix_location);
+    DrawQuadGeometry(frame,
+                     quad->shared_quad_state->content_to_target_transform,
+                     tile_rect, matrix_location);
   } else {
     float uvs[8] = {0};
     GetScaledUVs(quad->visible_rect, clip_region, uvs);
     gfx::QuadF region_quad = *clip_region;
     region_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height());
     region_quad -= gfx::Vector2dF(0.5f, 0.5f);
-    DrawQuadGeometryClippedByQuadF(frame, quad->quadTransform(), tile_rect,
-                                   region_quad, matrix_location, uvs);
+    DrawQuadGeometryClippedByQuadF(
+        frame, quad->shared_quad_state->content_to_target_transform, tile_rect,
+        region_quad, matrix_location, uvs);
   }
 }
 
@@ -2131,11 +2143,12 @@
 
   gl_->Uniform1i(program->fragment_shader().sampler_location(), 0);
 
-  SetShaderOpacity(quad->opacity(),
+  SetShaderOpacity(quad->shared_quad_state->opacity,
                    program->fragment_shader().alpha_location());
   if (!clip_region) {
-    DrawQuadGeometry(frame, quad->quadTransform(), quad->rect,
-                     program->vertex_shader().matrix_location());
+    DrawQuadGeometry(frame,
+                     quad->shared_quad_state->content_to_target_transform,
+                     quad->rect, program->vertex_shader().matrix_location());
   } else {
     gfx::QuadF region_quad(*clip_region);
     region_quad.Scale(1.0f / quad->rect.width(), 1.0f / quad->rect.height());
@@ -2143,8 +2156,8 @@
     float uvs[8] = {0};
     GetScaledUVs(quad->visible_rect, clip_region, uvs);
     DrawQuadGeometryClippedByQuadF(
-        frame, quad->quadTransform(), quad->rect, region_quad,
-        program->vertex_shader().matrix_location(), uvs);
+        frame, quad->shared_quad_state->content_to_target_transform, quad->rect,
+        region_quad, program->vertex_shader().matrix_location(), uvs);
   }
 }
 
@@ -2313,7 +2326,7 @@
   }
 
   // Generate the vertex opacity
-  const float opacity = quad->opacity();
+  const float opacity = quad->shared_quad_state->opacity;
   draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[0] * opacity);
   draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[1] * opacity);
   draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[2] * opacity);
@@ -2321,7 +2334,9 @@
 
   // Generate the transform matrix
   gfx::Transform quad_rect_matrix;
-  QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect);
+  QuadRectTransform(&quad_rect_matrix,
+                    quad->shared_quad_state->content_to_target_transform,
+                    quad->rect);
   quad_rect_matrix = frame->projection_matrix * quad_rect_matrix;
 
   Float16 m;
@@ -2376,8 +2391,10 @@
                    quad->io_surface_size.height());
   }
 
-  const float vertex_opacity[] = {quad->opacity(), quad->opacity(),
-                                  quad->opacity(), quad->opacity()};
+  const float vertex_opacity[] = {quad->shared_quad_state->opacity,
+                                  quad->shared_quad_state->opacity,
+                                  quad->shared_quad_state->opacity,
+                                  quad->shared_quad_state->opacity};
   gl_->Uniform1fv(binding.vertex_opacity_location, 4, vertex_opacity);
 
   ResourceProvider::ScopedReadLockGL lock(resource_provider_,
@@ -2386,13 +2403,15 @@
   gl_->BindTexture(GL_TEXTURE_RECTANGLE_ARB, lock.texture_id());
 
   if (!clip_region) {
-    DrawQuadGeometry(frame, quad->quadTransform(), quad->rect,
-                     binding.matrix_location);
+    DrawQuadGeometry(frame,
+                     quad->shared_quad_state->content_to_target_transform,
+                     quad->rect, binding.matrix_location);
   } else {
     float uvs[8] = {0};
     GetScaledUVs(quad->visible_rect, clip_region, uvs);
-    DrawQuadGeometryClippedByQuadF(frame, quad->quadTransform(), quad->rect,
-                                   *clip_region, binding.matrix_location, uvs);
+    DrawQuadGeometryClippedByQuadF(
+        frame, quad->shared_quad_state->content_to_target_transform, quad->rect,
+        *clip_region, binding.matrix_location, uvs);
   }
 
   gl_->BindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
diff --git a/cc/output/overlay_strategy_common.cc b/cc/output/overlay_strategy_common.cc
index 93bd15c..6fa778a 100644
--- a/cc/output/overlay_strategy_common.cc
+++ b/cc/output/overlay_strategy_common.cc
@@ -46,7 +46,7 @@
     const SolidColorDrawQuad* solid_quad =
         SolidColorDrawQuad::MaterialCast(draw_quad);
     SkColor color = solid_quad->color;
-    float opacity = solid_quad->opacity();
+    float opacity = solid_quad->shared_quad_state->opacity;
     float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
     return solid_quad->ShouldDrawWithBlending() &&
            alpha < std::numeric_limits<float>::epsilon();
@@ -57,8 +57,8 @@
 bool OverlayStrategyCommon::GetTextureQuadInfo(const TextureDrawQuad& quad,
                                                OverlayCandidate* quad_info) {
   gfx::OverlayTransform overlay_transform =
-      OverlayCandidate::GetOverlayTransform(quad.quadTransform(),
-                                            quad.y_flipped);
+      OverlayCandidate::GetOverlayTransform(
+          quad.shared_quad_state->content_to_target_transform, quad.y_flipped);
   if (quad.background_color != SK_ColorTRANSPARENT ||
       quad.premultiplied_alpha ||
       overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID)
@@ -72,7 +72,8 @@
 bool OverlayStrategyCommon::GetVideoQuadInfo(const StreamVideoDrawQuad& quad,
                                              OverlayCandidate* quad_info) {
   gfx::OverlayTransform overlay_transform =
-      OverlayCandidate::GetOverlayTransform(quad.quadTransform(), false);
+      OverlayCandidate::GetOverlayTransform(
+          quad.shared_quad_state->content_to_target_transform, false);
   if (overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID)
     return false;
   if (!quad.matrix.IsScaleOrTranslation()) {
@@ -130,7 +131,7 @@
 
   quad_info->format = RGBA_8888;
   quad_info->display_rect = OverlayCandidate::GetOverlayRect(
-      draw_quad.quadTransform(), draw_quad.rect);
+      draw_quad.shared_quad_state->content_to_target_transform, draw_quad.rect);
   return true;
 }
 
diff --git a/cc/output/overlay_strategy_single_on_top.cc b/cc/output/overlay_strategy_single_on_top.cc
index 7cb0dca..921dba7a 100644
--- a/cc/output/overlay_strategy_single_on_top.cc
+++ b/cc/output/overlay_strategy_single_on_top.cc
@@ -36,11 +36,13 @@
       // Check that no prior quads overlap it.
       bool intersects = false;
       gfx::RectF rect = draw_quad->rect;
-      draw_quad->quadTransform().TransformRect(&rect);
+      draw_quad->shared_quad_state->content_to_target_transform.TransformRect(
+          &rect);
       for (auto overlap_iter = quad_list.cbegin(); overlap_iter != it;
            ++overlap_iter) {
         gfx::RectF overlap_rect = overlap_iter->rect;
-        overlap_iter->quadTransform().TransformRect(&overlap_rect);
+        overlap_iter->shared_quad_state->content_to_target_transform
+            .TransformRect(&overlap_rect);
         if (rect.Intersects(overlap_rect) && !IsInvisibleQuad(*overlap_iter)) {
           intersects = true;
           break;
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index 992dbc9..e7540ccb 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -250,7 +250,9 @@
 
   TRACE_EVENT0("cc", "SoftwareRenderer::DoDrawQuad");
   gfx::Transform quad_rect_matrix;
-  QuadRectTransform(&quad_rect_matrix, quad->quadTransform(), quad->rect);
+  QuadRectTransform(&quad_rect_matrix,
+                    quad->shared_quad_state->content_to_target_transform,
+                    quad->rect);
   gfx::Transform contents_device_transform =
       frame->window_matrix * frame->projection_matrix * quad_rect_matrix;
   contents_device_transform.FlattenTo2d();
@@ -276,7 +278,7 @@
 
   if (quad->ShouldDrawWithBlending() ||
       quad->shared_quad_state->blend_mode != SkXfermode::kSrcOver_Mode) {
-    current_paint_.setAlpha(quad->opacity() * 255);
+    current_paint_.setAlpha(quad->shared_quad_state->opacity * 255);
     current_paint_.setXfermodeMode(quad->shared_quad_state->blend_mode);
   } else {
     current_paint_.setXfermodeMode(SkXfermode::kSrc_Mode);
@@ -351,7 +353,7 @@
   gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional(
       QuadVertexRect(), quad->rect, quad->visible_rect);
   current_paint_.setColor(quad->color);
-  current_paint_.setAlpha(quad->opacity());
+  current_paint_.setAlpha(quad->shared_quad_state->opacity);
   current_canvas_->drawRect(gfx::RectFToSkRect(visible_quad_vertex_rect),
                             current_paint_);
 }
@@ -368,7 +370,8 @@
   current_canvas_->resetMatrix();
 
   current_paint_.setColor(quad->color);
-  current_paint_.setAlpha(quad->opacity() * SkColorGetA(quad->color));
+  current_paint_.setAlpha(quad->shared_quad_state->opacity *
+                          SkColorGetA(quad->color));
   current_paint_.setStyle(SkPaint::kStroke_Style);
   current_paint_.setStrokeWidth(quad->width);
   current_canvas_->drawPoints(SkCanvas::kPolygon_PointMode,
@@ -387,10 +390,10 @@
   // TODO(aelias): This isn't correct in all cases. We should detect these
   // cases and fall back to a persistent bitmap backing
   // (http://crbug.com/280374).
-  skia::RefPtr<SkDrawFilter> opacity_filter =
-      skia::AdoptRef(new skia::OpacityDrawFilter(
-          quad->opacity(), frame->disable_picture_quad_image_filtering ||
-                               quad->nearest_neighbor));
+  skia::RefPtr<SkDrawFilter> opacity_filter = skia::AdoptRef(
+      new skia::OpacityDrawFilter(quad->shared_quad_state->opacity,
+                                  frame->disable_picture_quad_image_filtering ||
+                                      quad->nearest_neighbor));
   DCHECK(!current_canvas_->getDrawFilter());
   current_canvas_->setDrawFilter(opacity_filter.get());
 
@@ -408,7 +411,8 @@
   gfx::RectF visible_quad_vertex_rect = MathUtil::ScaleRectProportional(
       QuadVertexRect(), quad->rect, quad->visible_rect);
   current_paint_.setColor(quad->color);
-  current_paint_.setAlpha(quad->opacity() * SkColorGetA(quad->color));
+  current_paint_.setAlpha(quad->shared_quad_state->opacity *
+                          SkColorGetA(quad->color));
   current_canvas_->drawRect(gfx::RectFToSkRect(visible_quad_vertex_rect),
                             current_paint_);
 }
@@ -607,7 +611,7 @@
 #else
   current_paint_.setColor(SK_ColorMAGENTA);
 #endif
-  current_paint_.setAlpha(quad->opacity() * 255);
+  current_paint_.setAlpha(quad->shared_quad_state->opacity * 255);
   current_canvas_->drawRect(gfx::RectFToSkRect(QuadVertexRect()),
                             current_paint_);
 }
diff --git a/cc/playback/display_item_list.cc b/cc/playback/display_item_list.cc
index 2f1577a..abd40db 100644
--- a/cc/playback/display_item_list.cc
+++ b/cc/playback/display_item_list.cc
@@ -160,6 +160,15 @@
     items_.clear();
 }
 
+void DisplayItemList::RemoveLast() {
+  // We cannot remove the last item if it has been squashed into a picture.
+  // The last item should not have been handled by ProcessAppendedItems, so we
+  // don't need to remove it from approximate_op_count_, etc.
+  DCHECK(retain_individual_display_items_);
+  DCHECK(!use_cached_picture_);
+  items_.RemoveLast();
+}
+
 void DisplayItemList::Finalize() {
   ProcessAppendedItems();
 
diff --git a/cc/playback/display_item_list.h b/cc/playback/display_item_list.h
index ad5eeff4..5212a60 100644
--- a/cc/playback/display_item_list.h
+++ b/cc/playback/display_item_list.h
@@ -54,6 +54,11 @@
     return items_.AllocateAndConstruct<DisplayItemType>();
   }
 
+  // Removes the last item. This cannot be called on lists with cached pictures
+  // (since the data may already have been incorporated into cached picture
+  // sizes, etc).
+  void RemoveLast();
+
   // Called after all items are appended, to process the items and, if
   // applicable, create an internally cached SkPicture.
   void Finalize();
diff --git a/cc/quads/draw_quad.h b/cc/quads/draw_quad.h
index fa1959b..07bf177 100644
--- a/cc/quads/draw_quad.h
+++ b/cc/quads/draw_quad.h
@@ -51,17 +51,6 @@
 
   virtual ~DrawQuad();
 
-  // TODO(danakj): Chromify or remove these SharedQuadState helpers.
-  const gfx::Transform& quadTransform() const {
-    return shared_quad_state->content_to_target_transform;
-  }
-  gfx::Rect visibleContentRect() const {
-    return shared_quad_state->visible_content_rect;
-  }
-  gfx::Rect clipRect() const { return shared_quad_state->clip_rect; }
-  bool isClipped() const { return shared_quad_state->is_clipped; }
-  float opacity() const { return shared_quad_state->opacity; }
-
   Material material;
 
   // This rect, after applying the quad_transform(), gives the geometry that
diff --git a/cc/quads/list_container_unittest.cc b/cc/quads/list_container_unittest.cc
deleted file mode 100644
index 5836fb5..0000000
--- a/cc/quads/list_container_unittest.cc
+++ /dev/null
@@ -1,653 +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 "cc/base/list_container.h"
-
-#include <vector>
-#include "cc/quads/draw_quad.h"
-#include "cc/quads/largest_draw_quad.h"
-#include "cc/quads/render_pass_draw_quad.h"
-#include "cc/quads/shared_quad_state.h"
-#include "cc/quads/stream_video_draw_quad.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// TODO(jbroman): This unit test should be made generic and moved to cc/base/.
-
-namespace cc {
-namespace {
-
-int kMagicNumberToUseForDrawQuadOne = 42;
-int kMagicNumberToUseForDrawQuadTwo = 314;
-
-bool isConstSharedQuadStatePointer(const SharedQuadState* ptr) {
-  return true;
-}
-
-bool isConstSharedQuadStatePointer(SharedQuadState* ptr) {
-  return false;
-}
-
-class SimpleDrawQuad : public DrawQuad {
- public:
-  ~SimpleDrawQuad() override {}
-
-  void set_value(int val) { value = val; }
-  int get_value() { return value; }
-  void ExtendValue(base::trace_event::TracedValue* value) const override {}
-
- private:
-  int value;
-};
-
-class SimpleDrawQuadConstructMagicNumberOne : public SimpleDrawQuad {
- public:
-  SimpleDrawQuadConstructMagicNumberOne() : SimpleDrawQuad() {
-    set_value(kMagicNumberToUseForDrawQuadOne);
-  }
-};
-
-class SimpleDrawQuadConstructMagicNumberTwo : public SimpleDrawQuad {
- public:
-  SimpleDrawQuadConstructMagicNumberTwo() : SimpleDrawQuad() {
-    set_value(kMagicNumberToUseForDrawQuadTwo);
-  }
-};
-
-class MockDrawQuad : public SimpleDrawQuadConstructMagicNumberOne {
- public:
-  ~MockDrawQuad() override { Destruct(); }
-  MOCK_METHOD0(Destruct, void());
-};
-
-class MockDrawQuadSubclass : public MockDrawQuad {
- public:
-  MockDrawQuadSubclass() { set_value(kMagicNumberToUseForDrawQuadTwo); }
-};
-
-const size_t kLargestQuadSize =
-    std::max(LargestDrawQuadSize(), sizeof(MockDrawQuadSubclass));
-
-TEST(ListContainerTest, ConstructorCalledInAllocateAndConstruct) {
-  ListContainer<DrawQuad> list(kLargestQuadSize);
-
-  size_t size = 2;
-  SimpleDrawQuadConstructMagicNumberOne* dq_1 =
-      list.AllocateAndConstruct<SimpleDrawQuadConstructMagicNumberOne>();
-  SimpleDrawQuadConstructMagicNumberTwo* dq_2 =
-      list.AllocateAndConstruct<SimpleDrawQuadConstructMagicNumberTwo>();
-
-  EXPECT_EQ(size, list.size());
-  EXPECT_EQ(dq_1, list.front());
-  EXPECT_EQ(dq_2, list.back());
-
-  EXPECT_EQ(kMagicNumberToUseForDrawQuadOne, dq_1->get_value());
-  EXPECT_EQ(kMagicNumberToUseForDrawQuadTwo, dq_2->get_value());
-}
-
-TEST(ListContainerTest, DestructorCalled) {
-  ListContainer<DrawQuad> list(kLargestQuadSize);
-
-  size_t size = 1;
-  MockDrawQuad* dq_1 = list.AllocateAndConstruct<MockDrawQuad>();
-
-  EXPECT_CALL(*dq_1, Destruct());
-  EXPECT_EQ(size, list.size());
-  EXPECT_EQ(dq_1, list.front());
-}
-
-TEST(ListContainerTest, DestructorCalledOnceWhenClear) {
-  ListContainer<DrawQuad> list(kLargestQuadSize);
-  size_t size = 1;
-  MockDrawQuad* dq_1 = list.AllocateAndConstruct<MockDrawQuad>();
-
-  EXPECT_EQ(size, list.size());
-  EXPECT_EQ(dq_1, list.front());
-
-  // Make sure destructor is called once during clear, and won't be called
-  // again.
-  testing::MockFunction<void()> separator;
-  {
-    testing::InSequence s;
-    EXPECT_CALL(*dq_1, Destruct());
-    EXPECT_CALL(separator, Call());
-    EXPECT_CALL(*dq_1, Destruct()).Times(0);
-  }
-
-  list.clear();
-  separator.Call();
-}
-
-TEST(ListContainerTest, ReplaceExistingElement) {
-  ListContainer<DrawQuad> list(kLargestQuadSize);
-  size_t size = 1;
-  MockDrawQuad* dq_1 = list.AllocateAndConstruct<MockDrawQuad>();
-
-  EXPECT_EQ(size, list.size());
-  EXPECT_EQ(dq_1, list.front());
-
-  // Make sure destructor is called once during clear, and won't be called
-  // again.
-  testing::MockFunction<void()> separator;
-  {
-    testing::InSequence s;
-    EXPECT_CALL(*dq_1, Destruct());
-    EXPECT_CALL(separator, Call());
-    EXPECT_CALL(*dq_1, Destruct()).Times(0);
-  }
-
-  list.ReplaceExistingElement<MockDrawQuadSubclass>(list.begin());
-  EXPECT_EQ(kMagicNumberToUseForDrawQuadTwo, dq_1->get_value());
-  separator.Call();
-
-  EXPECT_CALL(*dq_1, Destruct());
-  list.clear();
-}
-
-TEST(ListContainerTest, DestructorCalledOnceWhenErase) {
-  ListContainer<DrawQuad> list(kLargestQuadSize);
-  size_t size = 1;
-  MockDrawQuad* dq_1 = list.AllocateAndConstruct<MockDrawQuad>();
-
-  EXPECT_EQ(size, list.size());
-  EXPECT_EQ(dq_1, list.front());
-
-  // Make sure destructor is called once during clear, and won't be called
-  // again.
-  testing::MockFunction<void()> separator;
-  {
-    testing::InSequence s;
-    EXPECT_CALL(*dq_1, Destruct());
-    EXPECT_CALL(separator, Call());
-    EXPECT_CALL(*dq_1, Destruct()).Times(0);
-  }
-
-  list.EraseAndInvalidateAllPointers(list.begin());
-  separator.Call();
-}
-
-TEST(ListContainerTest, SimpleIndexAccessSharedQuadState) {
-  ListContainer<SharedQuadState> list;
-
-  size_t size = 3;
-  SharedQuadState* sqs_1 = list.AllocateAndConstruct<SharedQuadState>();
-  SharedQuadState* sqs_2 = list.AllocateAndConstruct<SharedQuadState>();
-  SharedQuadState* sqs_3 = list.AllocateAndConstruct<SharedQuadState>();
-
-  EXPECT_EQ(size, list.size());
-  EXPECT_EQ(sqs_1, list.front());
-  EXPECT_EQ(sqs_3, list.back());
-  EXPECT_EQ(list.front(), list.ElementAt(0));
-  EXPECT_EQ(sqs_2, list.ElementAt(1));
-  EXPECT_EQ(list.back(), list.ElementAt(2));
-}
-
-TEST(ListContainerTest, SimpleInsertionSharedQuadState) {
-  ListContainer<SharedQuadState> list;
-
-  size_t size = 3;
-  SharedQuadState* sqs_1 = list.AllocateAndConstruct<SharedQuadState>();
-  list.AllocateAndConstruct<SharedQuadState>();
-  SharedQuadState* sqs_3 = list.AllocateAndConstruct<SharedQuadState>();
-
-  EXPECT_EQ(size, list.size());
-  EXPECT_EQ(sqs_1, list.front());
-  EXPECT_EQ(sqs_3, list.back());
-}
-
-TEST(ListContainerTest, SimpleInsertionAndClearSharedQuadState) {
-  ListContainer<SharedQuadState> list;
-  EXPECT_TRUE(list.empty());
-  EXPECT_EQ(0u, list.size());
-
-  size_t size = 3;
-  SharedQuadState* sqs_1 = list.AllocateAndConstruct<SharedQuadState>();
-  list.AllocateAndConstruct<SharedQuadState>();
-  SharedQuadState* sqs_3 = list.AllocateAndConstruct<SharedQuadState>();
-
-  EXPECT_EQ(size, list.size());
-  EXPECT_EQ(sqs_1, list.front());
-  EXPECT_EQ(sqs_3, list.back());
-  EXPECT_FALSE(list.empty());
-
-  list.clear();
-  EXPECT_TRUE(list.empty());
-  EXPECT_EQ(0u, list.size());
-}
-
-TEST(ListContainerTest, SimpleInsertionClearAndInsertAgainSharedQuadState) {
-  ListContainer<SharedQuadState> list;
-  EXPECT_TRUE(list.empty());
-  EXPECT_EQ(0u, list.size());
-
-  size_t size = 2;
-  SharedQuadState* sqs_front = list.AllocateAndConstruct<SharedQuadState>();
-  SharedQuadState* sqs_back = list.AllocateAndConstruct<SharedQuadState>();
-
-  EXPECT_EQ(size, list.size());
-  EXPECT_EQ(sqs_front, list.front());
-  EXPECT_EQ(sqs_back, list.back());
-  EXPECT_FALSE(list.empty());
-
-  list.clear();
-  EXPECT_TRUE(list.empty());
-  EXPECT_EQ(0u, list.size());
-
-  size = 3;
-  sqs_front = list.AllocateAndConstruct<SharedQuadState>();
-  list.AllocateAndConstruct<SharedQuadState>();
-  sqs_back = list.AllocateAndConstruct<SharedQuadState>();
-
-  EXPECT_EQ(size, list.size());
-  EXPECT_EQ(sqs_front, list.front());
-  EXPECT_EQ(sqs_back, list.back());
-  EXPECT_FALSE(list.empty());
-}
-
-// This test is used to test when there is more than one allocation needed
-// for, ListContainer can still perform like normal vector.
-TEST(ListContainerTest,
-     SimpleInsertionTriggerMoreThanOneAllocationSharedQuadState) {
-  ListContainer<SharedQuadState> list(sizeof(SharedQuadState), 2);
-  std::vector<SharedQuadState*> sqs_list;
-  size_t size = 10;
-  for (size_t i = 0; i < size; ++i) {
-    sqs_list.push_back(list.AllocateAndConstruct<SharedQuadState>());
-  }
-  EXPECT_EQ(size, list.size());
-
-  ListContainer<SharedQuadState>::Iterator iter = list.begin();
-  for (std::vector<SharedQuadState*>::const_iterator sqs_iter =
-           sqs_list.begin();
-       sqs_iter != sqs_list.end(); ++sqs_iter) {
-    EXPECT_EQ(*sqs_iter, *iter);
-    ++iter;
-  }
-}
-
-TEST(ListContainerTest,
-     CorrectAllocationSizeForMoreThanOneAllocationSharedQuadState) {
-  // Constructor sets the allocation size to 2. Every time ListContainer needs
-  // to allocate again, it doubles allocation size. In this test, 10 elements is
-  // needed, thus ListContainerShould allocate spaces 2, 4 and 8 elements.
-  ListContainer<SharedQuadState> list(sizeof(SharedQuadState), 2);
-  std::vector<SharedQuadState*> sqs_list;
-  size_t size = 10;
-  for (size_t i = 0; i < size; ++i) {
-    // Before asking for a new element, space available without another
-    // allocation follows.
-    switch (i) {
-      case 2:
-      case 6:
-        EXPECT_EQ(0u, list.AvailableSizeWithoutAnotherAllocationForTesting());
-        break;
-      case 1:
-      case 5:
-        EXPECT_EQ(1u, list.AvailableSizeWithoutAnotherAllocationForTesting());
-        break;
-      case 0:
-      case 4:
-        EXPECT_EQ(2u, list.AvailableSizeWithoutAnotherAllocationForTesting());
-        break;
-      case 3:
-        EXPECT_EQ(3u, list.AvailableSizeWithoutAnotherAllocationForTesting());
-        break;
-      case 9:
-        EXPECT_EQ(5u, list.AvailableSizeWithoutAnotherAllocationForTesting());
-        break;
-      case 8:
-        EXPECT_EQ(6u, list.AvailableSizeWithoutAnotherAllocationForTesting());
-        break;
-      case 7:
-        EXPECT_EQ(7u, list.AvailableSizeWithoutAnotherAllocationForTesting());
-        break;
-      default:
-        break;
-    }
-    sqs_list.push_back(list.AllocateAndConstruct<SharedQuadState>());
-    // After asking for a new element, space available without another
-    // allocation follows.
-    switch (i) {
-      case 1:
-      case 5:
-        EXPECT_EQ(0u, list.AvailableSizeWithoutAnotherAllocationForTesting());
-        break;
-      case 0:
-      case 4:
-        EXPECT_EQ(1u, list.AvailableSizeWithoutAnotherAllocationForTesting());
-        break;
-      case 3:
-        EXPECT_EQ(2u, list.AvailableSizeWithoutAnotherAllocationForTesting());
-        break;
-      case 2:
-        EXPECT_EQ(3u, list.AvailableSizeWithoutAnotherAllocationForTesting());
-        break;
-      case 9:
-        EXPECT_EQ(4u, list.AvailableSizeWithoutAnotherAllocationForTesting());
-        break;
-      case 8:
-        EXPECT_EQ(5u, list.AvailableSizeWithoutAnotherAllocationForTesting());
-        break;
-      case 7:
-        EXPECT_EQ(6u, list.AvailableSizeWithoutAnotherAllocationForTesting());
-        break;
-      case 6:
-        EXPECT_EQ(7u, list.AvailableSizeWithoutAnotherAllocationForTesting());
-        break;
-      default:
-        break;
-    }
-  }
-  EXPECT_EQ(size, list.size());
-
-  ListContainer<SharedQuadState>::Iterator iter = list.begin();
-  for (std::vector<SharedQuadState*>::const_iterator sqs_iter =
-           sqs_list.begin();
-       sqs_iter != sqs_list.end(); ++sqs_iter) {
-    EXPECT_EQ(*sqs_iter, *iter);
-    ++iter;
-  }
-}
-
-TEST(ListContainerTest, SimpleIterationSharedQuadState) {
-  ListContainer<SharedQuadState> list;
-  std::vector<SharedQuadState*> sqs_list;
-  size_t size = 10;
-  for (size_t i = 0; i < size; ++i) {
-    sqs_list.push_back(list.AllocateAndConstruct<SharedQuadState>());
-  }
-  EXPECT_EQ(size, list.size());
-
-  size_t num_iters_in_list = 0;
-  {
-    std::vector<SharedQuadState*>::const_iterator sqs_iter = sqs_list.begin();
-    for (ListContainer<SharedQuadState>::Iterator iter = list.begin();
-         iter != list.end(); ++iter) {
-      EXPECT_EQ(*sqs_iter, *iter);
-      ++num_iters_in_list;
-      ++sqs_iter;
-    }
-  }
-
-  size_t num_iters_in_vector = 0;
-  {
-    ListContainer<SharedQuadState>::Iterator iter = list.begin();
-    for (std::vector<SharedQuadState*>::const_iterator sqs_iter =
-             sqs_list.begin();
-         sqs_iter != sqs_list.end(); ++sqs_iter) {
-      EXPECT_EQ(*sqs_iter, *iter);
-      ++num_iters_in_vector;
-      ++iter;
-    }
-  }
-
-  EXPECT_EQ(num_iters_in_vector, num_iters_in_list);
-}
-
-TEST(ListContainerTest, SimpleConstIteratorIterationSharedQuadState) {
-  ListContainer<SharedQuadState> list;
-  std::vector<const SharedQuadState*> sqs_list;
-  size_t size = 10;
-  for (size_t i = 0; i < size; ++i) {
-    sqs_list.push_back(list.AllocateAndConstruct<SharedQuadState>());
-  }
-  EXPECT_EQ(size, list.size());
-
-  {
-    std::vector<const SharedQuadState*>::const_iterator sqs_iter =
-        sqs_list.begin();
-    for (ListContainer<SharedQuadState>::ConstIterator iter = list.begin();
-         iter != list.end(); ++iter) {
-      EXPECT_TRUE(isConstSharedQuadStatePointer(*iter));
-      EXPECT_EQ(*sqs_iter, *iter);
-      ++sqs_iter;
-    }
-  }
-
-  {
-    std::vector<const SharedQuadState*>::const_iterator sqs_iter =
-        sqs_list.begin();
-    for (ListContainer<SharedQuadState>::Iterator iter = list.begin();
-         iter != list.end(); ++iter) {
-      EXPECT_FALSE(isConstSharedQuadStatePointer(*iter));
-      EXPECT_EQ(*sqs_iter, *iter);
-      ++sqs_iter;
-    }
-  }
-
-  {
-    ListContainer<SharedQuadState>::ConstIterator iter = list.begin();
-    for (std::vector<const SharedQuadState*>::const_iterator sqs_iter =
-             sqs_list.begin();
-         sqs_iter != sqs_list.end(); ++sqs_iter) {
-      EXPECT_EQ(*sqs_iter, *iter);
-      ++iter;
-    }
-  }
-}
-
-TEST(ListContainerTest, SimpleReverseInsertionSharedQuadState) {
-  ListContainer<SharedQuadState> list;
-  std::vector<SharedQuadState*> sqs_list;
-  size_t size = 10;
-  for (size_t i = 0; i < size; ++i) {
-    sqs_list.push_back(list.AllocateAndConstruct<SharedQuadState>());
-  }
-  EXPECT_EQ(size, list.size());
-
-  {
-    std::vector<SharedQuadState*>::const_reverse_iterator sqs_iter =
-        sqs_list.rbegin();
-    for (ListContainer<SharedQuadState>::ReverseIterator iter = list.rbegin();
-         iter != list.rend(); ++iter) {
-      EXPECT_EQ(*sqs_iter, *iter);
-      ++sqs_iter;
-    }
-  }
-
-  {
-    ListContainer<SharedQuadState>::ReverseIterator iter = list.rbegin();
-    for (std::vector<SharedQuadState*>::reverse_iterator sqs_iter =
-             sqs_list.rbegin();
-         sqs_iter != sqs_list.rend(); ++sqs_iter) {
-      EXPECT_EQ(*sqs_iter, *iter);
-      ++iter;
-    }
-  }
-}
-
-TEST(ListContainerTest, SimpleDeletion) {
-  ListContainer<DrawQuad> list(kLargestQuadSize);
-  std::vector<SimpleDrawQuad*> sdq_list;
-  size_t size = 10;
-  for (size_t i = 0; i < size; ++i) {
-    sdq_list.push_back(list.AllocateAndConstruct<SimpleDrawQuad>());
-    sdq_list.back()->set_value(i);
-  }
-  EXPECT_EQ(size, list.size());
-
-  list.EraseAndInvalidateAllPointers(list.begin());
-  --size;
-  EXPECT_EQ(size, list.size());
-  int i = 1;
-  for (ListContainer<DrawQuad>::Iterator iter = list.begin();
-       iter != list.end(); ++iter) {
-    EXPECT_EQ(i, static_cast<SimpleDrawQuad*>(*iter)->get_value());
-    ++i;
-  }
-}
-
-TEST(ListContainerTest, DeletionAllInAllocation) {
-  const size_t kReserve = 10;
-  ListContainer<DrawQuad> list(kLargestQuadSize, kReserve);
-  std::vector<SimpleDrawQuad*> sdq_list;
-  // Add enough quads to cause another allocation.
-  for (size_t i = 0; i < kReserve + 1; ++i) {
-    sdq_list.push_back(list.AllocateAndConstruct<SimpleDrawQuad>());
-    sdq_list.back()->set_value(static_cast<int>(i));
-  }
-  EXPECT_EQ(kReserve + 1, list.size());
-
-  // Remove everything in the first allocation.
-  for (size_t i = 0; i < kReserve; ++i)
-    list.EraseAndInvalidateAllPointers(list.begin());
-  EXPECT_EQ(1u, list.size());
-
-  // The last quad is left.
-  SimpleDrawQuad* quad = static_cast<SimpleDrawQuad*>(*list.begin());
-  EXPECT_EQ(static_cast<int>(kReserve), quad->get_value());
-
-  // Remove the quad from the 2nd allocation.
-  list.EraseAndInvalidateAllPointers(list.begin());
-  EXPECT_EQ(0u, list.size());
-}
-
-TEST(ListContainerTest, DeletionAllInAllocationReversed) {
-  const size_t kReserve = 10;
-  ListContainer<DrawQuad> list(kLargestQuadSize, kReserve);
-  std::vector<SimpleDrawQuad*> sdq_list;
-  // Add enough quads to cause another allocation.
-  for (size_t i = 0; i < kReserve + 1; ++i) {
-    sdq_list.push_back(list.AllocateAndConstruct<SimpleDrawQuad>());
-    sdq_list.back()->set_value(static_cast<int>(i));
-  }
-  EXPECT_EQ(kReserve + 1, list.size());
-
-  // Remove everything in the 2nd allocation.
-  auto it = list.begin();
-  for (size_t i = 0; i < kReserve; ++i)
-    ++it;
-  list.EraseAndInvalidateAllPointers(it);
-
-  // The 2nd-last quad is next, and the rest of the quads exist.
-  size_t i = kReserve - 1;
-  for (auto it = list.rbegin(); it != list.rend(); ++it) {
-    SimpleDrawQuad* quad = static_cast<SimpleDrawQuad*>(*it);
-    EXPECT_EQ(static_cast<int>(i), quad->get_value());
-    --i;
-  }
-
-  // Can forward iterate too.
-  i = 0;
-  for (auto it = list.begin(); it != list.end(); ++it) {
-    SimpleDrawQuad* quad = static_cast<SimpleDrawQuad*>(*it);
-    EXPECT_EQ(static_cast<int>(i), quad->get_value());
-    ++i;
-  }
-
-  // Remove the last thing from the 1st allocation.
-  it = list.begin();
-  for (size_t i = 0; i < kReserve - 1; ++i)
-    ++it;
-  list.EraseAndInvalidateAllPointers(it);
-
-  // The 2nd-last quad is next, and the rest of the quads exist.
-  i = kReserve - 2;
-  for (auto it = list.rbegin(); it != list.rend(); ++it) {
-    SimpleDrawQuad* quad = static_cast<SimpleDrawQuad*>(*it);
-    EXPECT_EQ(static_cast<int>(i), quad->get_value());
-    --i;
-  }
-
-  // Can forward iterate too.
-  i = 0;
-  for (auto it = list.begin(); it != list.end(); ++it) {
-    SimpleDrawQuad* quad = static_cast<SimpleDrawQuad*>(*it);
-    EXPECT_EQ(static_cast<int>(i), quad->get_value());
-    ++i;
-  }
-}
-
-TEST(ListContainerTest, SimpleIterationAndManipulation) {
-  ListContainer<DrawQuad> list(kLargestQuadSize);
-  std::vector<SimpleDrawQuad*> sdq_list;
-  size_t size = 10;
-  for (size_t i = 0; i < size; ++i) {
-    SimpleDrawQuad* simple_dq = list.AllocateAndConstruct<SimpleDrawQuad>();
-    sdq_list.push_back(simple_dq);
-  }
-  EXPECT_EQ(size, list.size());
-
-  ListContainer<DrawQuad>::Iterator iter = list.begin();
-  for (int i = 0; i < 10; ++i) {
-    static_cast<SimpleDrawQuad*>(*iter)->set_value(i);
-    ++iter;
-  }
-
-  int i = 0;
-  for (std::vector<SimpleDrawQuad*>::const_iterator sdq_iter = sdq_list.begin();
-       sdq_iter < sdq_list.end(); ++sdq_iter) {
-    EXPECT_EQ(i, (*sdq_iter)->get_value());
-    ++i;
-  }
-}
-
-TEST(ListContainerTest, SimpleManipulationWithIndexSimpleDrawQuad) {
-  ListContainer<DrawQuad> list(kLargestQuadSize);
-  std::vector<SimpleDrawQuad*> dq_list;
-  size_t size = 10;
-  for (size_t i = 0; i < size; ++i) {
-    dq_list.push_back(list.AllocateAndConstruct<SimpleDrawQuad>());
-  }
-  EXPECT_EQ(size, list.size());
-
-  for (size_t i = 0; i < size; ++i) {
-    static_cast<SimpleDrawQuad*>(list.ElementAt(i))->set_value(i);
-  }
-
-  int i = 0;
-  for (std::vector<SimpleDrawQuad*>::const_iterator dq_iter = dq_list.begin();
-       dq_iter != dq_list.end(); ++dq_iter, ++i) {
-    EXPECT_EQ(i, (*dq_iter)->get_value());
-  }
-}
-
-TEST(ListContainerTest,
-     SimpleManipulationWithIndexMoreThanOneAllocationSimpleDrawQuad) {
-  ListContainer<DrawQuad> list(LargestDrawQuadSize(), 2);
-  std::vector<SimpleDrawQuad*> dq_list;
-  size_t size = 10;
-  for (size_t i = 0; i < size; ++i) {
-    dq_list.push_back(list.AllocateAndConstruct<SimpleDrawQuad>());
-  }
-  EXPECT_EQ(size, list.size());
-
-  for (size_t i = 0; i < size; ++i) {
-    static_cast<SimpleDrawQuad*>(list.ElementAt(i))->set_value(i);
-  }
-
-  int i = 0;
-  for (std::vector<SimpleDrawQuad*>::const_iterator dq_iter = dq_list.begin();
-       dq_iter != dq_list.end(); ++dq_iter, ++i) {
-    EXPECT_EQ(i, (*dq_iter)->get_value());
-  }
-}
-
-TEST(ListContainerTest,
-     SimpleIterationAndReverseIterationWithIndexSharedQuadState) {
-  ListContainer<SharedQuadState> list;
-  std::vector<SharedQuadState*> sqs_list;
-  size_t size = 10;
-  for (size_t i = 0; i < size; ++i) {
-    sqs_list.push_back(list.AllocateAndConstruct<SharedQuadState>());
-  }
-  EXPECT_EQ(size, list.size());
-
-  size_t i = 0;
-  for (ListContainer<SharedQuadState>::Iterator iter = list.begin();
-       iter != list.end(); ++iter) {
-    EXPECT_EQ(i, iter.index());
-    ++i;
-  }
-
-  i = 0;
-  for (ListContainer<SharedQuadState>::ReverseIterator iter = list.rbegin();
-       iter != list.rend(); ++iter) {
-    EXPECT_EQ(i, iter.index());
-    ++i;
-  }
-}
-
-}  // namespace
-}  // namespace cc
diff --git a/cc/raster/one_copy_tile_task_worker_pool.cc b/cc/raster/one_copy_tile_task_worker_pool.cc
index ebc2301..dd8937c 100644
--- a/cc/raster/one_copy_tile_task_worker_pool.cc
+++ b/cc/raster/one_copy_tile_task_worker_pool.cc
@@ -99,9 +99,6 @@
   DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl);
 };
 
-// Flush interval when performing copy operations.
-const int kCopyFlushPeriod = 4;
-
 // Number of in-flight copy operations to allow.
 const int kMaxCopyOperations = 32;
 
@@ -160,6 +157,7 @@
       last_flushed_copy_operation_(0),
       lock_(),
       copy_operation_count_cv_(&lock_),
+      bytes_scheduled_since_last_flush_(0),
       issued_copy_operation_count_(0),
       next_copy_operation_sequence_(1),
       check_for_completed_copy_operations_pending_(false),
@@ -401,13 +399,19 @@
     // Acquire a sequence number for this copy operation.
     sequence = next_copy_operation_sequence_++;
 
+    // Increment |bytes_scheduled_since_last_flush_| by the amount of memory
+    // used for this copy operation.
+    bytes_scheduled_since_last_flush_ += rows_to_copy * bytes_per_row;
+
     // Post task that will advance last flushed copy operation to |sequence|
-    // if we have reached the flush period.
-    if ((sequence % kCopyFlushPeriod) == 0) {
+    // when |bytes_scheduled_since_last_flush_| has reached
+    // |max_bytes_per_copy_operation_|.
+    if (bytes_scheduled_since_last_flush_ >= max_bytes_per_copy_operation_) {
       task_runner_->PostTask(
           FROM_HERE,
           base::Bind(&OneCopyTileTaskWorkerPool::AdvanceLastFlushedCopyTo,
                      weak_ptr_factory_.GetWeakPtr(), sequence));
+      bytes_scheduled_since_last_flush_ = 0;
     }
   }
 
diff --git a/cc/raster/one_copy_tile_task_worker_pool.h b/cc/raster/one_copy_tile_task_worker_pool.h
index 5998228..a808fc8 100644
--- a/cc/raster/one_copy_tile_task_worker_pool.h
+++ b/cc/raster/one_copy_tile_task_worker_pool.h
@@ -140,6 +140,7 @@
   base::Lock lock_;
   // |lock_| must be acquired when accessing the following members.
   base::ConditionVariable copy_operation_count_cv_;
+  int bytes_scheduled_since_last_flush_;
   size_t issued_copy_operation_count_;
   CopyOperation::Deque pending_copy_operations_;
   CopySequenceNumber next_copy_operation_sequence_;
diff --git a/cc/raster/pixel_buffer_tile_task_worker_pool.cc b/cc/raster/pixel_buffer_tile_task_worker_pool.cc
index 633a874..0132fe0 100644
--- a/cc/raster/pixel_buffer_tile_task_worker_pool.cc
+++ b/cc/raster/pixel_buffer_tile_task_worker_pool.cc
@@ -431,7 +431,10 @@
     DCHECK(state_it != raster_task_states_.end());
     RasterTaskState& state = *state_it;
 
-    bytes_pending_upload_ -= task->resource()->bytes();
+    // We can use UncheckedMemorySizeBytes here, since these tasks come from
+    // tiles, the size of which is controlled by the compositor.
+    bytes_pending_upload_ -= Resource::UncheckedMemorySizeBytes(
+        task->resource()->size(), task->resource()->format());
 
     task->WillComplete();
     task->CompleteOnOriginThread(this);
@@ -537,7 +540,10 @@
     // but if it's the only task allow it to complete no matter what its size,
     // to prevent starvation of the task queue.
     size_t new_bytes_pending_upload = bytes_pending_upload;
-    new_bytes_pending_upload += task->resource()->bytes();
+    // We can use UncheckedMemorySizeBytes here, since these tasks come from
+    // tiles, the size of which is controlled by the compositor.
+    new_bytes_pending_upload += Resource::UncheckedMemorySizeBytes(
+        task->resource()->size(), task->resource()->format());
     if (new_bytes_pending_upload > max_bytes_pending_upload_ &&
         bytes_pending_upload) {
       did_throttle_raster_tasks |= item.task_sets;
@@ -701,7 +707,10 @@
     resource_provider_->BeginSetPixels(raster_task->resource()->id());
     has_performed_uploads_since_last_flush_ = true;
 
-    bytes_pending_upload_ += raster_task->resource()->bytes();
+    // We can use UncheckedMemorySizeBytes here, since these tasks come from
+    // tiles, the size of which is controlled by the compositor.
+    bytes_pending_upload_ += Resource::UncheckedMemorySizeBytes(
+        raster_task->resource()->size(), raster_task->resource()->format());
     raster_tasks_with_pending_upload_.push_back(raster_task);
     state.type = RasterTaskState::UPLOADING;
   }
diff --git a/cc/raster/tile_task_worker_pool_unittest.cc b/cc/raster/tile_task_worker_pool_unittest.cc
index 09db4a7c..76e5fe4d 100644
--- a/cc/raster/tile_task_worker_pool_unittest.cc
+++ b/cc/raster/tile_task_worker_pool_unittest.cc
@@ -406,7 +406,9 @@
         ScopedResource::Create(resource_provider_.get()));
     resource->Allocate(size, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
                        RGBA_8888);
-    EXPECT_GE(resource->bytes(), kMaxTransferBufferUsageBytes);
+    EXPECT_GE(Resource::UncheckedMemorySizeBytes(resource->size(),
+                                                 resource->format()),
+              kMaxTransferBufferUsageBytes);
   }
 
   AppendTask(0u, size);
diff --git a/cc/resources/prioritized_resource.cc b/cc/resources/prioritized_resource.cc
index 968083c..1fe66b5 100644
--- a/cc/resources/prioritized_resource.cc
+++ b/cc/resources/prioritized_resource.cc
@@ -25,7 +25,9 @@
       is_self_managed_(false),
       backing_(NULL),
       manager_(NULL) {
-  bytes_ = Resource::MemorySizeBytes(size, format);
+  // We can use UncheckedMemorySizeBytes here, since the size is controlled by
+  // the compositor (used for tiles).
+  bytes_ = Resource::UncheckedMemorySizeBytes(size, format);
   if (manager)
     manager->RegisterTexture(this);
 }
@@ -51,7 +53,9 @@
     is_above_priority_cutoff_ = false;
     format_ = format;
     size_ = size;
-    bytes_ = Resource::MemorySizeBytes(size, format);
+    // We can use UncheckedMemorySizeBytes here, since the size is controlled by
+    // the compositor (used for tiles).
+    bytes_ = Resource::UncheckedMemorySizeBytes(size, format);
     DCHECK(manager_ || !backing_);
     if (manager_)
       manager_->ReturnBackingTexture(this);
diff --git a/cc/resources/prioritized_resource_manager.cc b/cc/resources/prioritized_resource_manager.cc
index dc17862..9240121 100644
--- a/cc/resources/prioritized_resource_manager.cc
+++ b/cc/resources/prioritized_resource_manager.cc
@@ -256,8 +256,7 @@
   if (!backing) {
     EvictBackingsToReduceMemory(memory_available_bytes_ - texture->bytes(),
                                 PriorityCalculator::AllowEverythingCutoff(),
-                                EVICT_ONLY_RECYCLABLE,
-                                DO_NOT_UNLINK_BACKINGS,
+                                EVICT_ONLY_RECYCLABLE, DO_NOT_UNLINK_BACKINGS,
                                 resource_provider);
     backing =
         CreateBacking(texture->size(), texture->format(), resource_provider);
@@ -323,7 +322,8 @@
       break;
     if ((*it)->in_parent_compositor())
       continue;
-    wasted_memory += (*it)->bytes();
+    wasted_memory +=
+        Resource::UncheckedMemorySizeBytes((*it)->size(), (*it)->format());
   }
   size_t wasted_memory_to_allow = memory_available_bytes_ / 10;
   // If the external priority cutoff indicates that unused memory should be
@@ -454,7 +454,8 @@
       ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
   PrioritizedResource::Backing* backing = new PrioritizedResource::Backing(
       resource_id, resource_provider, size, format);
-  memory_use_bytes_ += backing->bytes();
+  memory_use_bytes_ +=
+      Resource::UncheckedMemorySizeBytes(backing->size(), backing->format());
   return backing;
 }
 
@@ -470,7 +471,8 @@
   // we can delete the resource while the main thread is running, but we cannot
   // unlink backings while the main thread is running.
   backing->DeleteResource(resource_provider);
-  memory_use_bytes_ -= backing->bytes();
+  memory_use_bytes_ -=
+      Resource::UncheckedMemorySizeBytes(backing->size(), backing->format());
   backings_.pop_front();
   base::AutoLock scoped_lock(evicted_backings_lock_);
   evicted_backings_.push_back(backing);
diff --git a/cc/resources/prioritized_resource_unittest.cc b/cc/resources/prioritized_resource_unittest.cc
index cd1221f..0e0f32b 100644
--- a/cc/resources/prioritized_resource_unittest.cc
+++ b/cc/resources/prioritized_resource_unittest.cc
@@ -39,7 +39,7 @@
   }
 
   size_t TexturesMemorySize(size_t texture_count) {
-    return Resource::MemorySizeBytes(texture_size_, texture_format_) *
+    return Resource::UncheckedMemorySizeBytes(texture_size_, texture_format_) *
            texture_count;
   }
 
diff --git a/cc/resources/resource.cc b/cc/resources/resource.cc
deleted file mode 100644
index 9bbcd4f..0000000
--- a/cc/resources/resource.cc
+++ /dev/null
@@ -1,17 +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.
-
-#include "cc/resources/resource.h"
-
-namespace cc {
-
-size_t Resource::bytes() const {
-  if (size_.IsEmpty())
-    return 0;
-
-  return MemorySizeBytes(size_, format_);
-}
-
-
-}  // namespace cc
diff --git a/cc/resources/resource.h b/cc/resources/resource.h
index 0e3c3df..f9138fb 100644
--- a/cc/resources/resource.h
+++ b/cc/resources/resource.h
@@ -5,6 +5,7 @@
 #ifndef CC_RESOURCES_RESOURCE_H_
 #define CC_RESOURCES_RESOURCE_H_
 
+#include "base/numerics/safe_math.h"
 #include "cc/base/cc_export.h"
 #include "cc/resources/resource_provider.h"
 #include "ui/gfx/geometry/size.h"
@@ -13,7 +14,7 @@
 
 class CC_EXPORT Resource {
  public:
-  Resource() : id_(0) {}
+  Resource() : id_(0), format_(RGBA_8888) {}
   Resource(unsigned id, const gfx::Size& size, ResourceFormat format)
       : id_(id),
         size_(size),
@@ -22,14 +23,36 @@
   ResourceId id() const { return id_; }
   gfx::Size size() const { return size_; }
   ResourceFormat format() const { return format_; }
-  size_t bytes() const;
 
-  inline static size_t MemorySizeBytes(const gfx::Size& size,
+  // Return true if the call to UncheckedMemorySizeBytes would return a value
+  // that fits in a size_t.
+  static bool VerifySizeInBytes(const gfx::Size& size, ResourceFormat format) {
+    base::CheckedNumeric<size_t> checked_value = BitsPerPixel(format);
+    checked_value *= size.width();
+    checked_value *= size.height();
+    if (!checked_value.IsValid())
+      return false;
+    size_t value = checked_value.ValueOrDie();
+    if ((value % 8) != 0)
+      return false;
+    return true;
+  }
+
+  static size_t CheckedMemorySizeBytes(const gfx::Size& size,
                                        ResourceFormat format) {
-    DCHECK_EQ(0, (BitsPerPixel(format) * size.width() * size.height()) % 8);
-    // TODO(vmpstr): Make this function overflow safe. crbug.com/495867
-    return static_cast<size_t>(
-        (BitsPerPixel(format) * size.width() * size.height()) / 8);
+    DCHECK(VerifySizeInBytes(size, format));
+    base::CheckedNumeric<size_t> checked_value = BitsPerPixel(format);
+    checked_value *= size.width();
+    checked_value *= size.height();
+    checked_value /= 8;
+    return checked_value.ValueOrDie();
+  }
+
+  inline static size_t UncheckedMemorySizeBytes(const gfx::Size& size,
+                                                ResourceFormat format) {
+    DCHECK(VerifySizeInBytes(size, format));
+    return static_cast<size_t>(BitsPerPixel(format)) * size.width() *
+           size.height() / 8;
   }
 
  protected:
diff --git a/cc/resources/resource_pool.cc b/cc/resources/resource_pool.cc
index 08e2f4e..f5c7167 100644
--- a/cc/resources/resource_pool.cc
+++ b/cc/resources/resource_pool.cc
@@ -47,7 +47,8 @@
       continue;
 
     unused_resources_.erase(it);
-    unused_memory_usage_bytes_ -= resource->bytes();
+    unused_memory_usage_bytes_ -=
+        Resource::UncheckedMemorySizeBytes(size, format);
     return make_scoped_ptr(resource);
   }
 
@@ -55,7 +56,9 @@
       ScopedResource::Create(resource_provider_);
   resource->AllocateManaged(size, target_, format);
 
-  memory_usage_bytes_ += resource->bytes();
+  DCHECK(Resource::VerifySizeInBytes(resource->size(), resource->format()));
+  memory_usage_bytes_ +=
+      Resource::UncheckedMemorySizeBytes(resource->size(), resource->format());
   ++resource_count_;
   return resource.Pass();
 }
@@ -75,7 +78,8 @@
   DCHECK(resource_provider_->CanLockForWrite(resource->id()));
 
   unused_resources_.erase(it);
-  unused_memory_usage_bytes_ -= resource->bytes();
+  unused_memory_usage_bytes_ -=
+      Resource::UncheckedMemorySizeBytes(resource->size(), resource->format());
   return make_scoped_ptr(resource);
 }
 
@@ -108,8 +112,10 @@
     // memory is necessarily returned to the OS.
     ScopedResource* resource = unused_resources_.front().resource;
     unused_resources_.pop_front();
-    memory_usage_bytes_ -= resource->bytes();
-    unused_memory_usage_bytes_ -= resource->bytes();
+    size_t resource_bytes = Resource::UncheckedMemorySizeBytes(
+        resource->size(), resource->format());
+    memory_usage_bytes_ -= resource_bytes;
+    unused_memory_usage_bytes_ -= resource_bytes;
     --resource_count_;
     delete resource;
   }
@@ -145,7 +151,8 @@
 
 void ResourcePool::DidFinishUsingResource(ScopedResource* resource,
                                           uint64_t content_id) {
-  unused_memory_usage_bytes_ += resource->bytes();
+  unused_memory_usage_bytes_ +=
+      Resource::UncheckedMemorySizeBytes(resource->size(), resource->format());
   unused_resources_.push_back(PoolResource(resource, content_id));
 }
 
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 07ce62c..449e04b 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -9,6 +9,7 @@
 
 #include "base/containers/hash_tables.h"
 #include "base/metrics/histogram.h"
+#include "base/numerics/safe_math.h"
 #include "base/stl_util.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -772,12 +773,13 @@
     gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
 
     if (resource->format == ETC1) {
-      // TODO(vmpstr): Make this overflow safe. crbug.com/495867
-      int num_bytes =
-          image_size.width() * image_size.height() * BitsPerPixel(ETC1) / 8;
+      base::CheckedNumeric<int> num_bytes = BitsPerPixel(ETC1);
+      num_bytes *= image_size.width();
+      num_bytes *= image_size.height();
+      num_bytes /= 8;
       gl->CompressedTexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(ETC1),
                                image_size.width(), image_size.height(), 0,
-                               num_bytes, image);
+                               num_bytes.ValueOrDie(), image);
     } else {
       gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_size.width(),
                         image_size.height(), GLDataFormat(resource->format),
diff --git a/cc/resources/scoped_resource_unittest.cc b/cc/resources/scoped_resource_unittest.cc
index 73df3a6a..b37f09d 100644
--- a/cc/resources/scoped_resource_unittest.cc
+++ b/cc/resources/scoped_resource_unittest.cc
@@ -32,7 +32,8 @@
 
   // New scoped textures do not have a size yet.
   EXPECT_EQ(gfx::Size(), texture->size());
-  EXPECT_EQ(0u, texture->bytes());
+  EXPECT_EQ(0u, Resource::UncheckedMemorySizeBytes(texture->size(),
+                                                   texture->format()));
 }
 
 TEST(ScopedResourceTest, CreateScopedResource) {
@@ -51,7 +52,8 @@
 
   // The texture has an allocated byte-size now.
   size_t expected_bytes = 30 * 30 * 4;
-  EXPECT_EQ(expected_bytes, texture->bytes());
+  EXPECT_EQ(expected_bytes, Resource::UncheckedMemorySizeBytes(
+                                texture->size(), texture->format()));
 
   EXPECT_LT(0u, texture->id());
   EXPECT_EQ(static_cast<unsigned>(RGBA_8888), texture->format());
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 8b5ccca1..0d90c68214 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -226,6 +226,7 @@
 }
 
 void Scheduler::DidSwapBuffersComplete() {
+  DCHECK_GT(state_machine_.pending_swaps(), 0) << AsValue()->ToString();
   state_machine_.DidSwapBuffersComplete();
   ProcessScheduledActions();
 }
@@ -772,14 +773,16 @@
                    estimated_parent_draw_time_.InMillisecondsF());
   state->SetBoolean("last_set_needs_begin_frame_",
                     frame_source_->NeedsBeginFrames());
-  state->SetInteger("begin_retro_frame_args_",
+  state->SetInteger("begin_retro_frame_args",
                     static_cast<int>(begin_retro_frame_args_.size()));
-  state->SetBoolean("begin_retro_frame_task_",
+  state->SetBoolean("begin_retro_frame_task",
                     !begin_retro_frame_task_.IsCancelled());
-  state->SetBoolean("begin_impl_frame_deadline_task_",
+  state->SetBoolean("begin_impl_frame_deadline_task",
                     !begin_impl_frame_deadline_task_.IsCancelled());
-  state->SetBoolean("advance_commit_state_task_",
+  state->SetBoolean("advance_commit_state_task",
                     !advance_commit_state_task_.IsCancelled());
+  state->SetString("inside_action",
+                   SchedulerStateMachine::ActionToString(inside_action_));
   state->BeginDictionary("begin_impl_frame_args");
   begin_impl_frame_tracker_.AsValueInto(Now(), state);
   state->EndDictionary();
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index 933b966b..6d31583 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -34,6 +34,7 @@
       consecutive_checkerboard_animations_(0),
       max_pending_swaps_(1),
       pending_swaps_(0),
+      swaps_with_current_output_surface_(0),
       needs_redraw_(false),
       needs_animate_(false),
       needs_prepare_tiles_(false),
@@ -217,6 +218,8 @@
                     consecutive_checkerboard_animations_);
   state->SetInteger("max_pending_swaps_", max_pending_swaps_);
   state->SetInteger("pending_swaps_", pending_swaps_);
+  state->SetInteger("swaps_with_current_output_surface",
+                    swaps_with_current_output_surface_);
   state->SetBoolean("needs_redraw", needs_redraw_);
   state->SetBoolean("needs_animate_", needs_animate_);
   state->SetBoolean("needs_prepare_tiles", needs_prepare_tiles_);
@@ -1019,6 +1022,8 @@
 
 void SchedulerStateMachine::DidSwapBuffers() {
   pending_swaps_++;
+  swaps_with_current_output_surface_++;
+
   DCHECK_LE(pending_swaps_, max_pending_swaps_);
 
   did_perform_swap_in_last_draw_ = true;
@@ -1026,7 +1031,6 @@
 }
 
 void SchedulerStateMachine::DidSwapBuffersComplete() {
-  DCHECK_GT(pending_swaps_, 0);
   pending_swaps_--;
 }
 
@@ -1144,6 +1148,7 @@
   }
   did_create_and_initialize_first_output_surface_ = true;
   pending_swaps_ = 0;
+  swaps_with_current_output_surface_ = 0;
 }
 
 void SchedulerStateMachine::NotifyBeginMainFrameStarted() {
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h
index 238c08c..d57cc00 100644
--- a/cc/scheduler/scheduler_state_machine.h
+++ b/cc/scheduler/scheduler_state_machine.h
@@ -179,6 +179,8 @@
   // Notification from the OutputSurface that a swap has been consumed.
   void DidSwapBuffersComplete();
 
+  int pending_swaps() const { return pending_swaps_; }
+
   // Indicates whether to prioritize impl thread latency (i.e., animation
   // smoothness) over new content activation.
   void SetImplLatencyTakesPriority(bool impl_latency_takes_priority);
@@ -320,6 +322,7 @@
   int consecutive_checkerboard_animations_;
   int max_pending_swaps_;
   int pending_swaps_;
+  int swaps_with_current_output_surface_;
   bool needs_redraw_;
   bool needs_animate_;
   bool needs_prepare_tiles_;
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index a9cef08..294dc5b 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -88,6 +88,10 @@
     scheduler_->EntireDisplayDamaged(current_surface_id_);
 }
 
+void Display::SetExternalClip(const gfx::Rect& clip) {
+  external_clip_ = clip;
+}
+
 void Display::InitializeRenderer() {
   if (resource_provider_)
     return;
@@ -180,7 +184,8 @@
 
   if (should_draw) {
     gfx::Rect device_viewport_rect = gfx::Rect(current_surface_size_);
-    gfx::Rect device_clip_rect = device_viewport_rect;
+    gfx::Rect device_clip_rect =
+        external_clip_.IsEmpty() ? device_viewport_rect : external_clip_;
     bool disable_picture_quad_image_filtering = false;
 
     renderer_->DecideRenderPassAllocationsForFrame(
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h
index ab48181..b849b461 100644
--- a/cc/surfaces/display.h
+++ b/cc/surfaces/display.h
@@ -62,6 +62,7 @@
   // what scale this was rendered at.
   void SetSurfaceId(SurfaceId id, float device_scale_factor);
   void Resize(const gfx::Size& new_size);
+  void SetExternalClip(const gfx::Rect& clip);
 
   SurfaceId CurrentSurfaceId();
 
@@ -106,6 +107,7 @@
   gfx::Size current_surface_size_;
   float device_scale_factor_;
   bool swapped_since_resize_;
+  gfx::Rect external_clip_;
   scoped_ptr<OutputSurface> output_surface_;
   DisplayScheduler* scheduler_;
   scoped_ptr<ResourceProvider> resource_provider_;
diff --git a/cc/surfaces/display_scheduler.cc b/cc/surfaces/display_scheduler.cc
index a9eeade..ed81da0d 100644
--- a/cc/surfaces/display_scheduler.cc
+++ b/cc/surfaces/display_scheduler.cc
@@ -127,12 +127,6 @@
   TRACE_EVENT2("cc", "DisplayScheduler::BeginFrame", "args", args.AsValue(),
                "now", now);
 
-  // Only service missed BeginFrames if they haven't already expired.
-  base::TimeTicks adjusted_deadline =
-      args.deadline - BeginFrameArgs::DefaultEstimatedParentDrawTime();
-  if (args.type == BeginFrameArgs::MISSED && now > adjusted_deadline)
-    return false;
-
   // If we get another BeginFrame before the previous deadline,
   // synchronously trigger the previous deadline before progressing.
   if (inside_begin_frame_deadline_interval_) {
@@ -141,7 +135,8 @@
 
   // Schedule the deadline.
   current_begin_frame_args_ = args;
-  current_begin_frame_args_.deadline = adjusted_deadline;
+  current_begin_frame_args_.deadline -=
+      BeginFrameArgs::DefaultEstimatedParentDrawTime();
   inside_begin_frame_deadline_interval_ = true;
   ScheduleBeginFrameDeadline();
 
@@ -156,7 +151,7 @@
 
   if (pending_swaps_ >= max_pending_swaps_) {
     TRACE_EVENT_INSTANT0("cc", "Swap throttled", TRACE_EVENT_SCOPE_THREAD);
-    return base::TimeTicks();
+    return current_begin_frame_args_.deadline;
   }
 
   if (!needs_draw_) {
diff --git a/cc/surfaces/display_scheduler_unittest.cc b/cc/surfaces/display_scheduler_unittest.cc
index 7fedbc77..7526c2f 100644
--- a/cc/surfaces/display_scheduler_unittest.cc
+++ b/cc/surfaces/display_scheduler_unittest.cc
@@ -85,8 +85,7 @@
   void BeginFrameForTest() {
     base::TimeTicks frame_time = now_src_->Now();
     base::TimeDelta interval = BeginFrameArgs::DefaultInterval();
-    base::TimeTicks deadline = frame_time + interval -
-                               BeginFrameArgs::DefaultEstimatedParentDrawTime();
+    base::TimeTicks deadline = frame_time + interval;
     fake_begin_frame_source_.TestOnBeginFrame(
         BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline,
                                interval, BeginFrameArgs::NORMAL));
@@ -250,7 +249,7 @@
 TEST_F(DisplaySchedulerTest, DidSwapBuffers) {
   SurfaceId sid1(1);
   SurfaceId sid2(2);
-  base::TimeTicks late_deadline;
+  base::TimeTicks expected_deadline;
 
   // Get scheduler to detect surface 1 and 2 as active.
   BeginFrameForTest();
@@ -273,13 +272,16 @@
   EXPECT_EQ(3, client_->draw_and_swap_count());
   scheduler_->DidSwapBuffers();
 
-  // Deadline triggers early when swap throttled.
+  // Deadline triggers normally when swap throttled.
+  expected_deadline =
+      fake_begin_frame_source_.TestLastUsedBeginFrameArgs().deadline -
+      BeginFrameArgs::DefaultEstimatedParentDrawTime();
   BeginFrameForTest();
   // Damage surface 1, but not surface 2 so we avoid triggering deadline
   // early because all surfaces are ready.
   scheduler_->SurfaceDamaged(sid1);
-  EXPECT_EQ(scheduler_->DesiredBeginFrameDeadlineTimeForTest(),
-            base::TimeTicks());
+  EXPECT_EQ(expected_deadline,
+            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
 
   // Don't draw and swap in deadline while swap throttled.
   EXPECT_EQ(3, client_->draw_and_swap_count());
@@ -288,12 +290,13 @@
 
   // Deadline triggers normally once not swap throttled.
   // Damage from previous BeginFrame should cary over, so don't damage again.
-  late_deadline = now_src().Now() + BeginFrameArgs::DefaultInterval();
+  expected_deadline =
+      fake_begin_frame_source_.TestLastUsedBeginFrameArgs().deadline -
+      BeginFrameArgs::DefaultEstimatedParentDrawTime();
   scheduler_->DidSwapBuffersComplete();
   BeginFrameForTest();
-  EXPECT_GT(scheduler_->DesiredBeginFrameDeadlineTimeForTest(),
-            now_src().Now());
-  EXPECT_LT(scheduler_->DesiredBeginFrameDeadlineTimeForTest(), late_deadline);
+  EXPECT_EQ(expected_deadline,
+            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
   // Still waiting for surface 2. Once it updates, deadline should trigger
   // immediately again.
   scheduler_->SurfaceDamaged(sid2);
diff --git a/cc/surfaces/surface_aggregator.cc b/cc/surfaces/surface_aggregator.cc
index 531e2d2..a6af98ea 100644
--- a/cc/surfaces/surface_aggregator.cc
+++ b/cc/surfaces/surface_aggregator.cc
@@ -228,10 +228,12 @@
   SurfaceSet::iterator it = referenced_surfaces_.insert(surface_id).first;
   // TODO(vmpstr): provider check is a hack for unittests that don't set up a
   // resource provider.
+  ResourceProvider::ResourceIdMap empty_map;
   const ResourceProvider::ResourceIdMap& child_to_parent_map =
       provider_ ? provider_->GetChildToParentMap(ChildIdForSurface(surface))
-                : ResourceProvider::ResourceIdMap();
-  bool merge_pass = surface_quad->opacity() == 1.f && copy_requests.empty();
+                : empty_map;
+  bool merge_pass =
+      surface_quad->shared_quad_state->opacity == 1.f && copy_requests.empty();
 
   gfx::Rect surface_damage = DamageRectForSurface(
       surface, *render_pass_list.back(), surface_quad->visible_rect);
@@ -257,7 +259,7 @@
     // transform of the surface quad into account to update their transform to
     // the root surface.
     copy_pass->transform_to_root_target.ConcatTransform(
-        surface_quad->quadTransform());
+        surface_quad->shared_quad_state->content_to_target_transform);
     copy_pass->transform_to_root_target.ConcatTransform(target_transform);
     copy_pass->transform_to_root_target.ConcatTransform(
         dest_pass->transform_to_root_target);
@@ -277,16 +279,20 @@
     // TODO(jamesr): Clean up last pass special casing.
     const QuadList& quads = last_pass.quad_list;
 
-    gfx::Transform surface_transform = surface_quad->quadTransform();
+    gfx::Transform surface_transform =
+        surface_quad->shared_quad_state->content_to_target_transform;
     surface_transform.ConcatTransform(target_transform);
 
     // Intersect the transformed visible rect and the clip rect to create a
     // smaller cliprect for the quad.
     ClipData surface_quad_clip_rect(
-        true, MathUtil::MapEnclosingClippedRect(surface_quad->quadTransform(),
-                                                surface_quad->visible_rect));
-    if (surface_quad->isClipped())
-      surface_quad_clip_rect.rect.Intersect(surface_quad->clipRect());
+        true, MathUtil::MapEnclosingClippedRect(
+                  surface_quad->shared_quad_state->content_to_target_transform,
+                  surface_quad->visible_rect));
+    if (surface_quad->shared_quad_state->is_clipped) {
+      surface_quad_clip_rect.rect.Intersect(
+          surface_quad->shared_quad_state->clip_rect);
+    }
 
     ClipData quads_clip =
         CalculateClipRect(clip_rect, surface_quad_clip_rect, target_transform);
@@ -315,10 +321,11 @@
                  gfx::Vector2dF(),
                  FilterOperations());
   }
-  dest_pass->damage_rect =
-      gfx::UnionRects(dest_pass->damage_rect,
-                      MathUtil::MapEnclosingClippedRect(
-                          surface_quad->quadTransform(), surface_damage));
+  dest_pass->damage_rect = gfx::UnionRects(
+      dest_pass->damage_rect,
+      MathUtil::MapEnclosingClippedRect(
+          surface_quad->shared_quad_state->content_to_target_transform,
+          surface_damage));
 
   referenced_surfaces_.erase(it);
 }
@@ -394,10 +401,11 @@
         dest_quad = dest_pass->CopyFromAndAppendRenderPassDrawQuad(
             pass_quad, dest_pass->shared_quad_state_list.back(),
             remapped_pass_id);
-        dest_pass->damage_rect =
-            gfx::UnionRects(dest_pass->damage_rect,
-                            MathUtil::MapEnclosingClippedRect(
-                                dest_quad->quadTransform(), pass_damage));
+        dest_pass->damage_rect = gfx::UnionRects(
+            dest_pass->damage_rect,
+            MathUtil::MapEnclosingClippedRect(
+                dest_quad->shared_quad_state->content_to_target_transform,
+                pass_damage));
       } else {
         dest_quad = dest_pass->CopyFromAndAppendDrawQuad(
             quad, dest_pass->shared_quad_state_list.back());
@@ -432,9 +440,10 @@
 
   // TODO(vmpstr): provider check is a hack for unittests that don't set up a
   // resource provider.
+  ResourceProvider::ResourceIdMap empty_map;
   const ResourceProvider::ResourceIdMap& child_to_parent_map =
       provider_ ? provider_->GetChildToParentMap(ChildIdForSurface(surface))
-                : ResourceProvider::ResourceIdMap();
+                : empty_map;
   for (size_t i = 0; i < source_pass_list.size(); ++i) {
     const RenderPass& source = *source_pass_list[i];
 
diff --git a/cc/surfaces/surface_aggregator_unittest.cc b/cc/surfaces/surface_aggregator_unittest.cc
index 1fb5163..ac81b3b6 100644
--- a/cc/surfaces/surface_aggregator_unittest.cc
+++ b/cc/surfaces/surface_aggregator_unittest.cc
@@ -1036,7 +1036,7 @@
        iter != aggregated_pass_list[1]->quad_list.cend();
        ++iter) {
     EXPECT_EQ(expected_root_pass_quad_transforms[iter.index()].ToString(),
-              iter->quadTransform().ToString())
+              iter->shared_quad_state->content_to_target_transform.ToString())
         << iter.index();
   }
 
diff --git a/cc/test/fake_layer_tree_host_client.h b/cc/test/fake_layer_tree_host_client.h
index 206ad29..d6d6c64e 100644
--- a/cc/test/fake_layer_tree_host_client.h
+++ b/cc/test/fake_layer_tree_host_client.h
@@ -48,6 +48,10 @@
   void DidCommitAndDrawFrame() override {}
   void DidCompleteSwapBuffers() override {}
   void DidCompletePageScaleAnimation() override {}
+  void RecordFrameTimingEvents(
+      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events)
+      override {}
 
   // LayerTreeHostSingleThreadClient implementation.
   void DidPostSwapBuffers() override {}
diff --git a/cc/test/fake_layer_tree_host_impl_client.h b/cc/test/fake_layer_tree_host_impl_client.h
index b386e6ee..4085733f 100644
--- a/cc/test/fake_layer_tree_host_impl_client.h
+++ b/cc/test/fake_layer_tree_host_impl_client.h
@@ -5,6 +5,7 @@
 #ifndef CC_TEST_FAKE_LAYER_TREE_HOST_IMPL_CLIENT_H_
 #define CC_TEST_FAKE_LAYER_TREE_HOST_IMPL_CLIENT_H_
 
+#include "cc/debug/frame_timing_tracker.h"
 #include "cc/output/begin_frame_args.h"
 #include "cc/trees/layer_tree_host_impl.h"
 
@@ -42,6 +43,10 @@
   void DidPrepareTiles() override {}
   void DidCompletePageScaleAnimationOnImplThread() override {}
   void OnDrawForOutputSurface() override {}
+  void PostFrameTimingEventsOnImplThread(
+      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events)
+      override {}
 };
 
 }  // namespace cc
diff --git a/cc/test/fake_picture_layer_tiling_client.cc b/cc/test/fake_picture_layer_tiling_client.cc
index 75eff0c..bba8459 100644
--- a/cc/test/fake_picture_layer_tiling_client.cc
+++ b/cc/test/fake_picture_layer_tiling_client.cc
@@ -16,7 +16,7 @@
       pile_(FakePicturePileImpl::CreateInfiniteFilledPile()),
       twin_set_(nullptr),
       twin_tiling_(nullptr),
-      max_tile_priority_bin_(TilePriority::NOW) {
+      has_valid_tile_priorities_(true) {
 }
 
 FakePictureLayerTilingClient::FakePictureLayerTilingClient(
@@ -27,7 +27,7 @@
       pile_(FakePicturePileImpl::CreateInfiniteFilledPile()),
       twin_set_(nullptr),
       twin_tiling_(nullptr),
-      max_tile_priority_bin_(TilePriority::NOW) {
+      has_valid_tile_priorities_(true) {
 }
 
 FakePictureLayerTilingClient::~FakePictureLayerTilingClient() {
@@ -47,9 +47,8 @@
   return tile_size_;
 }
 
-TilePriority::PriorityBin FakePictureLayerTilingClient::GetMaxTilePriorityBin()
-    const {
-  return max_tile_priority_bin_;
+bool FakePictureLayerTilingClient::HasValidTilePriorities() const {
+  return has_valid_tile_priorities_;
 }
 
 const Region* FakePictureLayerTilingClient::GetPendingInvalidation() {
diff --git a/cc/test/fake_picture_layer_tiling_client.h b/cc/test/fake_picture_layer_tiling_client.h
index 82a6ff8..a49e2a1 100644
--- a/cc/test/fake_picture_layer_tiling_client.h
+++ b/cc/test/fake_picture_layer_tiling_client.h
@@ -24,7 +24,7 @@
   ScopedTilePtr CreateTile(float contents_scale,
                            const gfx::Rect& rect) override;
   gfx::Size CalculateTileSize(const gfx::Size& content_bounds) const override;
-  TilePriority::PriorityBin GetMaxTilePriorityBin() const override;
+  bool HasValidTilePriorities() const override;
 
   void SetTileSize(const gfx::Size& tile_size);
   gfx::Size TileSize() const { return tile_size_; }
@@ -44,8 +44,8 @@
   }
   void set_text_rect(const gfx::Rect& rect) { text_rect_ = rect; }
   void set_invalidation(const Region& region) { invalidation_ = region; }
-  void set_max_tile_priority_bin(TilePriority::PriorityBin bin) {
-    max_tile_priority_bin_ = bin;
+  void set_has_valid_tile_priorities(bool has_valid_tile_priorities) {
+    has_valid_tile_priorities_ = has_valid_tile_priorities;
   }
   RasterSource* raster_source() { return pile_.get(); }
 
@@ -63,7 +63,7 @@
   PictureLayerTiling* twin_tiling_;
   gfx::Rect text_rect_;
   Region invalidation_;
-  TilePriority::PriorityBin max_tile_priority_bin_;
+  bool has_valid_tile_priorities_;
 };
 
 }  // namespace cc
diff --git a/cc/test/layer_test_common.cc b/cc/test/layer_test_common.cc
index 83f756d..8ae9aef7 100644
--- a/cc/test/layer_test_common.cc
+++ b/cc/test/layer_test_common.cc
@@ -41,8 +41,9 @@
   Region remaining = rect;
 
   for (auto iter = quads.cbegin(); iter != quads.cend(); ++iter) {
-    gfx::RectF quad_rectf =
-        MathUtil::MapClippedRect(iter->quadTransform(), gfx::RectF(iter->rect));
+    gfx::RectF quad_rectf = MathUtil::MapClippedRect(
+        iter->shared_quad_state->content_to_target_transform,
+        gfx::RectF(iter->rect));
 
     // Before testing for exact coverage in the integer world, assert that
     // rounding will not round the rect incorrectly.
@@ -69,25 +70,29 @@
   // No quad should exist if it's fully occluded.
   for (const auto& quad : quads) {
     gfx::Rect target_visible_rect = MathUtil::MapEnclosingClippedRect(
-        quad->quadTransform(), quad->visible_rect);
+        quad->shared_quad_state->content_to_target_transform,
+        quad->visible_rect);
     EXPECT_FALSE(occluded.Contains(target_visible_rect));
   }
 
   // Quads that are fully occluded on one axis only should be shrunken.
   for (const auto& quad : quads) {
-    gfx::Rect target_rect =
-        MathUtil::MapEnclosingClippedRect(quad->quadTransform(), quad->rect);
-    if (!quad->quadTransform().IsIdentityOrIntegerTranslation()) {
-      DCHECK(quad->quadTransform().IsPositiveScaleOrTranslation())
-          << quad->quadTransform().ToString();
-      gfx::RectF target_rectf =
-          MathUtil::MapClippedRect(quad->quadTransform(), quad->rect);
+    gfx::Rect target_rect = MathUtil::MapEnclosingClippedRect(
+        quad->shared_quad_state->content_to_target_transform, quad->rect);
+    if (!quad->shared_quad_state->content_to_target_transform
+             .IsIdentityOrIntegerTranslation()) {
+      DCHECK(quad->shared_quad_state->content_to_target_transform
+                 .IsPositiveScaleOrTranslation())
+          << quad->shared_quad_state->content_to_target_transform.ToString();
+      gfx::RectF target_rectf = MathUtil::MapClippedRect(
+          quad->shared_quad_state->content_to_target_transform, quad->rect);
       // Scale transforms allowed, as long as the final transformed rect
       // ends up on integer boundaries for ease of testing.
       DCHECK_EQ(target_rectf.ToString(), gfx::RectF(target_rect).ToString());
     }
     gfx::Rect target_visible_rect = MathUtil::MapEnclosingClippedRect(
-        quad->quadTransform(), quad->visible_rect);
+        quad->shared_quad_state->content_to_target_transform,
+        quad->visible_rect);
 
     bool fully_occluded_horizontal = target_rect.x() >= occluded.x() &&
                                      target_rect.right() <= occluded.right();
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 20ea9c6..7c7e221 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -442,6 +442,11 @@
   void DidCompletePageScaleAnimation() override {}
   void BeginMainFrameNotExpectedSoon() override {}
 
+  void RecordFrameTimingEvents(
+      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events)
+      override {}
+
  private:
   explicit LayerTreeHostClientForTesting(TestHooks* test_hooks)
       : test_hooks_(test_hooks) {}
diff --git a/cc/tiles/picture_layer_tiling.cc b/cc/tiles/picture_layer_tiling.cc
index df6085d..3c22a4f 100644
--- a/cc/tiles/picture_layer_tiling.cc
+++ b/cc/tiles/picture_layer_tiling.cc
@@ -877,8 +877,9 @@
   DCHECK_EQ(ComputePriorityRectTypeForTile(tile), priority_rect_type);
   DCHECK_EQ(TileAt(tile->tiling_i_index(), tile->tiling_j_index()), tile);
 
-  TilePriority::PriorityBin priority_bin = client_->GetMaxTilePriorityBin();
-
+  TilePriority::PriorityBin priority_bin = client_->HasValidTilePriorities()
+                                               ? TilePriority::NOW
+                                               : TilePriority::EVENTUALLY;
   switch (priority_rect_type) {
     case VISIBLE_RECT:
       return TilePriority(resolution_, priority_bin, 0);
diff --git a/cc/tiles/picture_layer_tiling.h b/cc/tiles/picture_layer_tiling.h
index c5ed5bd..717b8a8 100644
--- a/cc/tiles/picture_layer_tiling.h
+++ b/cc/tiles/picture_layer_tiling.h
@@ -45,7 +45,7 @@
   virtual const Region* GetPendingInvalidation() = 0;
   virtual const PictureLayerTiling* GetPendingOrActiveTwinTiling(
       const PictureLayerTiling* tiling) const = 0;
-  virtual TilePriority::PriorityBin GetMaxTilePriorityBin() const = 0;
+  virtual bool HasValidTilePriorities() const = 0;
   virtual bool RequiresHighResToDraw() const = 0;
 
  protected:
diff --git a/cc/tiles/tile.cc b/cc/tiles/tile.cc
index 7d91552..a596194 100644
--- a/cc/tiles/tile.cc
+++ b/cc/tiles/tile.cc
@@ -66,8 +66,12 @@
 }
 
 size_t Tile::GPUMemoryUsageInBytes() const {
-  if (draw_info_.resource_)
-    return draw_info_.resource_->bytes();
+  if (draw_info_.resource_) {
+    // We can use UncheckedSizeInBytes, since the tile size is determined by the
+    // compositor.
+    return Resource::UncheckedMemorySizeBytes(draw_info_.resource_->size(),
+                                              draw_info_.resource_->format());
+  }
   return 0;
 }
 
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index cf6981e7..e110fc2 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -974,7 +974,9 @@
 TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig(
     const gfx::Size& size,
     ResourceFormat format) {
-  return MemoryUsage(Resource::MemorySizeBytes(size, format), 1);
+  // We can use UncheckedMemorySizeBytes here since this is used with a tile
+  // size which is determined by the compositor (it's at most max texture size).
+  return MemoryUsage(Resource::UncheckedMemorySizeBytes(size, format), 1);
 }
 
 // static
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc
index 1428db1..86b95664 100644
--- a/cc/tiles/tile_manager_unittest.cc
+++ b/cc/tiles/tile_manager_unittest.cc
@@ -1407,7 +1407,7 @@
 
   ManagedMemoryPolicy policy = host_impl_.ActualManagedMemoryPolicy();
   policy.bytes_limit_when_visible =
-      Resource::MemorySizeBytes(gfx::Size(256, 256), RGBA_8888);
+      Resource::UncheckedMemorySizeBytes(gfx::Size(256, 256), RGBA_8888);
   host_impl_.SetMemoryPolicy(policy);
 
   EXPECT_FALSE(host_impl_.is_likely_to_require_a_draw());
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index a0f279a..97568527 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -933,9 +933,10 @@
     Layer* render_surface_layer = update_list.at(i);
     RenderSurface* render_surface = render_surface_layer->render_surface();
 
-    size_t bytes =
-        Resource::MemorySizeBytes(render_surface->content_rect().size(),
-                                  RGBA_8888);
+    // We can use UncheckedMemorySizeBytes, since render surface content rect is
+    // limited by max texture size.
+    size_t bytes = Resource::UncheckedMemorySizeBytes(
+        render_surface->content_rect().size(), RGBA_8888);
     contents_texture_bytes += bytes;
 
     if (render_surface_layer->background_filters().IsEmpty() &&
@@ -943,8 +944,10 @@
       continue;
 
     if (!readback_bytes) {
-      readback_bytes = Resource::MemorySizeBytes(device_viewport_size_,
-                                                 RGBA_8888);
+      // We need to use a checked size calucation here, since we don't control
+      // the size of the device viewport.
+      readback_bytes =
+          Resource::CheckedMemorySizeBytes(device_viewport_size_, RGBA_8888);
     }
   }
   return readback_bytes + contents_texture_bytes;
@@ -1302,4 +1305,11 @@
   proxy_->SetAuthoritativeVSyncInterval(interval);
 }
 
+void LayerTreeHost::RecordFrameTimingEvents(
+    scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+    scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) {
+  client_->RecordFrameTimingEvents(composite_events.Pass(),
+                                   main_frame_events.Pass());
+}
+
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 278814a8..449d8e4 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -21,6 +21,7 @@
 #include "cc/animation/animation_events.h"
 #include "cc/base/cc_export.h"
 #include "cc/base/scoped_ptr_vector.h"
+#include "cc/debug/frame_timing_tracker.h"
 #include "cc/debug/micro_benchmark.h"
 #include "cc/debug/micro_benchmark_controller.h"
 #include "cc/input/input_handler.h"
@@ -329,6 +330,10 @@
     return settings().impl_side_painting;
   }
 
+  void RecordFrameTimingEvents(
+      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events);
+
  protected:
   explicit LayerTreeHost(InitParams* params);
   void InitializeThreaded(
diff --git a/cc/trees/layer_tree_host_client.h b/cc/trees/layer_tree_host_client.h
index 3aa041f..56a128f 100644
--- a/cc/trees/layer_tree_host_client.h
+++ b/cc/trees/layer_tree_host_client.h
@@ -8,6 +8,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/time/time.h"
+#include "cc/debug/frame_timing_tracker.h"
 
 namespace gfx {
 class Vector2d;
@@ -46,6 +47,9 @@
   virtual void DidCommit() = 0;
   virtual void DidCommitAndDrawFrame() = 0;
   virtual void DidCompleteSwapBuffers() = 0;
+  virtual void RecordFrameTimingEvents(
+      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) = 0;
 
   // Called when page scale animation has completed.
   virtual void DidCompletePageScaleAnimation() = 0;
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index 17800fe..3db11585 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -21,9 +21,7 @@
 #include "cc/output/copy_output_request.h"
 #include "cc/output/copy_output_result.h"
 #include "cc/test/animation_test_common.h"
-#include "cc/test/fake_content_layer.h"
 #include "cc/test/fake_content_layer_client.h"
-#include "cc/test/fake_content_layer_impl.h"
 #include "cc/test/fake_impl_proxy.h"
 #include "cc/test/fake_layer_tree_host.h"
 #include "cc/test/fake_layer_tree_host_impl.h"
@@ -2676,6 +2674,30 @@
   EXPECT_EQ(expected, actual);
 }
 
+TEST_F(LayerTreeHostCommonTest,
+       VisibleRectsForPositionedRootLayerClippedByViewport) {
+  scoped_refptr<Layer> root =
+      make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings()));
+  scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+  host->SetRootLayer(root);
+
+  gfx::Transform identity_matrix;
+  // Root layer is positioned at (60, 70). The default device viewport size
+  // is (0, 0, 100x100) in target space. So the root layer's visible rect
+  // will be clipped by the viewport to be (0, 0, 40x30) in layer's space.
+  SetLayerPropertiesForTesting(root.get(), identity_matrix, gfx::Point3F(),
+                               gfx::PointF(60, 70), gfx::Size(100, 100), true,
+                               false);
+  ExecuteCalculateDrawProperties(root.get());
+
+  EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
+            root->render_surface()->DrawableContentRect());
+  // In target space, not clipped.
+  EXPECT_EQ(gfx::Rect(60, 70, 100, 100), root->drawable_content_rect());
+  // In layer space, clipped.
+  EXPECT_EQ(gfx::Rect(0, 0, 40, 30), root->visible_content_rect());
+}
+
 TEST_F(LayerTreeHostCommonTest, DrawableAndVisibleContentRectsForSimpleLayers) {
   scoped_refptr<Layer> root = Layer::Create(layer_settings());
   scoped_refptr<LayerWithForcedDrawsContent> child1 =
@@ -9355,8 +9377,8 @@
       make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings()));
   scoped_refptr<LayerWithForcedDrawsContent> grandchild =
       make_scoped_refptr(new LayerWithForcedDrawsContent(layer_settings()));
-  scoped_refptr<FakeContentLayer> greatgrandchild(
-      FakeContentLayer::Create(layer_settings(), &client));
+  scoped_refptr<FakePictureLayer> greatgrandchild(
+      FakePictureLayer::Create(layer_settings(), &client));
   SetLayerPropertiesForTesting(root.get(), identity, gfx::Point3F(),
                                gfx::PointF(), gfx::Size(100, 100), true, false);
   SetLayerPropertiesForTesting(child.get(), identity, gfx::Point3F(),
@@ -9428,8 +9450,8 @@
   scoped_ptr<LayerImpl> grandchild =
       LayerImpl::Create(host_impl.active_tree(), 3);
 
-  scoped_ptr<FakeContentLayerImpl> greatgrandchild(
-      FakeContentLayerImpl::Create(host_impl.active_tree(), 4));
+  scoped_ptr<FakePictureLayerImpl> greatgrandchild(
+      FakePictureLayerImpl::Create(host_impl.active_tree(), 4));
 
   child->SetDrawsContent(true);
   grandchild->SetDrawsContent(true);
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index d1dc7b5..6dc90435 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -230,7 +230,7 @@
       id_(id),
       requires_high_res_to_draw_(false),
       is_likely_to_require_a_draw_(false),
-      frame_timing_tracker_(FrameTimingTracker::Create()) {
+      frame_timing_tracker_(FrameTimingTracker::Create(this)) {
   DCHECK(proxy_->IsImplThread());
   DidVisibilityChange(this, visible_);
   animation_registrar_->set_supports_scroll_animations(
@@ -2174,6 +2174,13 @@
       request_ids, start_time, end_time, active_tree_->source_frame_number());
 }
 
+void LayerTreeHostImpl::PostFrameTimingEvents(
+    scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+    scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) {
+  client_->PostFrameTimingEventsOnImplThread(composite_events.Pass(),
+                                             main_frame_events.Pass());
+}
+
 void LayerTreeHostImpl::DestroyTileManager() {
   tile_manager_ = nullptr;
   resource_pool_ = nullptr;
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 2b1fced..dddf231 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -127,6 +127,10 @@
   // Called when output surface asks for a draw.
   virtual void OnDrawForOutputSurface() = 0;
 
+  virtual void PostFrameTimingEventsOnImplThread(
+      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) = 0;
+
  protected:
   virtual ~LayerTreeHostImplClient() {}
 };
@@ -539,6 +543,11 @@
       const BeginFrameArgs& start_of_main_frame_args,
       const BeginFrameArgs& expected_next_main_frame_args);
 
+  // Post the given frame timing events to the requester.
+  void PostFrameTimingEvents(
+      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events);
+
  protected:
   LayerTreeHostImpl(
       const LayerTreeSettings& settings,
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index f55899c..5e9fcce8 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -166,6 +166,10 @@
     did_complete_page_scale_animation_ = true;
   }
   void OnDrawForOutputSurface() override {}
+  void PostFrameTimingEventsOnImplThread(
+      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events)
+      override {}
 
   void set_reduce_memory_result(bool reduce_memory_result) {
     reduce_memory_result_ = reduce_memory_result;
@@ -5829,7 +5833,7 @@
 
   bool antialiased =
       GLRendererWithSetupQuadForAntialiasing::ShouldAntialiasQuad(
-          quad->quadTransform(), quad, false);
+          quad->shared_quad_state->content_to_target_transform, quad, false);
   EXPECT_FALSE(antialiased);
 
   host_impl_->DrawLayers(&frame);
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 715165d..427b649 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -6040,8 +6040,9 @@
       const TileDrawQuad* quad = TileDrawQuad::MaterialCast(draw_quad);
       float quad_scale =
           quad->tex_coord_rect.width() / static_cast<float>(quad->rect.width());
-      float transform_scale =
-          SkMScalarToFloat(quad->quadTransform().matrix().get(0, 0));
+      float transform_scale = SkMScalarToFloat(
+          quad->shared_quad_state->content_to_target_transform.matrix().get(0,
+                                                                            0));
       float scale = quad_scale / transform_scale;
       if (frame_scale != 0.f && frame_scale != scale)
         return 0.f;
@@ -6343,8 +6344,9 @@
       const TileDrawQuad* quad = TileDrawQuad::MaterialCast(draw_quad);
       float quad_scale =
           quad->tex_coord_rect.width() / static_cast<float>(quad->rect.width());
-      float transform_scale =
-          SkMScalarToFloat(quad->quadTransform().matrix().get(0, 0));
+      float transform_scale = SkMScalarToFloat(
+          quad->shared_quad_state->content_to_target_transform.matrix().get(0,
+                                                                            0));
       float scale = quad_scale / transform_scale;
       if (frame_scale != 0.f && frame_scale != scale)
         return 0.f;
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index 6300622..e6f2b5c2 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -12,8 +12,8 @@
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_impl.h"
 #include "cc/test/animation_test_common.h"
-#include "cc/test/fake_content_layer.h"
 #include "cc/test/fake_content_layer_client.h"
+#include "cc/test/fake_picture_layer.h"
 #include "cc/test/layer_tree_test.h"
 #include "cc/trees/layer_tree_impl.h"
 
@@ -231,12 +231,12 @@
 
   void SetupTree() override {
     LayerTreeHostAnimationTest::SetupTree();
-    content_ = FakeContentLayer::Create(layer_settings(), &client_);
-    content_->SetBounds(gfx::Size(4, 4));
-    layer_tree_host()->root_layer()->AddChild(content_);
+    picture_ = FakePictureLayer::Create(layer_settings(), &client_);
+    picture_->SetBounds(gfx::Size(4, 4));
+    layer_tree_host()->root_layer()->AddChild(picture_);
   }
 
-  void BeginTest() override { PostAddAnimationToMainThread(content_.get()); }
+  void BeginTest() override { PostAddAnimationToMainThread(picture_.get()); }
 
   void AnimateLayers(LayerTreeHostImpl* host_impl,
                      base::TimeTicks monotonic_time) override {
@@ -265,7 +265,7 @@
   void AfterTest() override {}
 
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> content_;
+  scoped_refptr<FakePictureLayer> picture_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(
@@ -280,13 +280,13 @@
 
   void SetupTree() override {
     LayerTreeHostAnimationTest::SetupTree();
-    content_ = FakeContentLayer::Create(layer_settings(), &client_);
-    content_->SetBounds(gfx::Size(4, 4));
-    content_->set_layer_animation_delegate(this);
-    layer_tree_host()->root_layer()->AddChild(content_);
+    picture_ = FakePictureLayer::Create(layer_settings(), &client_);
+    picture_->SetBounds(gfx::Size(4, 4));
+    picture_->set_layer_animation_delegate(this);
+    layer_tree_host()->root_layer()->AddChild(picture_);
   }
 
-  void BeginTest() override { PostAddAnimationToMainThread(content_.get()); }
+  void BeginTest() override { PostAddAnimationToMainThread(picture_.get()); }
 
   void NotifyAnimationStarted(base::TimeTicks monotonic_time,
                               Animation::TargetProperty target_property,
@@ -321,7 +321,7 @@
   base::TimeTicks main_start_time_;
   base::TimeTicks impl_start_time_;
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> content_;
+  scoped_refptr<FakePictureLayer> picture_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(
@@ -361,7 +361,7 @@
  public:
   LayerTreeHostAnimationTestDoNotSkipLayersWithAnimatedOpacity()
       : update_check_layer_(
-            FakeContentLayer::Create(layer_settings(), &client_)) {}
+            FakePictureLayer::Create(layer_settings(), &client_)) {}
 
   void SetupTree() override {
     update_check_layer_->SetOpacity(0.f);
@@ -393,7 +393,7 @@
 
  private:
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> update_check_layer_;
+  scoped_refptr<FakePictureLayer> update_check_layer_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(
@@ -475,8 +475,6 @@
   int num_begin_frames_;
   int num_commit_calls_;
   int num_draw_calls_;
-  FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> content_;
 };
 
 MULTI_THREAD_TEST_F(LayerTreeHostAnimationTestCancelAnimateCommit);
@@ -558,15 +556,15 @@
 
   void SetupTree() override {
     LayerTreeHostAnimationTest::SetupTree();
-    content_ = FakeContentLayer::Create(layer_settings(), &client_);
-    content_->SetBounds(gfx::Size(4, 4));
-    content_->set_layer_animation_delegate(this);
-    layer_tree_host()->root_layer()->AddChild(content_);
+    picture_ = FakePictureLayer::Create(layer_settings(), &client_);
+    picture_->SetBounds(gfx::Size(4, 4));
+    picture_->set_layer_animation_delegate(this);
+    layer_tree_host()->root_layer()->AddChild(picture_);
   }
 
   void BeginTest() override {
     layer_tree_host()->SetViewportSize(gfx::Size());
-    PostAddAnimationToMainThread(content_.get());
+    PostAddAnimationToMainThread(picture_.get());
   }
 
   void NotifyAnimationStarted(base::TimeTicks monotonic_time,
@@ -586,7 +584,7 @@
  private:
   int started_times_;
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> content_;
+  scoped_refptr<FakePictureLayer> picture_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(
@@ -598,10 +596,10 @@
     : public LayerTreeHostAnimationTest {
   void SetupTree() override {
     LayerTreeHostAnimationTest::SetupTree();
-    content_ = FakeContentLayer::Create(layer_settings(), &client_);
-    content_->SetBounds(gfx::Size(4, 4));
-    content_->set_layer_animation_delegate(this);
-    layer_tree_host()->root_layer()->AddChild(content_);
+    picture_ = FakePictureLayer::Create(layer_settings(), &client_);
+    picture_->SetBounds(gfx::Size(4, 4));
+    picture_->set_layer_animation_delegate(this);
+    layer_tree_host()->root_layer()->AddChild(picture_);
   }
 
   void InitializeSettings(LayerTreeSettings* settings) override {
@@ -636,12 +634,12 @@
     switch (layer_tree_host()->source_frame_number()) {
       case 1:
         // The animation is longer than 1 BeginFrame interval.
-        AddOpacityTransitionToLayer(content_.get(), 0.1, 0.2f, 0.8f, false);
+        AddOpacityTransitionToLayer(picture_.get(), 0.1, 0.2f, 0.8f, false);
         added_animations_++;
         break;
       case 2:
         // This second animation will not be drawn so it should not start.
-        AddAnimatedTransformToLayer(content_.get(), 0.1, 5, 5);
+        AddAnimatedTransformToLayer(picture_.get(), 0.1, 5, 5);
         added_animations_++;
         break;
     }
@@ -667,7 +665,7 @@
   int added_animations_;
   int started_times_;
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> content_;
+  scoped_refptr<FakePictureLayer> picture_;
 };
 
 MULTI_THREAD_TEST_F(
@@ -684,7 +682,7 @@
   void SetupTree() override {
     LayerTreeHostAnimationTest::SetupTree();
 
-    scroll_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    scroll_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     scroll_layer_->SetScrollClipLayerId(layer_tree_host()->root_layer()->id());
     scroll_layer_->SetBounds(gfx::Size(1000, 1000));
     scroll_layer_->SetScrollOffset(gfx::ScrollOffset(10, 20));
@@ -722,7 +720,7 @@
 
  private:
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> scroll_layer_;
+  scoped_refptr<FakePictureLayer> scroll_layer_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(
@@ -741,7 +739,7 @@
   void SetupTree() override {
     LayerTreeHostAnimationTest::SetupTree();
 
-    scroll_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    scroll_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     scroll_layer_->SetScrollClipLayerId(layer_tree_host()->root_layer()->id());
     scroll_layer_->SetBounds(gfx::Size(10000, 10000));
     scroll_layer_->SetScrollOffset(gfx::ScrollOffset(100.0, 200.0));
@@ -836,7 +834,7 @@
 
  private:
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> scroll_layer_;
+  scoped_refptr<FakePictureLayer> scroll_layer_;
   const gfx::ScrollOffset final_postion_;
 };
 
@@ -937,10 +935,10 @@
 
   void SetupTree() override {
     LayerTreeHostAnimationTest::SetupTree();
-    content_ = Layer::Create(layer_settings());
-    content_->SetBounds(gfx::Size(4, 4));
-    layer_tree_host()->root_layer()->AddChild(content_);
-    AddOpacityTransitionToLayer(content_.get(), 10000.0, 0.1f, 0.9f, true);
+    layer_ = Layer::Create(layer_settings());
+    layer_->SetBounds(gfx::Size(4, 4));
+    layer_tree_host()->root_layer()->AddChild(layer_);
+    AddOpacityTransitionToLayer(layer_.get(), 10000.0, 0.1f, 0.9f, true);
   }
 
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
@@ -948,10 +946,10 @@
   void DidCommit() override {
     switch (layer_tree_host()->source_frame_number()) {
       case 1:
-        content_->RemoveFromParent();
+        layer_->RemoveFromParent();
         break;
       case 2:
-        layer_tree_host()->root_layer()->AddChild(content_);
+        layer_tree_host()->root_layer()->AddChild(layer_);
         break;
     }
   }
@@ -974,7 +972,7 @@
   void AfterTest() override {}
 
  private:
-  scoped_refptr<Layer> content_;
+  scoped_refptr<Layer> layer_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(
@@ -988,9 +986,9 @@
 
   void SetupTree() override {
     LayerTreeHostAnimationTest::SetupTree();
-    content_ = Layer::Create(layer_settings());
-    content_->SetBounds(gfx::Size(4, 4));
-    layer_tree_host()->root_layer()->AddChild(content_);
+    layer_ = Layer::Create(layer_settings());
+    layer_->SetBounds(gfx::Size(4, 4));
+    layer_tree_host()->root_layer()->AddChild(layer_);
   }
 
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
@@ -1004,7 +1002,7 @@
       case 2:
         // Second frame: add an animation to the content layer. The root layer
         // animation has caused us to animate already during this frame.
-        AddOpacityTransitionToLayer(content_.get(), 0.1, 5, 5, false);
+        AddOpacityTransitionToLayer(layer_.get(), 0.1, 5, 5, false);
         break;
     }
   }
@@ -1035,7 +1033,7 @@
   void AfterTest() override {}
 
  private:
-  scoped_refptr<Layer> content_;
+  scoped_refptr<Layer> layer_;
   int num_swap_buffers_;
 };
 
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc
index b3725d40..440063d 100644
--- a/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -5,9 +5,9 @@
 #include "cc/layers/layer_iterator.h"
 #include "cc/output/copy_output_request.h"
 #include "cc/output/copy_output_result.h"
-#include "cc/test/fake_content_layer.h"
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_picture_layer.h"
 #include "cc/test/layer_tree_test.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "gpu/GLES2/gl2extchromium.h"
@@ -23,10 +23,10 @@
     : public LayerTreeHostCopyRequestTest {
  protected:
   void SetupTree() override {
-    root = FakeContentLayer::Create(layer_settings(), &client_);
+    root = FakePictureLayer::Create(layer_settings(), &client_);
     root->SetBounds(gfx::Size(20, 20));
 
-    child = FakeContentLayer::Create(layer_settings(), &client_);
+    child = FakePictureLayer::Create(layer_settings(), &client_);
     child->SetBounds(gfx::Size(10, 10));
     root->AddChild(child);
 
@@ -114,8 +114,8 @@
   bool use_gl_renderer_;
   std::vector<gfx::Size> callbacks_;
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root;
-  scoped_refptr<FakeContentLayer> child;
+  scoped_refptr<FakePictureLayer> root;
+  scoped_refptr<FakePictureLayer> child;
 };
 
 // Readback can't be done with a delegating renderer.
@@ -148,14 +148,14 @@
     : public LayerTreeHostCopyRequestTest {
  protected:
   void SetupTree() override {
-    root_ = FakeContentLayer::Create(layer_settings(), &client_);
+    root_ = FakePictureLayer::Create(layer_settings(), &client_);
     root_->SetBounds(gfx::Size(20, 20));
 
-    main_destroyed_ = FakeContentLayer::Create(layer_settings(), &client_);
+    main_destroyed_ = FakePictureLayer::Create(layer_settings(), &client_);
     main_destroyed_->SetBounds(gfx::Size(15, 15));
     root_->AddChild(main_destroyed_);
 
-    impl_destroyed_ = FakeContentLayer::Create(layer_settings(), &client_);
+    impl_destroyed_ = FakePictureLayer::Create(layer_settings(), &client_);
     impl_destroyed_->SetBounds(gfx::Size(10, 10));
     root_->AddChild(impl_destroyed_);
 
@@ -229,9 +229,9 @@
 
   int callback_count_;
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> main_destroyed_;
-  scoped_refptr<FakeContentLayer> impl_destroyed_;
+  scoped_refptr<FakePictureLayer> root_;
+  scoped_refptr<FakePictureLayer> main_destroyed_;
+  scoped_refptr<FakePictureLayer> impl_destroyed_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostCopyRequestTestLayerDestroyed);
@@ -240,20 +240,20 @@
     : public LayerTreeHostCopyRequestTest {
  protected:
   void SetupTree() override {
-    root_ = FakeContentLayer::Create(layer_settings(), &client_);
+    root_ = FakePictureLayer::Create(layer_settings(), &client_);
     root_->SetBounds(gfx::Size(20, 20));
 
-    grand_parent_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    grand_parent_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     grand_parent_layer_->SetBounds(gfx::Size(15, 15));
     root_->AddChild(grand_parent_layer_);
 
     // parent_layer_ owns a render surface.
-    parent_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    parent_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     parent_layer_->SetBounds(gfx::Size(15, 15));
     parent_layer_->SetForceRenderSurface(true);
     grand_parent_layer_->AddChild(parent_layer_);
 
-    copy_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    copy_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     copy_layer_->SetBounds(gfx::Size(10, 10));
     parent_layer_->AddChild(copy_layer_);
 
@@ -326,34 +326,34 @@
 
   int callback_count_;
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> grand_parent_layer_;
-  scoped_refptr<FakeContentLayer> parent_layer_;
-  scoped_refptr<FakeContentLayer> copy_layer_;
+  scoped_refptr<FakePictureLayer> root_;
+  scoped_refptr<FakePictureLayer> grand_parent_layer_;
+  scoped_refptr<FakePictureLayer> parent_layer_;
+  scoped_refptr<FakePictureLayer> copy_layer_;
 };
 
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(
     LayerTreeHostCopyRequestTestInHiddenSubtree);
 
 class LayerTreeHostTestHiddenSurfaceNotAllocatedForSubtreeCopyRequest
     : public LayerTreeHostCopyRequestTest {
  protected:
   void SetupTree() override {
-    root_ = FakeContentLayer::Create(layer_settings(), &client_);
+    root_ = FakePictureLayer::Create(layer_settings(), &client_);
     root_->SetBounds(gfx::Size(20, 20));
 
-    grand_parent_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    grand_parent_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     grand_parent_layer_->SetBounds(gfx::Size(15, 15));
     grand_parent_layer_->SetHideLayerAndSubtree(true);
     root_->AddChild(grand_parent_layer_);
 
     // parent_layer_ owns a render surface.
-    parent_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    parent_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     parent_layer_->SetBounds(gfx::Size(15, 15));
     parent_layer_->SetForceRenderSurface(true);
     grand_parent_layer_->AddChild(parent_layer_);
 
-    copy_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    copy_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     copy_layer_->SetBounds(gfx::Size(10, 10));
     parent_layer_->AddChild(copy_layer_);
 
@@ -403,10 +403,10 @@
 
   FakeContentLayerClient client_;
   bool did_draw_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> grand_parent_layer_;
-  scoped_refptr<FakeContentLayer> parent_layer_;
-  scoped_refptr<FakeContentLayer> copy_layer_;
+  scoped_refptr<FakePictureLayer> root_;
+  scoped_refptr<FakePictureLayer> grand_parent_layer_;
+  scoped_refptr<FakePictureLayer> parent_layer_;
+  scoped_refptr<FakePictureLayer> copy_layer_;
 };
 
 // No output to copy for delegated renderers.
@@ -417,15 +417,15 @@
     : public LayerTreeHostCopyRequestTest {
  protected:
   void SetupTree() override {
-    root_ = FakeContentLayer::Create(layer_settings(), &client_);
+    root_ = FakePictureLayer::Create(layer_settings(), &client_);
     root_->SetBounds(gfx::Size(20, 20));
 
-    parent_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    parent_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     parent_layer_->SetBounds(gfx::Size(15, 15));
     parent_layer_->SetMasksToBounds(true);
     root_->AddChild(parent_layer_);
 
-    copy_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    copy_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     copy_layer_->SetPosition(gfx::Point(15, 15));
     copy_layer_->SetBounds(gfx::Size(10, 10));
     parent_layer_->AddChild(copy_layer_);
@@ -453,9 +453,9 @@
   void AfterTest() override {}
 
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> parent_layer_;
-  scoped_refptr<FakeContentLayer> copy_layer_;
+  scoped_refptr<FakePictureLayer> root_;
+  scoped_refptr<FakePictureLayer> parent_layer_;
+  scoped_refptr<FakePictureLayer> copy_layer_;
 };
 
 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
@@ -465,10 +465,10 @@
     : public LayerTreeHostCopyRequestTest {
  protected:
   void SetupTree() override {
-    root_ = FakeContentLayer::Create(layer_settings(), &client_);
+    root_ = FakePictureLayer::Create(layer_settings(), &client_);
     root_->SetBounds(gfx::Size(20, 20));
 
-    copy_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    copy_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     copy_layer_->SetBounds(gfx::Size(10, 10));
     root_->AddChild(copy_layer_);
 
@@ -525,11 +525,11 @@
   bool saw_copy_request_;
   int callback_count_;
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> copy_layer_;
+  scoped_refptr<FakePictureLayer> root_;
+  scoped_refptr<FakePictureLayer> copy_layer_;
 };
 
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(
     LayerTreeHostTestAsyncTwoReadbacksWithoutDraw);
 
 class LayerTreeHostCopyRequestTestLostOutputSurface
@@ -547,10 +547,10 @@
   }
 
   void SetupTree() override {
-    root_ = FakeContentLayer::Create(layer_settings(), &client_);
+    root_ = FakePictureLayer::Create(layer_settings(), &client_);
     root_->SetBounds(gfx::Size(20, 20));
 
-    copy_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    copy_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     copy_layer_->SetBounds(gfx::Size(10, 10));
     root_->AddChild(copy_layer_);
 
@@ -652,12 +652,12 @@
   size_t num_textures_without_readback_;
   size_t num_textures_after_loss_;
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> copy_layer_;
+  scoped_refptr<FakePictureLayer> root_;
+  scoped_refptr<FakePictureLayer> copy_layer_;
   scoped_ptr<CopyOutputResult> result_;
 };
 
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(
     LayerTreeHostCopyRequestTestLostOutputSurface);
 
 class LayerTreeHostCopyRequestTestCountTextures
@@ -669,10 +669,12 @@
   }
 
   void SetupTree() override {
-    root_ = FakeContentLayer::Create(layer_settings(), &client_);
+    client_.set_fill_with_nonsolid_color(true);
+
+    root_ = FakePictureLayer::Create(layer_settings(), &client_);
     root_->SetBounds(gfx::Size(20, 20));
 
-    copy_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    copy_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     copy_layer_->SetBounds(gfx::Size(10, 10));
     root_->AddChild(copy_layer_);
 
@@ -728,8 +730,8 @@
   size_t num_textures_with_readback_;
   unsigned waited_sync_point_after_readback_;
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> copy_layer_;
+  scoped_refptr<FakePictureLayer> root_;
+  scoped_refptr<FakePictureLayer> copy_layer_;
 };
 
 class LayerTreeHostCopyRequestTestCreatesTexture
@@ -763,7 +765,7 @@
   }
 };
 
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(
     LayerTreeHostCopyRequestTestCreatesTexture);
 
 class LayerTreeHostCopyRequestTestProvideTexture
@@ -816,17 +818,17 @@
   unsigned sync_point_;
 };
 
-SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
+SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(
     LayerTreeHostCopyRequestTestProvideTexture);
 
 class LayerTreeHostCopyRequestTestDestroyBeforeCopy
     : public LayerTreeHostCopyRequestTest {
  protected:
   void SetupTree() override {
-    root_ = FakeContentLayer::Create(layer_settings(), &client_);
+    root_ = FakePictureLayer::Create(layer_settings(), &client_);
     root_->SetBounds(gfx::Size(20, 20));
 
-    copy_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    copy_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     copy_layer_->SetBounds(gfx::Size(10, 10));
     root_->AddChild(copy_layer_);
 
@@ -889,8 +891,8 @@
 
   int callback_count_;
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> copy_layer_;
+  scoped_refptr<FakePictureLayer> root_;
+  scoped_refptr<FakePictureLayer> copy_layer_;
 };
 
 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
@@ -900,10 +902,10 @@
     : public LayerTreeHostCopyRequestTest {
  protected:
   void SetupTree() override {
-    root_ = FakeContentLayer::Create(layer_settings(), &client_);
+    root_ = FakePictureLayer::Create(layer_settings(), &client_);
     root_->SetBounds(gfx::Size(20, 20));
 
-    copy_layer_ = FakeContentLayer::Create(layer_settings(), &client_);
+    copy_layer_ = FakePictureLayer::Create(layer_settings(), &client_);
     copy_layer_->SetBounds(gfx::Size(10, 10));
     root_->AddChild(copy_layer_);
 
@@ -960,8 +962,8 @@
 
   int callback_count_;
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> copy_layer_;
+  scoped_refptr<FakePictureLayer> root_;
+  scoped_refptr<FakePictureLayer> copy_layer_;
 };
 
 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
@@ -971,11 +973,11 @@
     : public LayerTreeHostCopyRequestTest {
  protected:
   void SetupTree() override {
-    scoped_refptr<FakeContentLayer> root =
-        FakeContentLayer::Create(layer_settings(), &client_);
+    scoped_refptr<FakePictureLayer> root =
+        FakePictureLayer::Create(layer_settings(), &client_);
     root->SetBounds(gfx::Size(20, 20));
 
-    child_ = FakeContentLayer::Create(layer_settings(), &client_);
+    child_ = FakePictureLayer::Create(layer_settings(), &client_);
     child_->SetBounds(gfx::Size(10, 10));
     root->AddChild(child_);
     child_->SetHideLayerAndSubtree(true);
@@ -1074,7 +1076,7 @@
 
   void AfterTest() override {}
 
-  scoped_refptr<FakeContentLayer> child_;
+  scoped_refptr<FakePictureLayer> child_;
   FakeContentLayerClient client_;
   int num_draws_;
   bool copy_happened_;
diff --git a/cc/trees/layer_tree_host_unittest_damage.cc b/cc/trees/layer_tree_host_unittest_damage.cc
index db00fb5..4062236 100644
--- a/cc/trees/layer_tree_host_unittest_damage.cc
+++ b/cc/trees/layer_tree_host_unittest_damage.cc
@@ -9,7 +9,7 @@
 #include "base/location.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/time/time.h"
-#include "cc/test/fake_content_layer.h"
+#include "cc/layers/solid_color_layer.h"
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_painted_scrollbar_layer.h"
 #include "cc/test/fake_picture_layer.h"
@@ -28,8 +28,8 @@
     : public LayerTreeHostDamageTest {
   void SetupTree() override {
     // Viewport is 10x10.
-    scoped_refptr<FakeContentLayer> root =
-        FakeContentLayer::Create(layer_settings(), &client_);
+    scoped_refptr<FakePictureLayer> root =
+        FakePictureLayer::Create(layer_settings(), &client_);
     root->SetBounds(gfx::Size(10, 10));
 
     layer_tree_host()->SetRootLayer(root);
@@ -90,8 +90,8 @@
     : public LayerTreeHostDamageTest {
   void SetupTree() override {
     // Viewport is 10x10.
-    scoped_refptr<FakeContentLayer> root =
-        FakeContentLayer::Create(layer_settings(), &client_);
+    scoped_refptr<FakePictureLayer> root =
+        FakePictureLayer::Create(layer_settings(), &client_);
     root->SetBounds(gfx::Size(10, 10));
 
     layer_tree_host()->SetRootLayer(root);
@@ -157,12 +157,12 @@
   }
 
   void SetupTree() override {
-    scoped_refptr<FakeContentLayer> root =
-        FakeContentLayer::Create(layer_settings(), &client_);
+    scoped_refptr<FakePictureLayer> root =
+        FakePictureLayer::Create(layer_settings(), &client_);
     root->SetBounds(gfx::Size(10, 10));
 
     // Most of the layer isn't visible.
-    content_ = FakeContentLayer::Create(layer_settings(), &client_);
+    content_ = FakePictureLayer::Create(layer_settings(), &client_);
     content_->SetBounds(gfx::Size(2000, 100));
     root->AddChild(content_);
 
@@ -230,21 +230,20 @@
   }
 
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> content_;
+  scoped_refptr<FakePictureLayer> content_;
   int expect_swap_and_succeed_;
   int did_swaps_;
   int did_swap_and_succeed_;
 };
 
-SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
-    LayerTreeHostDamageTestNoDamageDoesNotSwap);
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostDamageTestNoDamageDoesNotSwap);
 
 class LayerTreeHostDamageTestForcedFullDamage : public LayerTreeHostDamageTest {
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
   void SetupTree() override {
-    root_ = FakeContentLayer::Create(layer_settings(), &client_);
-    child_ = FakeContentLayer::Create(layer_settings(), &client_);
+    root_ = FakePictureLayer::Create(layer_settings(), &client_);
+    child_ = FakePictureLayer::Create(layer_settings(), &client_);
 
     root_->SetBounds(gfx::Size(500, 500));
     child_->SetPosition(gfx::Point(100, 100));
@@ -296,21 +295,6 @@
         // should match the invalidation.
         EXPECT_EQ(gfx::RectF(100+10, 100+11, 12, 13).ToString(),
                   root_damage.ToString());
-
-        // TODO(danakj): Remove this when impl side painting is always on.
-        if (delegating_renderer() ||
-            host_impl->settings().impl_side_painting) {
-          // When using a delegating renderer, or using impl side painting, the
-          // entire child is considered damaged as we need to replace its
-          // resources with newly created ones. The damaged area is kept as it
-          // is, but entire child is painted.
-
-          // The paint rect should match the layer bounds.
-          gfx::RectF paint_rect = child_->LastPaintRect();
-          paint_rect.set_origin(child_->position());
-          EXPECT_EQ(gfx::RectF(100, 100, 30, 30).ToString(),
-                    paint_rect.ToString());
-        }
         EXPECT_FALSE(frame_data->has_no_damage);
 
         // If we damage part of the frame, but also damage the full
@@ -343,12 +327,12 @@
   void AfterTest() override {}
 
   FakeContentLayerClient client_;
-  scoped_refptr<FakeContentLayer> root_;
-  scoped_refptr<FakeContentLayer> child_;
+  scoped_refptr<FakePictureLayer> root_;
+  scoped_refptr<FakePictureLayer> child_;
   gfx::Rect child_damage_rect_;
 };
 
-SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(LayerTreeHostDamageTestForcedFullDamage);
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostDamageTestForcedFullDamage);
 
 class LayerTreeHostScrollbarDamageTest : public LayerTreeHostDamageTest {
   void SetupTree() override {
@@ -359,10 +343,11 @@
 
     scoped_refptr<Layer> scroll_clip_layer = Layer::Create(layer_settings());
     scoped_refptr<Layer> content_layer =
-        FakeContentLayer::Create(layer_settings(), &client_);
+        FakePictureLayer::Create(layer_settings(), &client_);
     content_layer->SetScrollClipLayerId(scroll_clip_layer->id());
     content_layer->SetScrollOffset(gfx::ScrollOffset(10, 20));
     content_layer->SetBounds(gfx::Size(100, 200));
+    content_layer->SetIsDrawable(true);
     scroll_clip_layer->SetBounds(
         gfx::Size(content_layer->bounds().width() - 30,
                   content_layer->bounds().height() - 50));
@@ -447,13 +432,25 @@
         host_impl->SetNeedsRedraw();
         break;
       case 3:
-        scroll_layer->SetBounds(gfx::Size(root->bounds().width() + 60,
-                                          root->bounds().height() + 100));
-        host_impl->SetNeedsRedraw();
+        // We will resize the content layer, on the main thread.
+        MainThreadTaskRunner()->PostTask(
+            FROM_HERE,
+            base::Bind(
+                &LayerTreeHostDamageTestScrollbarDoesDamage::ResizeScrollLayer,
+                base::Unretained(this)));
         break;
     }
   }
 
+  void ResizeScrollLayer() {
+    EXPECT_EQ(3, did_swaps_);
+    Layer* root = layer_tree_host()->root_layer();
+    Layer* scroll_clip_layer = root->child_at(0);
+    Layer* scroll_layer = scroll_clip_layer->child_at(0);
+    scroll_layer->SetBounds(
+        gfx::Size(root->bounds().width() + 60, root->bounds().height() + 100));
+  }
+
   void AfterTest() override { EXPECT_EQ(4, did_swaps_); }
 
   int did_swaps_;
diff --git a/cc/trees/layer_tree_host_unittest_no_message_loop.cc b/cc/trees/layer_tree_host_unittest_no_message_loop.cc
index 8b7b12d..cd13240d 100644
--- a/cc/trees/layer_tree_host_unittest_no_message_loop.cc
+++ b/cc/trees/layer_tree_host_unittest_no_message_loop.cc
@@ -76,6 +76,10 @@
   void DidCommitAndDrawFrame() override { did_commit_and_draw_frame_ = true; }
   void DidCompleteSwapBuffers() override {}
   void DidCompletePageScaleAnimation() override {}
+  void RecordFrameTimingEvents(
+      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events)
+      override {}
 
   // LayerTreeHostSingleThreadClient overrides.
   void DidPostSwapBuffers() override {}
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index 70dd418..b4783131 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -282,6 +282,8 @@
   if (is_root) {
     node->data.post_local.Scale(post_local_scale_factor,
                                 post_local_scale_factor);
+    node->data.post_local.Translate(layer->position().x(),
+                                    layer->position().y());
   } else {
     node->data.post_local_scale_factor = post_local_scale_factor;
     node->data.source_offset = source_offset;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 01b3c69..91816b9c 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -585,6 +585,13 @@
   NOTREACHED() << "Implemented by ThreadProxy for synchronous compositor.";
 }
 
+void SingleThreadProxy::PostFrameTimingEventsOnImplThread(
+    scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+    scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) {
+  layer_tree_host_->RecordFrameTimingEvents(composite_events.Pass(),
+                                            main_frame_events.Pass());
+}
+
 void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
   TRACE_EVENT0("cc,benchmark", "SingleThreadProxy::CompositeImmediately");
   DCHECK(Proxy::IsMainThread());
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index 98ac5e5..8cb5f665 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -113,6 +113,10 @@
   void DidPrepareTiles() override;
   void DidCompletePageScaleAnimationOnImplThread() override;
   void OnDrawForOutputSurface() override;
+  void PostFrameTimingEventsOnImplThread(
+      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events)
+      override;
 
   void SetDebugState(const LayerTreeDebugState& debug_state) override {}
 
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index 59ce0a7..94e8d89 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -1412,4 +1412,23 @@
   impl().scheduler->OnDrawForOutputSurface();
 }
 
+void ThreadProxy::PostFrameTimingEventsOnImplThread(
+    scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+    scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) {
+  DCHECK(IsImplThread());
+  Proxy::MainThreadTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&ThreadProxy::PostFrameTimingEvents, main_thread_weak_ptr_,
+                 base::Passed(composite_events.Pass()),
+                 base::Passed(main_frame_events.Pass())));
+}
+
+void ThreadProxy::PostFrameTimingEvents(
+    scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+    scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) {
+  DCHECK(IsMainThread());
+  layer_tree_host()->RecordFrameTimingEvents(composite_events.Pass(),
+                                             main_frame_events.Pass());
+}
+
 }  // namespace cc
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h
index f4f1f28..48aa661 100644
--- a/cc/trees/thread_proxy.h
+++ b/cc/trees/thread_proxy.h
@@ -217,6 +217,11 @@
   void DidPrepareTiles() override;
   void DidCompletePageScaleAnimationOnImplThread() override;
   void OnDrawForOutputSurface() override;
+  // This should only be called by LayerTreeHostImpl::PostFrameTimingEvents.
+  void PostFrameTimingEventsOnImplThread(
+      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events)
+      override;
 
   // SchedulerClient implementation
   void WillBeginImplFrame(const BeginFrameArgs& args) override;
@@ -292,6 +297,9 @@
   void SetInputThrottledUntilCommitOnImplThread(bool is_throttled);
   void SetDebugStateOnImplThread(const LayerTreeDebugState& debug_state);
   void SetDeferCommitsOnImplThread(bool defer_commits) const;
+  void PostFrameTimingEvents(
+      scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events);
 
   LayerTreeHost* layer_tree_host();
   const LayerTreeHost* layer_tree_host() const;
diff --git a/chrome/VERSION b/chrome/VERSION
index d8f2282..1f0c08d 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=45
 MINOR=0
-BUILD=2423
+BUILD=2427
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 32fd952..055e8ed 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -133,7 +133,7 @@
     "//chrome:page_info_connection_type_javagen",
     "//chrome:content_setting_javagen",
     "//chrome:content_settings_type_javagen",
-    "//components/enhanced_bookmarks:enhanced_bookmarks_launch_location_srcjar",
+    "//components/enhanced_bookmarks:enhanced_bookmarks_java_enums_srcjar",
   ]
 
   DEPRECATED_java_in_dir = "java/src"
@@ -562,14 +562,14 @@
   ]
 }
 
-#GYP: //chrome/android/chrome_apk.gyp:hosted_service_aidl
-android_aidl("hosted_service_aidl") {
-  import_include = "java_staging/src/org/chromium/chrome/browser/hosted"
+#GYP: //chrome/android/chrome_apk.gyp:custom_tabs_service_aidl
+android_aidl("custom_tabs_service_aidl") {
+  import_include = "java_staging/src/org/chromium/chrome/browser/customtabs"
   interface_file =
-      "java_staging/src/org/chromium/chrome/browser/hosted/common.aidl"
+      "java_staging/src/org/chromium/chrome/browser/customtabs/common.aidl"
   sources = [
-    "java_staging/src/org/chromium/chrome/browser/hosted/IBrowserConnectionCallback.aidl",
-    "java_staging/src/org/chromium/chrome/browser/hosted/IBrowserConnectionService.aidl",
+    "java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionCallback.aidl",
+    "java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionService.aidl",
   ]
 }
 
@@ -610,7 +610,7 @@
     "//ui/android:ui_java_resources",
     google_play_services_library,
   ]
-  srcjar_deps = [ ":hosted_service_aidl" ]
+  srcjar_deps = [ ":custom_tabs_service_aidl" ]
 }
 
 #GYP: //chrome/android/chrome_apk.gyp:chrome_staging_java
@@ -621,7 +621,6 @@
   ]
   custom_package = "com.google.android.apps.chrome"
   deps = [
-    ":chrome_template_resources",
     "//chrome/android:chrome_java_resources",
     "//components/policy:app_restrictions_resources",
     "//third_party/android_tools:android_support_v7_appcompat_resources",
@@ -632,16 +631,6 @@
   }
 }
 
-# GYP: //chrome/android/chrome_apk.gyp:chrome_template_resources
-jinja_template_resources("chrome_template_resources") {
-  resources = [
-    "java_staging/res_template/xml/searchable.xml",
-    "java_staging/res_template/xml/syncadapter.xml",
-  ]
-  res_dir = "java_staging/res_template"
-  variables = jinja_variables
-}
-
 # GYP: //chrome/android/chrome_apk.gyp:chrome_staging_test_java
 android_library("chrome_staging_test_java") {
   testonly = true
@@ -764,6 +753,16 @@
   variables = jinja_variables + [ "min_sdk_version=16" ]
 }
 
+# GYP: //chrome/android/chrome_apk.gyp:chrome_public_template_resources
+jinja_template_resources("chrome_public_template_resources") {
+  resources = [
+    "java_staging/res_template/xml/searchable.xml",
+    "java_staging/res_template/xml/syncadapter.xml",
+  ]
+  res_dir = "java_staging/res_template"
+  variables = jinja_variables
+}
+
 # GYP: //chrome/android/chrome_apk.gyp:libchrome_public
 shared_library("chrome_public") {
   deps = [
@@ -804,6 +803,7 @@
     ":chrome_public",
     ":chrome_public_apk_assets",
     ":chrome_public_apk_manifest",
+    ":chrome_public_template_resources",
     "//base:base_java",
     "//third_party/android_tools:google_play_services_default_resources",
   ]
@@ -820,9 +820,7 @@
 }
 
 # GYP: //chrome/android/chrome_apk.gyp:chrome_public_test_apk
-android_apk("chrome_public_test_apk") {
-  testonly = true
-
+instrumentation_test_apk("chrome_public_test_apk") {
   # TODO(GYP,cjhopman): Does this need version code/name?
   apk_name = "ChromePublicTest"
   apk_under_test = ":chrome_public_apk"
@@ -832,4 +830,5 @@
     "//chrome/test/android:chrome_staging_test_support_java",
     "//chrome/android:chrome_staging_test_java",
   ]
+  isolate_file = "../chrome_public_test_apk.isolate"
 }
diff --git a/chrome/android/chrome_apk.gyp b/chrome/android/chrome_apk.gyp
index 6d319177..5a4b5f7 100644
--- a/chrome/android/chrome_apk.gyp
+++ b/chrome/android/chrome_apk.gyp
@@ -9,7 +9,7 @@
   'variables': {
     'chromium_code': 1,
     'package_name': 'chrome_public_apk',
-    'manifest_package%': 'org.chromium.chrome',
+    'manifest_package': 'org.chromium.chrome',
     'chrome_public_apk_manifest': '<(SHARED_INTERMEDIATE_DIR)/chrome_public_apk_manifest/AndroidManifest.xml',
     'chrome_public_test_apk_manifest': '<(SHARED_INTERMEDIATE_DIR)/chrome_public_test_apk_manifest/AndroidManifest.xml',
     'never_lint': 1,
@@ -140,8 +140,7 @@
         'res_extra_files': ['<!@(find <(res_channel_dir) -type f)'],
       },
       'dependencies': [
-        'chrome_template_resources',
-        'hosted_service_aidl',
+        'custom_tabs_service_aidl',
         '<(DEPTH)/base/base.gyp:base_java',
         '<(DEPTH)/chrome/chrome.gyp:chrome_java',
         '<(DEPTH)/chrome/chrome.gyp:document_tab_model_info_proto_java',
@@ -191,8 +190,22 @@
       'includes': [ '../../build/java.gypi' ],
     },
     {
-      # GN: //chrome/android:chrome_template_resources
-      'target_name': 'chrome_template_resources',
+      # GN: //chrome/android:custom_tabs_service_aidl
+      'target_name': 'custom_tabs_service_aidl',
+      'type': 'none',
+      'variables': {
+        'aidl_interface_file': '<(chrome_java_dir)/src/org/chromium/chrome/browser/customtabs/common.aidl',
+        'aidl_import_include': '<(chrome_java_dir)/src/org/chromium/chrome/browser/customtabs',
+      },
+      'sources': [
+        '<(chrome_java_dir)/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionCallback.aidl',
+        '<(chrome_java_dir)/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionService.aidl',
+      ],
+      'includes': [ '../../build/java_aidl.gypi' ],
+    },
+    {
+      # GN: //chrome/android:chrome_public_template_resources
+      'target_name': 'chrome_public_template_resources',
       'type': 'none',
       'variables': {
         'jinja_inputs_base_dir': '<(chrome_java_dir)/res_template',
@@ -214,20 +227,6 @@
       'includes': [ '../../build/android/jinja_template.gypi' ],
     },
     {
-      # GN: //chrome/android:hosted_service_aidl
-      'target_name': 'hosted_service_aidl',
-      'type': 'none',
-      'variables': {
-        'aidl_interface_file': '<(chrome_java_dir)/src/org/chromium/chrome/browser/hosted/common.aidl',
-        'aidl_import_include': '<(chrome_java_dir)/src/org/chromium/chrome/browser/hosted',
-      },
-      'sources': [
-        '<(chrome_java_dir)/src/org/chromium/chrome/browser/hosted/IBrowserConnectionCallback.aidl',
-        '<(chrome_java_dir)/src/org/chromium/chrome/browser/hosted/IBrowserConnectionService.aidl',
-      ],
-      'includes': [ '../../build/java_aidl.gypi' ],
-    },
-    {
       # GN: //chrome/android:chrome_public
       'target_name': 'libchrome_public',
       'type': 'shared_library',
@@ -307,6 +306,7 @@
       },
       'dependencies': [
         'chrome_android_paks_copy',
+        'chrome_public_template_resources',
         'chrome_staging_java',
       ],
       'includes': [ 'chrome_apk.gypi' ],
@@ -400,8 +400,13 @@
         'java_in_dir_suffix': '/src_dummy',
         'apk_name': 'ChromePublicTest',
         'is_test_apk': 1,
+        'test_type': 'instrumentation',
+        'isolate_file': '../chrome_public_test_apk.isolate',
       },
-      'includes': [ '../../build/java_apk.gypi' ],
+      'includes': [
+        '../../build/java_apk.gypi',
+        '../../build/android/test_runner.gypi',
+      ],
     },
   ],
 }
diff --git a/chrome/android/java/res/drawable-hdpi/btn_trash.png b/chrome/android/java/res/drawable-hdpi/btn_trash.png
index 538ec57..9ee22eda 100644
--- a/chrome/android/java/res/drawable-hdpi/btn_trash.png
+++ b/chrome/android/java/res/drawable-hdpi/btn_trash.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/generic_card.png b/chrome/android/java/res/drawable-hdpi/generic_card.png
index 3bc9f44..fff62cfb 100644
--- a/chrome/android/java/res/drawable-hdpi/generic_card.png
+++ b/chrome/android/java/res/drawable-hdpi/generic_card.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/btn_trash.png b/chrome/android/java/res/drawable-mdpi/btn_trash.png
index 8bb0eb1..745c568 100644
--- a/chrome/android/java/res/drawable-mdpi/btn_trash.png
+++ b/chrome/android/java/res/drawable-mdpi/btn_trash.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/generic_card.png b/chrome/android/java/res/drawable-mdpi/generic_card.png
index d424b15..d2bd6f7 100644
--- a/chrome/android/java/res/drawable-mdpi/generic_card.png
+++ b/chrome/android/java/res/drawable-mdpi/generic_card.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/btn_trash.png b/chrome/android/java/res/drawable-xhdpi/btn_trash.png
index 5ba6b79c..c44f55c9 100644
--- a/chrome/android/java/res/drawable-xhdpi/btn_trash.png
+++ b/chrome/android/java/res/drawable-xhdpi/btn_trash.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/generic_card.png b/chrome/android/java/res/drawable-xhdpi/generic_card.png
index 60764db..51e790f4 100644
--- a/chrome/android/java/res/drawable-xhdpi/generic_card.png
+++ b/chrome/android/java/res/drawable-xhdpi/generic_card.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/btn_trash.png b/chrome/android/java/res/drawable-xxhdpi/btn_trash.png
index 1149a1d0..6050c58 100644
--- a/chrome/android/java/res/drawable-xxhdpi/btn_trash.png
+++ b/chrome/android/java/res/drawable-xxhdpi/btn_trash.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/generic_card.png b/chrome/android/java/res/drawable-xxhdpi/generic_card.png
index 5bd5265..8442ce6b 100644
--- a/chrome/android/java/res/drawable-xxhdpi/generic_card.png
+++ b/chrome/android/java/res/drawable-xxhdpi/generic_card.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/btn_trash.png b/chrome/android/java/res/drawable-xxxhdpi/btn_trash.png
index cdf773d..71e4f80 100644
--- a/chrome/android/java/res/drawable-xxxhdpi/btn_trash.png
+++ b/chrome/android/java/res/drawable-xxxhdpi/btn_trash.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/generic_card.png b/chrome/android/java/res/drawable-xxxhdpi/generic_card.png
index c0724522..c9796a3 100644
--- a/chrome/android/java/res/drawable-xxxhdpi/generic_card.png
+++ b/chrome/android/java/res/drawable-xxxhdpi/generic_card.png
Binary files differ
diff --git a/chrome/android/java/res/layout/clear_storage.xml b/chrome/android/java/res/layout/clear_storage.xml
index de39488..7a3a587 100644
--- a/chrome/android/java/res/layout/clear_storage.xml
+++ b/chrome/android/java/res/layout/clear_storage.xml
@@ -3,8 +3,11 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+<org.chromium.chrome.browser.widget.TintedImageView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:chrome="http://schemas.android.com/apk/res-auto"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:contentDescription="@string/webstorage_clear_data_dialog_title"
-    android:src="@drawable/btn_trash"/>
+    android:src="@drawable/btn_trash"
+    chrome:tint="@color/blue_mode_tint"/>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/EmptyTabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/EmptyTabObserver.java
index 0a3b9af..b90f505e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/EmptyTabObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/EmptyTabObserver.java
@@ -40,7 +40,7 @@
     public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) { }
 
     @Override
-    public void onPageLoadStarted(Tab tab) { }
+    public void onPageLoadStarted(Tab tab, String url) { }
 
     @Override
     public void onPageLoadFinished(Tab tab) { }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
index 0778b50..279e5e2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
@@ -1518,7 +1518,7 @@
 
         clearHungRendererState();
 
-        for (TabObserver observer : mObservers) observer.onPageLoadStarted(this);
+        for (TabObserver observer : mObservers) observer.onPageLoadStarted(this, validatedUrl);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/TabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/TabObserver.java
index f863dc7..5a1dd09e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/TabObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/TabObserver.java
@@ -74,7 +74,6 @@
      */
     void onLoadUrl(Tab tab, LoadUrlParams params, int loadType);
 
-
     /**
      * Called when a tab has started to load a page.
      * <p>
@@ -86,8 +85,9 @@
      * {@link #onLoadStopped(Tab)} should be used to drive updates.
      *
      * @param tab The notifying {@link Tab}.
+     * @param url The committed URL being navigated to.
      */
-    void onPageLoadStarted(Tab tab);
+    void onPageLoadStarted(Tab tab, String url);
 
     /**
      * Called when a tab has finished loading a page.
@@ -167,9 +167,10 @@
     // WebContentsDelegateAndroid methods ---------------------------------------------------------
 
     /**
-     * Called when the WebContents starts loading. Different from {@link #onPageLoadStarted(Tab)},
-     * if the user is navigated to a different url while staying in the same html document,
-     * {@link #onLoadStarted(Tab)} will be called, while {@link #onPageLoadStarted(Tab)} will not.
+     * Called when the WebContents starts loading. Different from
+     * {@link #onPageLoadStarted(Tab, String)}, if the user is navigated to a different url while
+     * staying in the same html document, {@link #onLoadStarted(Tab)} will be called, while
+     * {@link #onPageLoadStarted(Tab, String)} will not.
      * @param tab The notifying {@link Tab}.
      */
     void onLoadStarted(Tab tab);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java b/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
index 74b31229..76da4f0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
@@ -39,6 +39,7 @@
     private final Set<String> mDnsRequestsInFlight;
     private final Map<String, Profile> mPendingPreconnectWithProfile;
 
+    private boolean mPrerenderIsAllowed;
     private WebContents mPrerenderedWebContents;
     private boolean mPrerendered;
     private ViewGroup mMainView;
@@ -54,11 +55,22 @@
     }
 
     private WarmupManager() {
+        mPrerenderIsAllowed = true;
         mDnsRequestsInFlight = new HashSet<String>();
         mPendingPreconnectWithProfile = new HashMap<String, Profile>();
     }
 
     /**
+     * Disallow prerendering from now until the browser process death.
+     */
+    public void disallowPrerendering() {
+        ThreadUtils.assertOnUiThread();
+        mPrerenderIsAllowed = false;
+        cancelCurrentPrerender();
+        mExternalPrerenderHandler = null;
+    }
+
+    /**
      * Check whether prerender manager has the given url prerendered. This also works with
      * redirected urls.
      *
@@ -69,6 +81,7 @@
      */
     public boolean hasPrerenderedUrl(String url) {
         ThreadUtils.assertOnUiThread();
+        if (!mPrerenderIsAllowed) return false;
         return hasAnyPrerenderedUrl() && ExternalPrerenderHandler.hasPrerenderedUrl(
                 Profile.getLastUsedProfile(), url, mPrerenderedWebContents);
     }
@@ -78,6 +91,7 @@
      */
     public boolean hasAnyPrerenderedUrl() {
         ThreadUtils.assertOnUiThread();
+        if (!mPrerenderIsAllowed) return false;
         return mPrerendered;
     }
 
@@ -86,6 +100,7 @@
      */
     public WebContents takePrerenderedWebContents() {
         ThreadUtils.assertOnUiThread();
+        if (!mPrerenderIsAllowed) return null;
         WebContents prerenderedWebContents = mPrerenderedWebContents;
         assert (mPrerenderedWebContents != null);
         mPrerenderedWebContents = null;
@@ -105,6 +120,7 @@
     public void prerenderUrl(final String url, final String referrer,
             final int widthPix, final int heightPix) {
         ThreadUtils.assertOnUiThread();
+        if (!mPrerenderIsAllowed) return;
         clearWebContentsIfNecessary();
         if (mExternalPrerenderHandler == null) {
             mExternalPrerenderHandler = new ExternalPrerenderHandler();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
index 782da04..37e024f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
@@ -12,6 +12,8 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.UrlUtilities;
+import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
+import org.chromium.chrome.browser.preferences.bandwidth.DataReductionProxyUma;
 import org.chromium.chrome.browser.search_engines.TemplateUrlService;
 
 /**
@@ -85,6 +87,9 @@
 
             if (!params.imageWasFetchedLoFi()) {
                 menu.findItem(R.id.contextmenu_show_original_image).setVisible(false);
+            } else {
+                DataReductionProxyUma.dataReductionProxyLoFiUIAction(
+                        DataReductionProxyUma.ACTION_LOAD_IMAGE_CONTEXT_MENU_SHOWN);
             }
 
             // Avoid showing open image option for same image which is already opened.
@@ -121,6 +126,13 @@
                 || itemId == R.id.contextmenu_open_original_image_in_new_tab) {
             mDelegate.onOpenImageInNewTab(params.getSrcUrl(), params.getReferrer());
         } else if (itemId == R.id.contextmenu_show_original_image) {
+            DataReductionProxyUma.dataReductionProxyLoFiUIAction(
+                    DataReductionProxyUma.ACTION_LOAD_IMAGE_CONTEXT_MENU_CLICKED);
+            if (!DataReductionProxySettings.getInstance().wasLoFiShowImageRequestedBefore()) {
+                DataReductionProxyUma.dataReductionProxyLoFiUIAction(
+                        DataReductionProxyUma.ACTION_LOAD_IMAGE_CONTEXT_MENU_CLICKED_ON_PAGE);
+                DataReductionProxySettings.getInstance().setLoFiShowImageRequested();
+            }
             mDelegate.onShowOriginalImage();
         } else if (itemId == R.id.contextmenu_copy_link_address_text) {
             mDelegate.onSaveToClipboard(params.getUnfilteredLinkUrl(), true);
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 26924b2..632fb07 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
@@ -429,22 +429,6 @@
     }
 
     /**
-     * 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
-     * (disabled, enabled or uninitialized). Calling more than once is fine.
-     * @param promoTapsRemaining The number of taps remaining, or -1 if not applicable.
-     */
-    @Deprecated
-    public static void logPreferenceState(int promoTapsRemaining) {
-        RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchPreferenceState",
-                getPreferenceValue(), PREFERENCE_HISTOGRAM_BOUNDARY);
-        if (promoTapsRemaining != PROMO_TAPS_REMAINING_INVALID) {
-            RecordHistogram.recordCountHistogram("Search.ContextualSearchPromoTapsRemaining",
-                    promoTapsRemaining);
-        }
-    }
-
-    /**
      * Logs the given number of promo taps remaining.  Should be called only for users that
      * are still undecided.
      * @param promoTapsRemaining The number of taps remaining (should not be negative).
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java
index df8d40a..6f65835 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java
@@ -248,7 +248,7 @@
         final String okButtonText = mContext.getResources().getString(R.string.ok);
         final String cancelButtonText = mContext.getResources().getString(R.string.cancel);
 
-        mTab.getInfoBarContainer().addInfoBar(new ConfirmInfoBar(0,
+        mTab.getInfoBarContainer().addInfoBar(new ConfirmInfoBar(
                 this, drawableId, null, titleText, null, okButtonText, cancelButtonText));
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksBridge.java
index e629bfe..080bced 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksBridge.java
@@ -268,6 +268,13 @@
     }
 
     /**
+     * @see |enhanced_bookmarks::GetDefaultViewMode()|
+     */
+    public static int getDefaultViewMode() {
+        return nativeGetDefaultViewMode();
+    }
+
+    /**
      * @return Return the cache if it is stored in the static weak reference, or create a new empty
      *         one if the reference is empty.
      */
@@ -337,4 +344,5 @@
             String url, SalientImageCallback callback);
     private native void nativeFetchImageForTab(long nativeEnhancedBookmarksBridge,
             WebContents webContents);
+    private static native int nativeGetDefaultViewMode();
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollector.java b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollector.java
index ec760af0..bcf16c6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollector.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollector.java
@@ -8,7 +8,9 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.browser.profiles.Profile;
 
+import java.util.Collections;
 import java.util.EnumMap;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -21,6 +23,36 @@
     private static final String TAG = "Feedback";
 
     /**
+     * FeedbackData contains the set of information that is to be included in a feedback report.
+     */
+    public static final class FeedbackData {
+        private final Map<Type, Result> mConnections;
+
+        FeedbackData(Map<Type, Result> connections) {
+            mConnections = connections;
+        }
+
+        /**
+         * @return a {@link Map} with information about connection status for different connection
+         * types.
+         */
+        public Map<Type, Result> getConnections() {
+            return Collections.unmodifiableMap(mConnections);
+        }
+
+        /**
+         * @return a {@link Map} with all the data fields for this feedback.
+         */
+        public Map<String, String> toMap() {
+            Map<String, String> map = new HashMap<>();
+            for (Map.Entry<Type, Result> entry : mConnections.entrySet()) {
+                map.put(entry.getKey().name(), entry.getValue().name());
+            }
+            return map;
+        }
+    }
+
+    /**
      * The type of network stack and connectivity check this result is about.
      */
     public enum Type { CHROME_HTTP, CHROME_HTTPS, SYSTEM_HTTP, SYSTEM_HTTPS }
@@ -31,7 +63,7 @@
      */
     public enum Result { UNKNOWN, NOT_CONNECTED, CONNECTED }
 
-    private static class ConnectivityCheckerFuture implements Future<Map<Type, Result>> {
+    private static class ConnectivityCheckerFuture implements Future<FeedbackData> {
         private final Map<Type, Result> mResult = new EnumMap<Type, Result>(Type.class);
 
         private class SingleTypeTask implements ConnectivityChecker.ConnectivityCheckerCallback {
@@ -97,7 +129,7 @@
         }
 
         @Override
-        public Map<Type, Result> get() {
+        public FeedbackData get() {
             ThreadUtils.assertOnUiThread();
             Map<Type, Result> result = new EnumMap<Type, Result>(Type.class);
             // Ensure the map is filled with a result for all {@link Type}s.
@@ -108,11 +140,11 @@
                     result.put(type, Result.UNKNOWN);
                 }
             }
-            return result;
+            return new FeedbackData(result);
         }
 
         @Override
-        public Map<Type, Result> get(long l, TimeUnit timeUnit) {
+        public FeedbackData get(long l, TimeUnit timeUnit) {
             return get();
         }
 
@@ -143,7 +175,7 @@
      * @param timeoutMs number of milliseconds to wait before giving up waiting for a connection.
      * @return a Future to retrieve the results.
      */
-    public static Future<Map<Type, Result>> startChecks(Profile profile, int timeoutMs) {
+    public static Future<FeedbackData> startChecks(Profile profile, int timeoutMs) {
         ThreadUtils.assertOnUiThread();
         ConnectivityCheckerFuture future = new ConnectivityCheckerFuture();
         future.startChecks(profile, timeoutMs);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AccountChooserInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AccountChooserInfoBar.java
index 6678220..9455802 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AccountChooserInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AccountChooserInfoBar.java
@@ -12,7 +12,6 @@
 import android.widget.ArrayAdapter;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.TextView;
 
@@ -28,43 +27,32 @@
  * full name in case they are available.
  */
 public class AccountChooserInfoBar extends InfoBar {
+    private long mNativePtr;
     private final Credential[] mCredentials;
     private final ImageView[] mAvatarViews;
 
     /**
      * Creates and shows the infobar wich allows user to choose credentials for login.
-     * @param nativeInfoBar Pointer to the native infobar.
      * @param enumeratedIconId Enum ID corresponding to the icon that the infobar will show.
      * @param credentials Credentials to display in the infobar.
      */
     @CalledByNative
-    private static InfoBar show(
-            long nativeInfoBar, int enumeratedIconId, Credential[] credentials) {
-        return new AccountChooserInfoBar(
-                nativeInfoBar, ResourceId.mapToDrawableId(enumeratedIconId), credentials);
+    private static InfoBar show(int enumeratedIconId, Credential[] credentials) {
+        return new AccountChooserInfoBar(ResourceId.mapToDrawableId(enumeratedIconId), credentials);
     }
 
     /**
      * Creates and shows the infobar  which allows user to choose credentials.
-     * @param nativeInfoBar Pointer to the native infobar.
      * @param iconDrawableId Drawable ID corresponding to the icon that the infobar will show.
      * @param credentials Credentials to display in the infobar.
      */
-    public AccountChooserInfoBar(long nativeInfoBar, int iconDrawableId, Credential[] credentials) {
+    public AccountChooserInfoBar(int iconDrawableId, Credential[] credentials) {
         super(null /* Infobar Listener */, iconDrawableId, null /* bitmap*/,
                 null /* message to show */);
-        setNativeInfoBar(nativeInfoBar);
         mCredentials = credentials.clone();
         mAvatarViews = new ImageView[mCredentials.length];
     }
 
-
-    @Override
-    public void onCloseButtonClicked() {
-        // Notifies the native infobar, which closes the infobar.
-        nativeOnCloseButtonClicked(mNativeInfoBarPtr);
-    }
-
     @Override
     public void onButtonClicked(boolean isPrimaryButton) {
         onCloseButtonClicked();
@@ -97,8 +85,9 @@
             @Override
             public View getView(int position, View convertView, ViewGroup parent) {
                 if (convertView == null) {
-                    convertView = (LinearLayout) LayoutInflater.from(getContext()).inflate(
-                        R.layout.account_chooser_infobar_item, parent, false);
+                    convertView =
+                            LayoutInflater.from(getContext())
+                                    .inflate(R.layout.account_chooser_infobar_item, parent, false);
                 } else {
                     int oldPosition = (int) convertView.getTag();
                     mAvatarViews[oldPosition] = null;
@@ -126,7 +115,7 @@
                     @Override
                     public void onClick(View view) {
                         nativeOnCredentialClicked(
-                                mNativeInfoBarPtr, currentCredentialIndex, credentialType);
+                                mNativePtr, currentCredentialIndex, credentialType);
                     }
                 });
                 return convertView;
@@ -155,6 +144,17 @@
         layout.setCustomViewInButtonRow(OverflowSelector.createOverflowSelector(getContext()));
     }
 
+    @CalledByNative
+    private void setNativePtr(long nativePtr) {
+        mNativePtr = nativePtr;
+    }
+
+    @Override
+    protected void onNativeDestroyed() {
+        mNativePtr = 0;
+        super.onNativeDestroyed();
+    }
+
     private native void nativeOnCredentialClicked(
             long nativeAccountChooserInfoBar, int credentialId, int credentialType);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java
index f566636..0476a2a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java
@@ -45,9 +45,8 @@
     private final String mAppUrl;
 
     // Banner for native apps.
-    private AppBannerInfoBarAndroid(
-            long nativeInfoBar, String appTitle, Bitmap iconBitmap, AppData data) {
-        super(nativeInfoBar, null, 0, iconBitmap, appTitle, null, data.installButtonText(), null);
+    private AppBannerInfoBarAndroid(String appTitle, Bitmap iconBitmap, AppData data) {
+        super(null, 0, iconBitmap, appTitle, null, data.installButtonText(), null);
         mAppTitle = appTitle;
         mAppData = data;
         mAppUrl = null;
@@ -55,9 +54,8 @@
     }
 
     // Banner for web apps.
-    private AppBannerInfoBarAndroid(
-            long nativeInfoBar, String appTitle, Bitmap iconBitmap, String url) {
-        super(nativeInfoBar, null, 0, iconBitmap, appTitle, null, getAddToHomescreenText(), null);
+    private AppBannerInfoBarAndroid(String appTitle, Bitmap iconBitmap, String url) {
+        super(null, 0, iconBitmap, appTitle, null, getAddToHomescreenText(), null);
         mAppTitle = appTitle;
         mAppData = null;
         mAppUrl = url;
@@ -170,13 +168,12 @@
 
     @CalledByNative
     private static InfoBar createNativeAppInfoBar(
-            long nativeInfoBar, String appTitle, Bitmap iconBitmap, AppData appData) {
-        return new AppBannerInfoBarAndroid(nativeInfoBar, appTitle, iconBitmap, appData);
+            String appTitle, Bitmap iconBitmap, AppData appData) {
+        return new AppBannerInfoBarAndroid(appTitle, iconBitmap, appData);
     }
 
     @CalledByNative
-    private static InfoBar createWebAppInfoBar(
-            long nativeInfoBar, String appTitle, Bitmap iconBitmap, String url) {
-        return new AppBannerInfoBarAndroid(nativeInfoBar, appTitle, iconBitmap, url);
+    private static InfoBar createWebAppInfoBar(String appTitle, Bitmap iconBitmap, String url) {
+        return new AppBannerInfoBarAndroid(appTitle, iconBitmap, url);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java
index 4564ebd..c33b904 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java
@@ -24,15 +24,14 @@
     /** Notified when one of the buttons is clicked. */
     private final InfoBarListeners.Confirm mConfirmListener;
 
-    public ConfirmInfoBar(long nativeInfoBar, InfoBarListeners.Confirm confirmListener,
-            int iconDrawableId, Bitmap iconBitmap, String message, String linkText,
-            String primaryButtonText, String secondaryButtonText) {
+    public ConfirmInfoBar(InfoBarListeners.Confirm confirmListener, int iconDrawableId,
+            Bitmap iconBitmap, String message, String linkText, String primaryButtonText,
+            String secondaryButtonText) {
         super(confirmListener, iconDrawableId, iconBitmap, message);
         mPrimaryButtonText = primaryButtonText;
         mSecondaryButtonText = secondaryButtonText;
         mTertiaryButtonText = linkText;
         mConfirmListener = confirmListener;
-        setNativeInfoBar(nativeInfoBar);
     }
 
     @Override
@@ -46,18 +45,7 @@
             mConfirmListener.onConfirmInfoBarButtonClicked(this, isPrimaryButton);
         }
 
-        if (mNativeInfoBarPtr != 0) {
-            int action = isPrimaryButton ? InfoBar.ACTION_TYPE_OK : InfoBar.ACTION_TYPE_CANCEL;
-            nativeOnButtonClicked(mNativeInfoBarPtr, action, "");
-        }
-    }
-
-    @Override
-    public void onCloseButtonClicked() {
-        if (mNativeInfoBarPtr != 0) {
-            nativeOnCloseButtonClicked(mNativeInfoBarPtr);
-        } else {
-            super.dismissJavaOnlyInfoBar();
-        }
+        int action = isPrimaryButton ? InfoBar.ACTION_TYPE_OK : InfoBar.ACTION_TYPE_CANCEL;
+        onButtonClicked(action, "");
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java
index 601eb6c0..d5d0ad1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBarDelegate.java
@@ -24,23 +24,22 @@
 
     /**
      * Creates and begins the process for showing a ConfirmInfoBar.
-     * @param nativeInfoBar Pointer to the C++ InfoBar corresponding to the Java InfoBar.
      * @param enumeratedIconId ID corresponding to the icon that will be shown for the InfoBar.
      *                         The ID must have been mapped using the ResourceMapper class before
      *                         passing it to this function.
-     * @param bitmap Bitmap to use if there is no equivalent Java resource for enumeratedIconId.
+     * @param iconBitmap Bitmap to use if there is no equivalent Java resource for enumeratedIconId.
      * @param message Message to display to the user indicating what the InfoBar is for.
      * @param linkText Link text to display in addition to the message.
      * @param buttonOk String to display on the OK button.
      * @param buttonCancel String to display on the Cancel button.
      */
     @CalledByNative
-    InfoBar showConfirmInfoBar(long nativeInfoBar, int enumeratedIconId, Bitmap iconBitmap,
-            String message, String linkText, String buttonOk, String buttonCancel) {
+    InfoBar showConfirmInfoBar(int enumeratedIconId, Bitmap iconBitmap, String message,
+            String linkText, String buttonOk, String buttonCancel) {
         int drawableId = ResourceId.mapToDrawableId(enumeratedIconId);
 
-        ConfirmInfoBar infoBar = new ConfirmInfoBar(nativeInfoBar, null, drawableId, iconBitmap,
-                message, linkText, buttonOk, buttonCancel);
+        ConfirmInfoBar infoBar = new ConfirmInfoBar(
+                null, drawableId, iconBitmap, message, linkText, buttonOk, buttonCancel);
         return infoBar;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBar.java
index 325b931..9d534f0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBar.java
@@ -31,8 +31,8 @@
         DataReductionProxyInfoBarDelegate.launch(webContents, linkUrl);
     }
 
-    DataReductionProxyInfoBar(long nativeInfoBar, int iconDrawableId) {
-        super(nativeInfoBar, null, iconDrawableId, null, sTitle, sLinkText, null, null);
+    DataReductionProxyInfoBar(int iconDrawableId) {
+        super(null, iconDrawableId, null, sTitle, sLinkText, null, null);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBarDelegate.java
index 9ae5ac5..ca54d0d7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBarDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DataReductionProxyInfoBarDelegate.java
@@ -30,18 +30,16 @@
 
     /**
      * Creates and begins the process for showing a DataReductionProxyInfoBarDelegate.
-     * @param nativeInfoBar Pointer to the C++ InfoBar corresponding to the Java InfoBar.
      * @param enumeratedIconId ID corresponding to the icon that will be shown for the InfoBar.
      *                         The ID must have been mapped using the ResourceMapper class before
      *                         passing it to this function.
      */
     @CalledByNative
-    InfoBar showDataReductionProxyInfoBar(long nativeInfoBar, int enumeratedIconId) {
+    InfoBar showDataReductionProxyInfoBar(int enumeratedIconId) {
         int drawableId = ResourceId.mapToDrawableId(enumeratedIconId);
-        DataReductionProxyInfoBar infoBar = new DataReductionProxyInfoBar(
-                nativeInfoBar, drawableId);
+        DataReductionProxyInfoBar infoBar = new DataReductionProxyInfoBar(drawableId);
         return infoBar;
     }
 
-    protected static native void nativeLaunch(WebContents webContents, String linkUrl);
+    private static native void nativeLaunch(WebContents webContents, String linkUrl);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DownloadOverwriteInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DownloadOverwriteInfoBar.java
index c16e0ea..5aa601f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/DownloadOverwriteInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/DownloadOverwriteInfoBar.java
@@ -33,37 +33,28 @@
     private final String mDirFullPath;
 
     @CalledByNative
-    private static InfoBar createInfoBar(
-            long nativeInfoBar, String fileName, String dirName, String dirFullPath) {
-        return new DownloadOverwriteInfoBar(nativeInfoBar, fileName, dirName, dirFullPath);
+    private static InfoBar createInfoBar(String fileName, String dirName, String dirFullPath) {
+        return new DownloadOverwriteInfoBar(fileName, dirName, dirFullPath);
     }
 
     /**
      * Constructs DownloadOverwriteInfoBar.
-     * @param nativeInfoBarPtr Pointer value of the native infobar.
      * @param fileName The file name. ex) example.jpg
      * @param dirName The dir name. ex) Downloads
      * @param dirFullPath The full dir path. ex) sdcards/Downloads
      */
-    private DownloadOverwriteInfoBar(
-            long nativeInfoBarPtr, String fileName, String dirName, String dirFullPath) {
+    private DownloadOverwriteInfoBar(String fileName, String dirName, String dirFullPath) {
         super(null, R.drawable.infobar_downloading, null, null);
         mFileName = fileName;
         mDirName = dirName;
         mDirFullPath = dirFullPath;
-        setNativeInfoBar(nativeInfoBarPtr);
-    }
-
-    @Override
-    public void onCloseButtonClicked() {
-        if (mNativeInfoBarPtr != 0) nativeOnCloseButtonClicked(mNativeInfoBarPtr);
     }
 
     @Override
     public void onButtonClicked(boolean isPrimaryButton) {
         int action = isPrimaryButton ? InfoBar.ACTION_TYPE_OVERWRITE
                                      : InfoBar.ACTION_TYPE_CREATE_NEW_FILE;
-        if (mNativeInfoBarPtr != 0) nativeOnButtonClicked(mNativeInfoBarPtr, action, "");
+        onButtonClicked(action, "");
     }
 
     private CharSequence getMessageText(Context context) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBar.java
index f43c8ef..cba284c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBar.java
@@ -20,17 +20,15 @@
 
     /**
      * Creates and shows the infobar to notify that the generated password was saved.
-     * @param nativeInfoBar Pointer to the native infobar.
      * @param iconDrawableId Drawable ID corresponding to the icon that the infobar will show.
      * @param messageText Message to display in the infobar.
      * @param inlineLinkRangeStart The start of the range of the messageText that should be a link.
      * @param inlineLinkRangeEnd The end of the range of the messageText that should be a link.
      * @param buttonLabel String to display on the button.
      */
-    public GeneratedPasswordSavedInfoBar(long nativeInfoBar, int iconDrawableId, String messageText,
+    public GeneratedPasswordSavedInfoBar(int iconDrawableId, String messageText,
             int inlineLinkRangeStart, int inlineLinkRangeEnd, String buttonLabel) {
         super(null, iconDrawableId, null, null);
-        setNativeInfoBar(nativeInfoBar);
         mMessageText = messageText;
         mInlineLinkRangeStart = inlineLinkRangeStart;
         mInlineLinkRangeEnd = inlineLinkRangeEnd;
@@ -62,15 +60,6 @@
      */
     @Override
     public void onButtonClicked(boolean isPrimaryButton) {
-        nativeOnButtonClicked(mNativeInfoBarPtr, InfoBar.ACTION_TYPE_OK, "");
-    }
-
-    /**
-     * Called when the close button is clicked. Notifies the native infobar, which closes the
-     * infobar.
-     */
-    @Override
-    public void onCloseButtonClicked() {
-        nativeOnCloseButtonClicked(mNativeInfoBarPtr);
+        onButtonClicked(InfoBar.ACTION_TYPE_OK, "");
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBarDelegate.java
index db4cac5..6f0240b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBarDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBarDelegate.java
@@ -13,7 +13,6 @@
 public class GeneratedPasswordSavedInfoBarDelegate {
     /**
      * Creates and shows the infobar to notify that the generated password was saved.
-     * @param nativeInfoBar Pointer to the native infobar.
      * @param enumeratedIconId Enum ID corresponding to the icon that the infobar will show.
      * @param messageText Message to display in the infobar.
      * @param inlineLinkRangeStart The start of the range of the messageText that should be a link.
@@ -21,10 +20,9 @@
      * @param buttonLabel String to display on the button.
      */
     @CalledByNative
-    private static InfoBar show(long nativeInfoBar, int enumeratedIconId, String messageText,
-            int inlineLinkRangeStart, int inlineLinkRangeEnd, String buttonLabel) {
-        return new GeneratedPasswordSavedInfoBar(nativeInfoBar,
-                ResourceId.mapToDrawableId(enumeratedIconId), messageText, inlineLinkRangeStart,
-                inlineLinkRangeEnd, buttonLabel);
+    private static InfoBar show(int enumeratedIconId, String messageText, int inlineLinkRangeStart,
+            int inlineLinkRangeEnd, String buttonLabel) {
+        return new GeneratedPasswordSavedInfoBar(ResourceId.mapToDrawableId(enumeratedIconId),
+                messageText, inlineLinkRangeStart, inlineLinkRangeEnd, buttonLabel);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java
index 26c1a29..5395ad4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java
@@ -52,11 +52,10 @@
     private boolean mExpireOnNavigation;
     private boolean mIsDismissed;
     private boolean mControlsEnabled;
+    private boolean mIsJavaOnlyInfoBar = true;
 
-    // This cannot be private until the swap in place infrastructure is
-    // improved since subclasses need to access a possibly replaced native
-    // pointer.
-    protected long mNativeInfoBarPtr;
+    // This points to the InfoBarAndroid class not any of its subclasses.
+    private long mNativeInfoBarPtr;
 
     // Used by tests to reference infobars.
     private final int mId;
@@ -82,23 +81,21 @@
 
     /**
      * Stores a pointer to the native-side counterpart of this InfoBar.
-     * @param nativeInfoBarPtr Pointer to the NativeInfoBar.
+     * @param nativeInfoBarPtr Pointer to the native InfoBarAndroid, not to its subclass.
      */
-    protected void setNativeInfoBar(long nativeInfoBarPtr) {
+    @CalledByNative
+    private void setNativeInfoBar(long nativeInfoBarPtr) {
         if (nativeInfoBarPtr != 0) {
             // The native code takes care of expiring infobars on navigations.
             mExpireOnNavigation = false;
             mNativeInfoBarPtr = nativeInfoBarPtr;
+            mIsJavaOnlyInfoBar = false;
         }
     }
 
-    /**
-     * Change the pointer to the native-side counterpart of this InfoBar.  Native-side code is
-     * responsible for managing the cleanup of the pointer.
-     * @param newInfoBarPtr Pointer to the NativeInfoBar.
-     */
-    protected void replaceNativePointer(long newInfoBarPtr) {
-        mNativeInfoBarPtr = newInfoBarPtr;
+    @CalledByNative
+    protected void onNativeDestroyed() {
+        mNativeInfoBarPtr = 0;
     }
 
     /**
@@ -109,7 +106,7 @@
      * It should really be removed once all infobars have a C++ counterpart.
      */
     public final boolean shouldExpire() {
-        return mExpireOnNavigation && mNativeInfoBarPtr == 0;
+        return mExpireOnNavigation && mIsJavaOnlyInfoBar;
     }
 
     // Sets whether the bar should be dismissed when a navigation occurs.
@@ -118,20 +115,6 @@
     }
 
     /**
-     * @return true if this java infobar owns this {@code nativePointer}
-     */
-    boolean ownsNativeInfoBar(long nativePointer) {
-        return mNativeInfoBarPtr == nativePointer;
-    }
-
-    /**
-     * @return whether or not the InfoBar has been dismissed.
-     */
-    protected boolean isDismissed() {
-        return mIsDismissed;
-    }
-
-    /**
      * Sets the Context used when creating the InfoBar.
      */
     protected void setContext(Context context) {
@@ -237,8 +220,25 @@
 
     @Override
     public void onLinkClicked() {
-        if (mNativeInfoBarPtr != 0) {
-            nativeOnLinkClicked(mNativeInfoBarPtr);
+        if (mNativeInfoBarPtr != 0) nativeOnLinkClicked(mNativeInfoBarPtr);
+    }
+
+    /**
+     * Performs some action related to the button being clicked.
+     *
+     * @param action The type of action defined as ACTION_* in this class.
+     * @param actionValue An additional string associated with the action if any. "" if none.
+     */
+    protected void onButtonClicked(int action, String actionValue) {
+        if (mNativeInfoBarPtr != 0) nativeOnButtonClicked(mNativeInfoBarPtr, action, actionValue);
+    }
+
+    @Override
+    public void onCloseButtonClicked() {
+        if (mIsJavaOnlyInfoBar) {
+            dismissJavaOnlyInfoBar();
+        } else {
+            if (mNativeInfoBarPtr != 0) nativeOnCloseButtonClicked(mNativeInfoBarPtr);
         }
     }
 
@@ -263,8 +263,8 @@
         mListener = listener;
     }
 
-    protected native void nativeOnLinkClicked(long nativeInfoBarAndroid);
-    protected native void nativeOnButtonClicked(
+    private native void nativeOnLinkClicked(long nativeInfoBarAndroid);
+    private native void nativeOnButtonClicked(
             long nativeInfoBarAndroid, int action, String actionValue);
-    protected native void nativeOnCloseButtonClicked(long nativeInfoBarAndroid);
+    private native void nativeOnCloseButtonClicked(long nativeInfoBarAndroid);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainer.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainer.java
index 45efdf3..dc0fbb2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainer.java
@@ -15,6 +15,7 @@
 import android.widget.LinearLayout;
 
 import org.chromium.base.CalledByNative;
+import org.chromium.base.ObserverList;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.Tab;
@@ -54,6 +55,27 @@
         void notifyAnimationFinished(int animationType);
     }
 
+    /**
+     * An observer that is notified of changes to a {@link InfoBarContainer} object.
+     */
+    public interface InfoBarContainerObserver {
+        /**
+         * Called when an {@link InfoBar} is about to be added (before the animation).
+         * @param container The notifying {@link InfoBarContainer}
+         * @param infoBar An {@link InfoBar} being added
+         * @param isFirst Whether the infobar container was empty
+         */
+        void onAddInfoBar(InfoBarContainer container, InfoBar infoBar, boolean isFirst);
+
+        /**
+         * Called when an {@link InfoBar} is about to be removed (before the animation).
+         * @param container The notifying {@link InfoBarContainer}
+         * @param infoBar An {@link InfoBar} being removed
+         * @param isLast Whether the infobar container is going to be empty
+         */
+        void onRemoveInfoBar(InfoBarContainer container, InfoBar infoBar, boolean isLast);
+    }
+
     private static class InfoBarTransitionInfo {
         // InfoBar being animated.
         public InfoBar target;
@@ -111,6 +133,9 @@
 
     private Paint mTopBorderPaint;
 
+    private final ObserverList<InfoBarContainerObserver> mObservers =
+            new ObserverList<InfoBarContainerObserver>();
+
     public InfoBarContainer(Context context, int tabId, ViewGroup parentView, Tab tab) {
         super(context, null);
         tab.addObserver(getTabObserver());
@@ -147,6 +172,22 @@
         mNativeInfoBarContainer = nativeInit();
     }
 
+    /**
+     * Adds an {@link InfoBarContainerObserver}.
+     * @param observer The {@link InfoBarContainerObserver} to add.
+     */
+    public void addObserver(InfoBarContainerObserver observer) {
+        mObservers.addObserver(observer);
+    }
+
+    /**
+     * Removes a {@link InfoBarContainerObserver}.
+     * @param observer The {@link InfoBarContainerObserver} to remove.
+     */
+    public void removeObserver(InfoBarContainerObserver observer) {
+        mObservers.removeObserver(observer);
+    }
+
     @Override
     public void setContentViewCore(ContentViewCore contentViewCore) {
         super.setContentViewCore(contentViewCore);
@@ -227,7 +268,7 @@
     protected TabObserver createTabObserver() {
         return new SwipableOverlayViewTabObserver() {
             @Override
-            public void onPageLoadStarted(Tab tab) {
+            public void onPageLoadStarted(Tab tab, String url) {
                 onPageStarted();
             }
         };
@@ -254,6 +295,11 @@
             return;
         }
 
+        // We notify observers immediately (before the animation starts).
+        for (InfoBarContainerObserver observer : mObservers) {
+            observer.onAddInfoBar(this, infoBar, mInfoBars.isEmpty());
+        }
+
         // We add the infobar immediately to mInfoBars but we wait for the animation to end to
         // notify it's been added, as tests rely on this notification but expects the infobar view
         // to be available when they get the notification.
@@ -312,6 +358,11 @@
             return;
         }
 
+        // Notify observers immediately, before the animation begins.
+        for (InfoBarContainerObserver observer : mObservers) {
+            observer.onRemoveInfoBar(this, infoBar, mInfoBars.isEmpty());
+        }
+
         // If an InfoBar is told to hide itself before it has a chance to be shown, don't bother
         // with animating any of it.
         boolean collapseAnimations = false;
@@ -325,9 +376,7 @@
                     assert !collapseAnimations;
                     collapseAnimations = true;
                 }
-                if (collapseAnimations) {
-                    mInfoBarTransitions.remove(info);
-                }
+                if (collapseAnimations) mInfoBarTransitions.remove(info);
             }
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/MessageInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/MessageInfoBar.java
index 5f43c98..1c1597f7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/MessageInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/MessageInfoBar.java
@@ -32,9 +32,4 @@
             CharSequence title) {
         super(listener, iconResourceId, null, title);
     }
-
-    @Override
-    public void onCloseButtonClicked() {
-        super.dismissJavaOnlyInfoBar();
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/SavePasswordInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/SavePasswordInfoBar.java
index 41d1283..acb41224 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/SavePasswordInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/SavePasswordInfoBar.java
@@ -24,19 +24,18 @@
     private final String mTitle;
 
     @CalledByNative
-    private static InfoBar show(long nativeInfoBar, int enumeratedIconId, String message,
-            int titleLinkStart, int titleLinkEnd, String primaryButtonText,
-            String secondaryButtonText, boolean isMoreButtonNeeded) {
-        return new SavePasswordInfoBar(nativeInfoBar, ResourceId.mapToDrawableId(enumeratedIconId),
-                message, titleLinkStart, titleLinkEnd, primaryButtonText, secondaryButtonText,
+    private static InfoBar show(int enumeratedIconId, String message, int titleLinkStart,
+            int titleLinkEnd, String primaryButtonText, String secondaryButtonText,
+            boolean isMoreButtonNeeded) {
+        return new SavePasswordInfoBar(ResourceId.mapToDrawableId(enumeratedIconId), message,
+                titleLinkStart, titleLinkEnd, primaryButtonText, secondaryButtonText,
                 isMoreButtonNeeded);
     }
 
-    private SavePasswordInfoBar(long nativeInfoBar, int iconDrawbleId, String message,
-            int titleLinkStart, int titleLinkEnd, String primaryButtonText,
-            String secondaryButtonText, boolean isMoreButtonNeeded) {
-        super(nativeInfoBar, null, iconDrawbleId, null, message, null, primaryButtonText,
-                secondaryButtonText);
+    private SavePasswordInfoBar(int iconDrawbleId, String message, int titleLinkStart,
+            int titleLinkEnd, String primaryButtonText, String secondaryButtonText,
+            boolean isMoreButtonNeeded) {
+        super(null, iconDrawbleId, null, message, null, primaryButtonText, secondaryButtonText);
         mIsMoreButtonNeeded = isMoreButtonNeeded;
         mTitleLinkRangeStart = titleLinkStart;
         mTitleLinkRangeEnd = titleLinkEnd;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBar.java
index bbfa182..0c21639 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBar.java
@@ -13,6 +13,7 @@
 import android.view.View;
 import android.widget.CheckBox;
 
+import org.chromium.base.CalledByNative;
 import org.chromium.chrome.R;
 import org.chromium.ui.base.DeviceFormFactor;
 
@@ -34,25 +35,30 @@
     public static final int ALWAYS_PANEL = 3;
     public static final int MAX_PANEL_INDEX = 4;
 
+    private long mNativeTranslateInfoBarPtr;
     private int mInfoBarType;
     private final TranslateOptions mOptions;
     private int mOptionsPanelViewType;
     private TranslateSubPanel mSubPanel;
     private final boolean mShouldShowNeverBar;
-    private final TranslateInfoBarDelegate mTranslateDelegate;
 
-    public TranslateInfoBar(long nativeInfoBarPtr, TranslateInfoBarDelegate delegate,
-            int infoBarType, int sourceLanguageIndex, int targetLanguageIndex,
-            boolean autoTranslatePair, boolean shouldShowNeverBar,
+    @CalledByNative
+    private static InfoBar show(int translateBarType, int sourceLanguageIndex,
+            int targetLanguageIndex, boolean autoTranslatePair, boolean showNeverInfobar,
             boolean triggeredFromMenu, String[] languages) {
+        return new TranslateInfoBar(translateBarType, sourceLanguageIndex, targetLanguageIndex,
+                autoTranslatePair, showNeverInfobar, triggeredFromMenu, languages);
+    }
+
+    private TranslateInfoBar(int infoBarType, int sourceLanguageIndex, int targetLanguageIndex,
+            boolean autoTranslatePair, boolean shouldShowNeverBar, boolean triggeredFromMenu,
+            String[] languages) {
         super(null, R.drawable.infobar_translate, null, null);
-        mTranslateDelegate = delegate;
         mOptions = new TranslateOptions(sourceLanguageIndex, targetLanguageIndex, languages,
                 autoTranslatePair, triggeredFromMenu);
         mInfoBarType = infoBarType;
         mShouldShowNeverBar = shouldShowNeverBar;
         mOptionsPanelViewType = NO_PANEL;
-        setNativeInfoBar(nativeInfoBarPtr);
     }
 
     @Override
@@ -61,7 +67,7 @@
             // Make it behave exactly as the Nope Button.
             onButtonClicked(false);
         } else {
-            nativeOnCloseButtonClicked(mNativeInfoBarPtr);
+            super.onCloseButtonClicked();
         }
     }
 
@@ -205,11 +211,7 @@
 
     private void onTranslateInfoBarButtonClicked(int action) {
         onOptionsChanged();
-
-        // We need to re-check if the pointer is null now because applying options (like never
-        // translate this site) can sometimes trigger closing the InfoBar.
-        if (mNativeInfoBarPtr == 0) return;
-        nativeOnButtonClicked(mNativeInfoBarPtr, action, "");
+        onButtonClicked(action, "");
     }
 
     @Override
@@ -226,15 +228,12 @@
 
     @Override
     public void onOptionsChanged() {
-        if (mNativeInfoBarPtr == 0) return;
+        if (mNativeTranslateInfoBarPtr == 0) return;
 
         if (mOptions.optionsChanged()) {
-            mTranslateDelegate.applyTranslateOptions(mNativeInfoBarPtr,
-                    mOptions.sourceLanguageIndex(),
-                    mOptions.targetLanguageIndex(),
-                    mOptions.alwaysTranslateLanguageState(),
-                    mOptions.neverTranslateLanguageState(),
-                    mOptions.neverTranslateDomainState());
+            nativeApplyTranslateOptions(mNativeTranslateInfoBarPtr, mOptions.sourceLanguageIndex(),
+                    mOptions.targetLanguageIndex(), mOptions.alwaysTranslateLanguageState(),
+                    mOptions.neverTranslateLanguageState(), mOptions.neverTranslateDomainState());
         }
     }
 
@@ -331,13 +330,28 @@
         return mInfoBarType;
     }
 
-    void changeInfoBarTypeAndNativePointer(int infoBarType, long newNativePointer) {
+    @CalledByNative
+    private void setNativePtr(long nativePtr) {
+        mNativeTranslateInfoBarPtr = nativePtr;
+    }
+
+    @Override
+    protected void onNativeDestroyed() {
+        mNativeTranslateInfoBarPtr = 0;
+        super.onNativeDestroyed();
+    }
+
+    @CalledByNative
+    private void changeTranslateInfoBarType(int infoBarType) {
         if (infoBarType >= 0 && infoBarType < MAX_INFOBAR_INDEX) {
             mInfoBarType = infoBarType;
-            replaceNativePointer(newNativePointer);
             updateViewForCurrentState(createView());
         } else {
             assert false : "Trying to change the InfoBar to a type that is invalid.";
         }
     }
+
+    private native void nativeApplyTranslateOptions(long nativeTranslateInfoBar,
+            int sourceLanguageIndex, int targetLanguageIndex, boolean alwaysTranslate,
+            boolean neverTranslateLanguage, boolean neverTranslateSite);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBarDelegate.java
deleted file mode 100644
index 00d9d40..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBarDelegate.java
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2013 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.infobar;
-
-import org.chromium.base.CalledByNative;
-
-/**
- * Translate JNI methods
- */
-public class TranslateInfoBarDelegate {
-    private TranslateInfoBar mInfoBar;
-
-    private TranslateInfoBarDelegate() {}
-
-    @CalledByNative
-    public static TranslateInfoBarDelegate create() {
-        return new TranslateInfoBarDelegate();
-    }
-
-    @CalledByNative
-    boolean changeTranslateInfoBarTypeAndPointer(
-            long newNativeInfoBar, int translateBarType) {
-        mInfoBar.changeInfoBarTypeAndNativePointer(
-                translateBarType, newNativeInfoBar);
-        return true;
-    }
-
-    @CalledByNative
-    InfoBar showTranslateInfoBar(
-            long nativeInfoBar, int translateBarType,
-            int sourceLanguageIndex, int targetLanguageIndex, boolean autoTranslatePair,
-            boolean showNeverInfobar, boolean triggeredFromMenu,
-            String[] languages) {
-        mInfoBar = new TranslateInfoBar(nativeInfoBar, this, translateBarType,
-                sourceLanguageIndex, targetLanguageIndex, autoTranslatePair, showNeverInfobar,
-                triggeredFromMenu, languages);
-        return mInfoBar;
-    }
-
-    public void applyTranslateOptions(long nativeTranslateInfoBar,
-            int sourceLanguageIndex, int targetLanguageIndex, boolean alwaysTranslate,
-            boolean neverTranslateLanguage, boolean neverTranslateSite) {
-        nativeApplyTranslateOptions(nativeTranslateInfoBar, sourceLanguageIndex,
-                targetLanguageIndex, alwaysTranslate, neverTranslateLanguage, neverTranslateSite);
-    }
-
-    private native void nativeApplyTranslateOptions(long nativeTranslateInfoBar,
-            int sourceLanguageIndex, int targetLanguageIndex, boolean alwaysTranslate,
-            boolean neverTranslateLanguage, boolean neverTranslateSite);
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java b/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java
index d944658..0dea87b7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java
@@ -137,14 +137,41 @@
         nativeSetDataReductionProxyEnabled(mNativeDataReductionProxySettings, enabled);
     }
 
-    /** Returns true if the SPDY proxy is enabled. */
+    /** Returns true if the Data Reduction Proxy proxy is enabled. */
     public boolean isDataReductionProxyEnabled() {
         return nativeIsDataReductionProxyEnabled(mNativeDataReductionProxySettings);
     }
 
-    /** Returns true if Data Reduction Proxy LoFi is enabled. */
-    public boolean isLoFiEnabled() {
-        return nativeIsLoFiEnabled(mNativeDataReductionProxySettings);
+    /**
+     * Returns true if the Data Reduction Proxy proxy can be used for the given url. This method
+     * does not take into account the proxy config or proxy retry list, so it can return true even
+     * when the proxy will not be used.
+     */
+    public boolean canUseDataReductionProxy(String url) {
+        return nativeCanUseDataReductionProxy(mNativeDataReductionProxySettings, url);
+    }
+
+    /**
+     * Returns true if the Data Reduction Proxy's Lo-Fi mode was enabled on the last main frame
+     * request.
+     */
+    public boolean wasLoFiModeActiveOnMainFrame() {
+        return nativeWasLoFiModeActiveOnMainFrame(mNativeDataReductionProxySettings);
+    }
+
+    /**
+     * Returns true if a "Show image" context menu request has not been made since the last main
+     * frame request.
+     */
+    public boolean wasLoFiShowImageRequestedBefore() {
+        return nativeWasLoFiShowImageRequestedBefore(mNativeDataReductionProxySettings);
+    }
+
+    /**
+     * Sets that a "Show image" context menu request has been made.
+     */
+    public void setLoFiShowImageRequested() {
+        nativeSetLoFiShowImageRequested(mNativeDataReductionProxySettings);
     }
 
     /** Returns true if the SPDY proxy is managed by an administrator's policy. */
@@ -217,7 +244,13 @@
             long nativeDataReductionProxySettingsAndroid);
     private native boolean nativeIsDataReductionProxyEnabled(
             long nativeDataReductionProxySettingsAndroid);
-    private native boolean nativeIsLoFiEnabled(
+    private native boolean nativeCanUseDataReductionProxy(
+            long nativeDataReductionProxySettingsAndroid, String url);
+    private native boolean nativeWasLoFiModeActiveOnMainFrame(
+            long nativeDataReductionProxySettingsAndroid);
+    private native boolean nativeWasLoFiShowImageRequestedBefore(
+            long nativeDataReductionProxySettingsAndroid);
+    private native void nativeSetLoFiShowImageRequested(
             long nativeDataReductionProxySettingsAndroid);
     private native boolean nativeIsDataReductionProxyManaged(
             long nativeDataReductionProxySettingsAndroid);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/DataReductionProxyUma.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/DataReductionProxyUma.java
index 2074bdd..dc2d0f9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/DataReductionProxyUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/DataReductionProxyUma.java
@@ -23,6 +23,15 @@
     public static final int ACTION_ON_TO_ON = 8;
     public static final int ACTION_INDEX_BOUNDARY = 9;
 
+    // Represent the possible Lo-Fi user actions. This must remain in sync with
+    // DataReductionProxy.UIAction.LoFi in tools/metrics/histograms/histograms.xml.
+    public static final int ACTION_LOAD_IMAGES_SNACKBAR_SHOWN = 0;
+    public static final int ACTION_LOAD_IMAGES_SNACKBAR_CLICKED = 1;
+    public static final int ACTION_LOAD_IMAGE_CONTEXT_MENU_SHOWN = 2;
+    public static final int ACTION_LOAD_IMAGE_CONTEXT_MENU_CLICKED = 3;
+    public static final int ACTION_LOAD_IMAGE_CONTEXT_MENU_CLICKED_ON_PAGE = 4;
+    public static final int LOFI_ACTION_INDEX_BOUNDARY = 5;
+
     /**
      * Record the DataReductionProxy.UIAction histogram.
      * @param action User action at the promo or settings screen
@@ -33,4 +42,15 @@
                 "DataReductionProxy.UIAction", action,
                 DataReductionProxyUma.ACTION_INDEX_BOUNDARY);
     }
+
+    /**
+     * Record the DataReductionProxy.UIAction.LoFi histogram.
+     * @param action LoFi user action on the snackbar or context menu
+     */
+    public static void dataReductionProxyLoFiUIAction(int action) {
+        assert action >= 0 && action < LOFI_ACTION_INDEX_BOUNDARY;
+        RecordHistogram.recordEnumeratedHistogram(
+                "DataReductionProxy.LoFi.UIAction", action,
+                DataReductionProxyUma.LOFI_ACTION_INDEX_BOUNDARY);
+    }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java
index 732ecab..e25fa10c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/share/ShareHelper.java
@@ -4,11 +4,15 @@
 
 package org.chromium.chrome.browser.share;
 
+import android.annotation.TargetApi;
 import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
 import android.content.ClipData;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -19,6 +23,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.AsyncTask;
+import android.os.Build;
 import android.preference.PreferenceManager;
 import android.support.v7.app.AlertDialog;
 import android.util.Log;
@@ -70,6 +75,65 @@
     }
 
     /**
+     * Receiver to record the chosen component when sharing an Intent.
+     */
+    static class TargetChosenReceiver extends BroadcastReceiver {
+        private static final String EXTRA_RECEIVER_TOKEN = "receiver_token";
+        private static final Object LOCK = new Object();
+
+        private static String sTargetChosenReceiveAction;
+        private static TargetChosenReceiver sLastRegisteredReceiver;
+
+        static boolean isSupported() {
+            return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1;
+        }
+
+        @TargetApi(Build.VERSION_CODES.LOLLIPOP_MR1)
+        static void sendChooserIntent(Activity activity, Intent sharingIntent) {
+            synchronized (LOCK) {
+                if (sTargetChosenReceiveAction == null) {
+                    sTargetChosenReceiveAction = activity.getPackageName() + "/"
+                            + TargetChosenReceiver.class.getName() + "_ACTION";
+                }
+                if (sLastRegisteredReceiver != null) {
+                    activity.unregisterReceiver(sLastRegisteredReceiver);
+                }
+                sLastRegisteredReceiver = new TargetChosenReceiver();
+                activity.registerReceiver(
+                        sLastRegisteredReceiver, new IntentFilter(sTargetChosenReceiveAction));
+            }
+
+            Intent intent = new Intent(sTargetChosenReceiveAction);
+            intent.setPackage(activity.getPackageName());
+            intent.putExtra(EXTRA_RECEIVER_TOKEN, sLastRegisteredReceiver.hashCode());
+            final PendingIntent callback = PendingIntent.getBroadcast(activity, 0, intent,
+                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
+            Intent chooserIntent = Intent.createChooser(sharingIntent,
+                    activity.getString(R.string.share_link_chooser_title),
+                    callback.getIntentSender());
+            activity.startActivity(chooserIntent);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            synchronized (LOCK) {
+                if (sLastRegisteredReceiver != this) return;
+                context.unregisterReceiver(sLastRegisteredReceiver);
+                sLastRegisteredReceiver = null;
+            }
+            if (!intent.hasExtra(EXTRA_RECEIVER_TOKEN)
+                    || intent.getIntExtra(EXTRA_RECEIVER_TOKEN, 0) != this.hashCode()) {
+                return;
+            }
+
+            ComponentName target = intent.getParcelableExtra(Intent.EXTRA_CHOSEN_COMPONENT);
+            if (target != null) {
+                setLastShareComponentName(context, target);
+            }
+        }
+    }
+
+    /**
      * Clears all shared screenshot files.
      */
     public static void clearSharedScreenshots(final Context context) {
@@ -107,6 +171,8 @@
             Bitmap screenshot) {
         if (shareDirectly) {
             shareWithLastUsed(activity, title, url, screenshot);
+        } else if (TargetChosenReceiver.isSupported()) {
+            makeIntentAndShare(activity, title, url, screenshot, null);
         } else {
             showShareDialog(activity, title, url, screenshot);
         }
@@ -166,10 +232,19 @@
         makeIntentAndShare(activity, title, url, screenshot, component);
     }
 
+    private static void shareIntent(Activity activity, Intent sharingIntent) {
+        if (sharingIntent.getComponent() != null) {
+            activity.startActivity(sharingIntent);
+        } else {
+            assert TargetChosenReceiver.isSupported();
+            TargetChosenReceiver.sendChooserIntent(activity, sharingIntent);
+        }
+    }
+
     private static void makeIntentAndShare(final Activity activity, final String title,
             final String url, final Bitmap screenshot, final ComponentName component) {
         if (screenshot == null) {
-            activity.startActivity(getDirectShareIntentForComponent(title, url, null, component));
+            shareIntent(activity, getDirectShareIntentForComponent(title, url, null, component));
         } else {
             new AsyncTask<Void, Void, File>() {
                 @Override
@@ -207,7 +282,7 @@
                             != ApplicationState.HAS_DESTROYED_ACTIVITIES) {
                         Uri screenshotUri = saveFile == null
                                 ? null : UiUtils.getUriForImageCaptureFile(activity, saveFile);
-                        activity.startActivity(getDirectShareIntentForComponent(
+                        shareIntent(activity, getDirectShareIntentForComponent(
                                 title, url, screenshotUri, component));
                     }
                 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
index 3381295..0980a56 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/AccountManagementFragment.java
@@ -118,6 +118,8 @@
     private ArrayList<Preference> mAccountsListPreferences = new ArrayList<Preference>();
     private Preference mPrimaryAccountPreference;
 
+    private boolean mSaveInstanceStateWasCalled;
+
     private AccountManagementFragmentDelegate getDelegate() {
         return AccountManagementScreenHelper.getDelegate();
     }
@@ -157,6 +159,12 @@
         ProfileSyncService.get(getActivity()).removeSyncStateChangedListener(this);
     }
 
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        mSaveInstanceStateWasCalled = true;
+    }
+
     /**
      * Initiate fetching the user accounts data (images and the full name).
      * Fetched data will be sent to observers of ProfileDownloader.
@@ -219,6 +227,7 @@
                 @Override
                 public boolean onPreferenceChange(Preference preference, Object newValue) {
                     if ((boolean) newValue) return true;
+                    if (mSaveInstanceStateWasCalled) return false;
 
                     if (ChromeSigninController.get(getActivity()).isSignedIn()
                             && getSignOutAllowedPreferenceValue(getActivity())) {
@@ -252,6 +261,8 @@
             addAccount.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                 @Override
                 public boolean onPreferenceClick(Preference preference) {
+                    if (mSaveInstanceStateWasCalled) return false;
+
                     AccountManagementScreenHelper.logEvent(
                             ProfileAccountManagementMetrics.ADD_ACCOUNT,
                             mGaiaServiceType);
@@ -284,6 +295,7 @@
             goIncognito.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                 @Override
                 public boolean onPreferenceClick(Preference preference) {
+                    if (mSaveInstanceStateWasCalled) return false;
                     if (!PrefServiceBridge.getInstance().isIncognitoModeEnabled()) return false;
 
                     AccountManagementFragmentDelegate delegate = getDelegate();
@@ -389,6 +401,8 @@
                 pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                     @Override
                     public boolean onPreferenceClick(Preference preference) {
+                        if (mSaveInstanceStateWasCalled) return false;
+
                         AccountManagementScreenHelper.logEvent(
                                 ProfileAccountManagementMetrics.CLICK_PRIMARY_ACCOUNT,
                                 mGaiaServiceType);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCreatorManager.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCreatorManager.java
index 4255b5a..c06de53 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCreatorManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabCreatorManager.java
@@ -6,6 +6,9 @@
 
 import org.chromium.chrome.browser.Tab;
 import org.chromium.chrome.browser.TabState;
+import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.WebContents;
 
 /**
  * An interface to return a {@link TabCreator} either for regular or incognito tabs.
@@ -16,19 +19,48 @@
      */
     public interface TabCreator {
         /**
+         * Creates a new tab and posts to UI.
+         * @param loadUrlParams parameters of the url load.
+         * @param type Information about how the tab was launched.
+         * @param parent the parent tab, if present.
+         * @return The new tab.
+         */
+        Tab createNewTab(LoadUrlParams loadUrlParams, TabModel.TabLaunchType type, Tab parent);
+
+        /**
          * On restore, allows us to create a frozen version of a tab using saved tab state we read
          * from disk.
          * @param state    The tab state that the tab can be restored from.
          * @param id       The id to give the new tab.
          * @param index    The index for where to place the tab.
          */
-        public void createFrozenTab(TabState state, int id, int index);
+        void createFrozenTab(TabState state, int id, int index);
+
+        /**
+         * Creates a tab around the native web contents pointer.
+         * @param webContents The web contents to create a tab around.
+         * @param parentId    The id of the parent tab.
+         * @param type        The TabLaunchType describing how this tab was created.
+         * @return            The created tab.
+         */
+        Tab createTabWithWebContents(WebContents webContents, int parentId, TabLaunchType type);
 
         /**
          * Creates a new tab and loads the NTP.
          * @return The created tab.
          */
-        public Tab launchNTP();
+        Tab launchNTP();
+
+        /**
+         * Creates a new tab and loads the specified URL in it. This is a convenience method for
+         * {@link #createNewTab} with the default {@link LoadUrlParams} and no parent tab.
+         *
+         * @param url the URL to open.
+         * @param type the type of action that triggered that launch. Determines how the tab is
+         *             opened (for example, in the foreground or background).
+         * @return the created tab.
+         */
+        Tab launchUrl(String url, TabModel.TabLaunchType type);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
index eb0409f..ff1ffbd7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
@@ -221,62 +221,67 @@
     public void saveState() {
         // Temporarily allowing disk access. TODO: Fix. See http://b/5518024
         StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
-        // Add current tabs to save because they did not get a save signal yet.
-        Tab currentStandardTab = TabModelUtils.getCurrentTab(mTabModelSelector.getModel(false));
-        if (currentStandardTab != null && !mTabsToSave.contains(currentStandardTab)
-                && currentStandardTab.isTabStateDirty()
-                // For content URI, the read permission granted to an activity is not persistent.
-                && !isTabUrlContentScheme(currentStandardTab)) {
-            mTabsToSave.addLast(currentStandardTab);
-        }
-        Tab currentIncognitoTab = TabModelUtils.getCurrentTab(mTabModelSelector.getModel(true));
-        if (currentIncognitoTab != null && !mTabsToSave.contains(currentIncognitoTab)
-                && currentIncognitoTab.isTabStateDirty()
-                && !isTabUrlContentScheme(currentIncognitoTab)) {
-            mTabsToSave.addLast(currentIncognitoTab);
-        }
-        // Wait for the current tab to save.
-        if (mSaveTabTask != null) {
-            // Cancel calls get() to wait for this to finish internally if it has to.
-            // The issue is it may assume it cancelled the task, but the task still actually wrote
-            // the state to disk.  That's why we have to check mStateSaved here.
-            if (mSaveTabTask.cancel(false) && !mSaveTabTask.mStateSaved) {
-                // The task was successfully cancelled.  We should try to save this state again.
-                Tab cancelledTab = mSaveTabTask.mTab;
-                if (!mTabsToSave.contains(cancelledTab)
-                        && cancelledTab.isTabStateDirty()
-                        && !isTabUrlContentScheme(cancelledTab)) {
-                    mTabsToSave.addLast(cancelledTab);
+        try {
+            // Add current tabs to save because they did not get a save signal yet.
+            Tab currentStandardTab = TabModelUtils.getCurrentTab(mTabModelSelector.getModel(false));
+            if (currentStandardTab != null && !mTabsToSave.contains(currentStandardTab)
+                    && currentStandardTab.isTabStateDirty()
+                    // For content URI, the read permission granted to an activity is not
+                    // persistent.
+                    && !isTabUrlContentScheme(currentStandardTab)) {
+                mTabsToSave.addLast(currentStandardTab);
+            }
+            Tab currentIncognitoTab = TabModelUtils.getCurrentTab(mTabModelSelector.getModel(true));
+            if (currentIncognitoTab != null && !mTabsToSave.contains(currentIncognitoTab)
+                    && currentIncognitoTab.isTabStateDirty()
+                    && !isTabUrlContentScheme(currentIncognitoTab)) {
+                mTabsToSave.addLast(currentIncognitoTab);
+            }
+            // Wait for the current tab to save.
+            if (mSaveTabTask != null) {
+                // Cancel calls get() to wait for this to finish internally if it has to.
+                // The issue is it may assume it cancelled the task, but the task still actually
+                // wrote the state to disk.  That's why we have to check mStateSaved here.
+                if (mSaveTabTask.cancel(false) && !mSaveTabTask.mStateSaved) {
+                    // The task was successfully cancelled.  We should try to save this state again.
+                    Tab cancelledTab = mSaveTabTask.mTab;
+                    if (!mTabsToSave.contains(cancelledTab)
+                            && cancelledTab.isTabStateDirty()
+                            && !isTabUrlContentScheme(cancelledTab)) {
+                        mTabsToSave.addLast(cancelledTab);
+                    }
+                }
+
+                mSaveTabTask = null;
+            }
+
+            // Synchronously save any remaining unsaved tabs (hopefully very few).
+            for (Tab tab : mTabsToSave) {
+                int id = tab.getId();
+                boolean incognito = tab.isIncognito();
+                try {
+                    TabState.saveState(openTabStateOutputStream(id, incognito), tab.getState(),
+                            incognito);
+                } catch (IOException e) {
+                    logSaveException(e);
+                } catch (OutOfMemoryError e) {
+                    Log.w(TAG, "Out of memory error while attempting to save tab state.  Erasing.");
+                    deleteTabState(id, incognito);
                 }
             }
+            mTabsToSave.clear();
 
-            mSaveTabTask = null;
-        }
-
-        // Synchronously save any remaining unsaved tabs (hopefully very few).
-        for (Tab tab : mTabsToSave) {
-            int id = tab.getId();
-            boolean incognito = tab.isIncognito();
-            try {
-                TabState.saveState(openTabStateOutputStream(id, incognito), tab.getState(),
-                        incognito);
-            } catch (IOException e) {
-                logSaveException(e);
-            } catch (OutOfMemoryError e) {
-                Log.w(TAG, "Out of memory error while attempting to save tab state.  Erasing.");
-                deleteTabState(id, incognito);
+            if (mSaveListTask == null
+                    || (mSaveListTask.cancel(false) && !mSaveListTask.mStateSaved)) {
+                try {
+                    saveListToFile(serializeTabMetadata());
+                } catch (IOException e) {
+                    logSaveException(e);
+                }
             }
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
         }
-        mTabsToSave.clear();
-
-        if (mSaveListTask == null || (mSaveListTask.cancel(false) && !mSaveListTask.mStateSaved)) {
-            try {
-                saveListToFile(serializeTabMetadata());
-            } catch (IOException e) {
-                logSaveException(e);
-            }
-        }
-        StrictMode.setThreadPolicy(oldPolicy);
     }
 
     /**
@@ -621,50 +626,55 @@
      */
     @VisibleForTesting
     public int loadStateInternal() throws IOException {
-        assert  mTabModelSelector.getModel(true).getCount() == 0;
-        assert  mTabModelSelector.getModel(false).getCount() == 0;
-        int maxId = 0;
-        File[] folders = getBaseStateDirectory(mContext).listFiles();
-        File stateFolder = getStateDirectory();
-        for (File folder : folders) {
-            assert folder.isDirectory();
-            if (!folder.isDirectory()) continue;
-            boolean readDir = folder.equals(stateFolder);
-            final Deque<TabRestoreDetails> restoreList = readDir ? mTabsToRestore : null;
-            final boolean isIncognitoSelected = mTabModelSelector.isIncognitoSelected();
+        // Temporarily allowing disk access. TODO: Fix. See http://crbug.com/473357
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        try {
+            assert  mTabModelSelector.getModel(true).getCount() == 0;
+            assert  mTabModelSelector.getModel(false).getCount() == 0;
+            int maxId = 0;
+            File[] folders = getBaseStateDirectory(mContext).listFiles();
+            File stateFolder = getStateDirectory();
+            for (File folder : folders) {
+                assert folder.isDirectory();
+                if (!folder.isDirectory()) continue;
+                boolean readDir = folder.equals(stateFolder);
+                final Deque<TabRestoreDetails> restoreList = readDir ? mTabsToRestore : null;
+                final boolean isIncognitoSelected = mTabModelSelector.isIncognitoSelected();
 
-            // TODO(dfalcantara): Store the max tab ID in a shared preference so that it can be
-            //                    shared with all of the other modes that Chrome runs in and to
-            //                    avoid reading in all of the possible app_tabs subdirectories.
-            int curId = readSavedStateFile(folder, new OnTabStateReadCallback() {
-                @Override
-                public void onDetailsRead(int index, int id, String url,
-                        boolean isStandardActiveIndex, boolean isIncognitoActiveIndex) {
-                    // If we're not trying to build the restore list skip the build part.
-                    // We've already read all the state for this entry from the input stream.
-                    if (restoreList == null) return;
+                // TODO(dfalcantara): Store the max tab ID in a shared preference so that it can be
+                //                    shared with all of the other modes that Chrome runs in and to
+                //                    avoid reading in all of the possible app_tabs subdirectories.
+                int curId = readSavedStateFile(folder, new OnTabStateReadCallback() {
+                    @Override
+                    public void onDetailsRead(int index, int id, String url,
+                            boolean isStandardActiveIndex, boolean isIncognitoActiveIndex) {
+                        // If we're not trying to build the restore list skip the build part.
+                        // We've already read all the state for this entry from the input stream.
+                        if (restoreList == null) return;
 
-                    // Note that incognito tab may not load properly so we may need to use
-                    // the current tab from the standard model.
-                    // This logic only works because we store the incognito indices first.
-                    if ((isIncognitoActiveIndex && isIncognitoSelected)
-                            || (isStandardActiveIndex && !isIncognitoSelected)) {
-                        // Active tab gets loaded first
-                        restoreList.addFirst(new TabRestoreDetails(id, index, url));
-                    } else {
-                        restoreList.addLast(new TabRestoreDetails(id, index, url));
+                        // Note that incognito tab may not load properly so we may need to use
+                        // the current tab from the standard model.
+                        // This logic only works because we store the incognito indices first.
+                        if ((isIncognitoActiveIndex && isIncognitoSelected)
+                                || (isStandardActiveIndex && !isIncognitoSelected)) {
+                            // Active tab gets loaded first
+                            restoreList.addFirst(new TabRestoreDetails(id, index, url));
+                        } else {
+                            restoreList.addLast(new TabRestoreDetails(id, index, url));
+                        }
+
+                        if (mObserver != null) {
+                            mObserver.onDetailsRead(
+                                    index, id, url, isStandardActiveIndex, isIncognitoActiveIndex);
+                        }
                     }
-
-                    if (mObserver != null) {
-                        mObserver.onDetailsRead(
-                                index, id, url, isStandardActiveIndex, isIncognitoActiveIndex);
-                    }
-                }
-            });
-            maxId = Math.max(maxId, curId);
+                });
+                maxId = Math.max(maxId, curId);
+            }
+            return maxId;
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
         }
-
-        return maxId;
     }
 
     public static int readSavedStateFile(File folder, OnTabStateReadCallback callback)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java
index 40615ee..0d208bb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/DocumentTabModelImpl.java
@@ -11,6 +11,7 @@
 import android.content.SharedPreferences;
 import android.os.AsyncTask;
 import android.os.Build;
+import android.os.StrictMode;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
@@ -505,50 +506,57 @@
     }
 
     private void initializeTabList() {
-        setCurrentState(STATE_READ_RECENT_TASKS_START);
+        // Temporarily allowing disk access. TODO: Fix. See http://crbug.com/496348
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        try {
+            setCurrentState(STATE_READ_RECENT_TASKS_START);
 
-        // Run through Recents to see what tasks exist. Prevent them from being retargeted until we
-        // have had the opportunity to load more information about them.
-        List<Entry> entries = mActivityDelegate.getTasksFromRecents(isIncognito());
-        for (Entry entry : entries) {
-            entry.canGoBack = true;
-            mEntryMap.put(entry.tabId, entry);
-        }
-
-        // Read the file, which saved out the task IDs in regular order.
-        byte[] tabFileBytes = mStorageDelegate.readTaskFileBytes(isIncognito());
-        if (tabFileBytes != null) {
-            try {
-                DocumentList list = MessageNano.mergeFrom(new DocumentList(), tabFileBytes);
-                for (int i = 0; i < list.entries.length; i++) {
-                    DocumentEntry savedEntry = list.entries[i];
-                    int tabId = savedEntry.tabId;
-
-                    if (mEntryMap.indexOfKey(tabId) < 0) {
-                        mHistoricalTabs.add(tabId);
-                        continue;
-                    }
-
-                    addTabId(getCount(), tabId);
-                    mEntryMap.get(tabId).canGoBack = savedEntry.canGoBack;
-                    // For backward compatibility, isCoveredByChildActivity may not be available.
-                    mEntryMap.get(tabId).isCoveredByChildActivity =
-                            (savedEntry.isCoveredByChildActivity == null)
-                            ? false : savedEntry.isCoveredByChildActivity;
-                }
-            } catch (IOException e) {
-                Log.e(TAG, "I/O exception", e);
+            // Run through Recents to see what tasks exist. Prevent them from being retargeted until
+            // we have had the opportunity to load more information about them.
+            List<Entry> entries = mActivityDelegate.getTasksFromRecents(isIncognito());
+            for (Entry entry : entries) {
+                entry.canGoBack = true;
+                mEntryMap.put(entry.tabId, entry);
             }
-        }
 
-        // Add any missing tasks to the list.
-        for (int i = 0; i < mEntryMap.size(); i++) {
-            int id = mEntryMap.keyAt(i);
-            if (mTabIdList.contains(id)) continue;
-            addTabId(id);
-        }
+            // Read the file, which saved out the task IDs in regular order.
+            byte[] tabFileBytes = mStorageDelegate.readTaskFileBytes(isIncognito());
+            if (tabFileBytes != null) {
+                try {
+                    DocumentList list = MessageNano.mergeFrom(new DocumentList(), tabFileBytes);
+                    for (int i = 0; i < list.entries.length; i++) {
+                        DocumentEntry savedEntry = list.entries[i];
+                        int tabId = savedEntry.tabId;
 
-        setCurrentState(STATE_READ_RECENT_TASKS_END);
+                        if (mEntryMap.indexOfKey(tabId) < 0) {
+                            mHistoricalTabs.add(tabId);
+                            continue;
+                        }
+
+                        addTabId(getCount(), tabId);
+                        mEntryMap.get(tabId).canGoBack = savedEntry.canGoBack;
+                        // For backward compatibility, isCoveredByChildActivity may not be
+                        // available.
+                        mEntryMap.get(tabId).isCoveredByChildActivity =
+                                (savedEntry.isCoveredByChildActivity == null)
+                                ? false : savedEntry.isCoveredByChildActivity;
+                    }
+                } catch (IOException e) {
+                    Log.e(TAG, "I/O exception", e);
+                }
+            }
+
+            // Add any missing tasks to the list.
+            for (int i = 0; i < mEntryMap.size(); i++) {
+                int id = mEntryMap.keyAt(i);
+                if (mTabIdList.contains(id)) continue;
+                addTabId(id);
+            }
+
+            setCurrentState(STATE_READ_RECENT_TASKS_END);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
     }
 
     // TODO(mariakhomenko): we no longer need prioritized tab id in constructor, shift it here.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java
index 4cf4ec2..1bc89862 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/document/TabDelegate.java
@@ -14,6 +14,7 @@
 
 /**
  * Provides Tabs to a DocumentTabModel.
+ * TODO(dfalcantara): Make this a TabCreatorManager.TabCreator subclass.
  */
 public interface TabDelegate {
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/IntentUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/util/IntentUtils.java
index 10067b0..ae7f118 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/IntentUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/IntentUtils.java
@@ -11,6 +11,8 @@
 import android.os.Bundle;
 import android.os.Parcelable;
 
+import org.chromium.base.Log;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -18,6 +20,7 @@
  * Utilities dealing with extracting information from intents.
  */
 public class IntentUtils {
+    private static final String TAG = "IntentUtils";
 
     /**
      * Retrieves a list of components that would handle the given intent.
@@ -40,8 +43,9 @@
     public static boolean safeGetBooleanExtra(Intent intent, String name, boolean defaultValue) {
         try {
             return intent.getBooleanExtra(name, defaultValue);
-        } catch (Exception e) {
+        } catch (Throwable t) {
             // Catches un-parceling exceptions.
+            Log.e(TAG, "getBooleanExtra failed on intent " + intent);
             return defaultValue;
         }
     }
@@ -52,8 +56,9 @@
     public static int safeGetIntExtra(Intent intent, String name, int defaultValue) {
         try {
             return intent.getIntExtra(name, defaultValue);
-        } catch (Exception e) {
+        } catch (Throwable t) {
             // Catches un-parceling exceptions.
+            Log.e(TAG, "getIntExtra failed on intent " + intent);
             return defaultValue;
         }
     }
@@ -64,8 +69,9 @@
     public static long safeGetLongExtra(Intent intent, String name, long defaultValue) {
         try {
             return intent.getLongExtra(name, defaultValue);
-        } catch (Exception e) {
+        } catch (Throwable t) {
             // Catches un-parceling exceptions.
+            Log.e(TAG, "getLongExtra failed on intent " + intent);
             return defaultValue;
         }
     }
@@ -76,8 +82,9 @@
     public static String safeGetStringExtra(Intent intent, String name) {
         try {
             return intent.getStringExtra(name);
-        } catch (Exception e) {
+        } catch (Throwable t) {
             // Catches un-parceling exceptions.
+            Log.e(TAG, "getStringExtra failed on intent " + intent);
             return null;
         }
     }
@@ -88,8 +95,9 @@
     public static String safeGetString(Bundle bundle, String name) {
         try {
             return bundle.getString(name);
-        } catch (Exception e) {
+        } catch (Throwable t) {
             // Catches un-parceling exceptions.
+            Log.e(TAG, "getString failed on bundle " + bundle);
             return null;
         }
     }
@@ -100,8 +108,9 @@
     public static Bundle safeGetBundleExtra(Intent intent, String name) {
         try {
             return intent.getBundleExtra(name);
-        } catch (Exception e) {
+        } catch (Throwable t) {
             // Catches un-parceling exceptions.
+            Log.e(TAG, "getBundleExtra failed on intent " + intent);
             return null;
         }
     }
@@ -112,8 +121,9 @@
     public static <T extends Parcelable> T safeGetParcelable(Bundle bundle, String name) {
         try {
             return bundle.getParcelable(name);
-        } catch (Exception e) {
+        } catch (Throwable t) {
             // Catches un-parceling exceptions.
+            Log.e(TAG, "getParcelable failed on bundle " + bundle);
             return null;
         }
     }
@@ -124,8 +134,9 @@
     public static <T extends Parcelable> T safeGetParcelableExtra(Intent intent, String name) {
         try {
             return intent.getParcelableExtra(name);
-        } catch (Exception e) {
+        } catch (Throwable t) {
             // Catches un-parceling exceptions.
+            Log.e(TAG, "getParcelableExtra failed on intent " + intent);
             return null;
         }
     }
@@ -137,8 +148,9 @@
             Intent intent, String name) {
         try {
             return intent.getParcelableArrayListExtra(name);
-        } catch (Exception e) {
+        } catch (Throwable t) {
             // Catches un-parceling exceptions.
+            Log.e(TAG, "getParcelableArrayListExtra failed on intent " + intent);
             return null;
         }
     }
@@ -149,8 +161,9 @@
     public static ArrayList<String> safeGetStringArrayListExtra(Intent intent, String name) {
         try {
             return intent.getStringArrayListExtra(name);
-        } catch (Exception e) {
+        } catch (Throwable t) {
             // Catches un-parceling exceptions.
+            Log.e(TAG, "getStringArrayListExtra failed on intent " + intent);
             return null;
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java
index 3060512..9ef0d88f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/accessibility/AccessibilityTabModelWrapper.java
@@ -138,9 +138,13 @@
         if (incognitoSelected) {
             mIncognitoButton.setBackgroundResource(R.drawable.btn_bg_holo_active);
             mStandardButton.setBackgroundResource(R.drawable.btn_bg_holo);
+            mAccessibilityView.setContentDescription(getContext().getString(
+                    R.string.accessibility_tab_switcher_incognito_stack));
         } else {
             mIncognitoButton.setBackgroundResource(R.drawable.btn_bg_holo);
             mStandardButton.setBackgroundResource(R.drawable.btn_bg_holo_active);
+            mAccessibilityView.setContentDescription(getContext().getString(
+                    R.string.accessibility_tab_switcher_standard_stack));
         }
 
         getAdapter().setTabModel(mTabModelSelector.getModel(incognitoSelected));
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index c60abfd..795e9d03 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -187,7 +187,7 @@
         Sign in to Chrome
       </message>
       <message name="IDS_SIGN_IN_TO_CHROME_SUMMARY" desc="Summary for the button to sign in to Chrome, explaining benefits of signing in.">
-        Sign in to get your tabs, bookmarks, history, and other settings on all your devices
+        Sign in to get your bookmarks, history, passwords, and other settings on all your devices
       </message>
       <message name="IDS_NUMBER_OF_SIGNED_IN_ACCOUNTS" desc="Summary indicating the number of accounts (always greater than 1) the user is signed in to the content area.">
         <ph name="NUMBER_OF_ACCOUNTS">%1$d<ex>3</ex></ph> accounts
@@ -908,7 +908,7 @@
         You're now signed in to Chrome.
       </message>
       <message name="IDS_FIRSTRUN_SIGNED_IN_DESCRIPTION" desc="Message informing the user what is being synced.">
-        Your open tabs, bookmarks, history, and more are being synced with your Google Account.
+        Your open bookmarks, history, passwords, and more are being synced with your Google Account.
       </message>
 
       <!-- Sync strings -->
@@ -1475,7 +1475,7 @@
         Set up Chrome
       </message>
       <message name="IDS_FRE_ACCOUNT_CHOICE_DESCRIPTION" desc="Text for account chooser page">
-        Select an account to get your tabs, bookmarks, history, and other settings on all your devices.
+        Select an account to get your bookmarks, history, passwords, and other settings on all your devices.
       </message>
       <message name="IDS_FRE_SKIP_TEXT" desc="Text for second page skip button">
         No thanks
@@ -1496,7 +1496,7 @@
         Make Chrome yours
       </message>
       <message name="IDS_FRE_NO_ACCOUNT_CHOICE_DESCRIPTION" desc="Text for account chooser page when there are no accounts on the device.">
-        Add an account to get your tabs, bookmarks, history, and other settings on all your devices.
+        Add an account to get your bookmarks, history, passwords, and other settings on all your devices.
       </message>
       <message name="IDS_SIGN_IN_TO_CHROME_SUMMARY_VARIANT" desc="A variant of summary for the signin promo; lists reasons to sign in to Chrome.">
         Sign in to access all your web stuff from any device
@@ -1508,7 +1508,7 @@
         Hi, <ph name="FULL_NAME">%1$s<ex>John Smith</ex></ph>
       </message>
       <message name="IDS_FRE_SIGNED_IN_DESCRIPTION" desc="Explanation of what gets synced after the user signed in">
-        Your tabs, bookmarks, history and other settings will be synced to your Google Account.
+        Your bookmarks, history, passwords, and other settings will be synced to your Google Account.
       </message>
       <message name="IDS_FRE_SIGNED_IN_DESCRIPTION_UCA_ADDENDUM" desc="Additional explanation for child accounts that synced settings are managed by parents.">
         Your parents help manage these settings.
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_am.xtb b/chrome/android/java/strings/translations/android_chrome_strings_am.xtb
index ddb62bd..c3d9f15 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_am.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_am.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">ይህንን ምስል <ph name="SEARCH_ENGINE"/> ላይ ይፈልጉት</translation>
 <translation id="7764225426217299476">አድራሻ አክል</translation>
 <translation id="4816465935029283692">የውሂብ ዓይነቶች</translation>
-<translation id="5098185943924922330">ስለፋይሎች፣ መተግበሪያዎች፣ እና እየሰሩ ያሉ አገልግሎቶች በማናቸውም ጊዜ መሰናከል በሚያጋጥምዎት ጊዜ ወደ Google መረጃ በመላክ ልንሰራባቸው የሚገቡ ነገሮችን ቅድሚያ የሚሰጣቸውን እንድንለይ እና ማሻሻያዎችን እንድናደርግ ያግዙን።
-
-        የአጠቃቀም ስታትስቲክስ እንደ ምርጫዎች፣ የአዝራር ጠቅ ማድረጎች እና የማህደረ ትውስታ የመሳሰሉ መረጃዎችን ያካትታል። የድር ገጽ ዩአርኤሎችን ወይም ማናቸውም የግል መረጃዎችን አያካትቱም። የብልሽት ሪፖርቶች በብልሽቱ ጊዜ ያለውን የስርዓት መረጃ ይይዛሉ፣ እና በብልሽቱ ወቅት ምን እንደተፈጠረ የሚመረኮዝ ሆኖ  የድር ገጽ ዩአርኤሎች ወይም የግል መረጃን ይይዛሉ።</translation>
 <translation id="4042870126885713738">አንድ የድር አድራሻ መፍትሔ ካላመጣ ወይም ግንኙነት ሊፈጠር ካልቻለ ጥቆማዎችን አሳይ</translation>
 <translation id="8237438615979997762">በዚህ መሣሪያ እና እንዲሁም በGoogle መለያዎ ላይ የተከማቸው ውሂብ በሁለቱም ቦታዎች ላይ እንደሆኑ ይቀራሉ። ይሁንና አዲስ ውሂብ ወይም በውሂብዎ ላይ የሚያደርጓቸው ለውጦች አይመሳሰሉም።</translation>
 <translation id="6831043979455480757">መተርጎም</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ar.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ar.xtb
index 7552330..6c93a44 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ar.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ar.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">البحث في <ph name="SEARCH_ENGINE"/> عن هذه الصورة</translation>
 <translation id="7764225426217299476">إضافة عنوان</translation>
 <translation id="4816465935029283692">أنواع البيانات</translation>
-<translation id="5098185943924922330">‏ساعدنا على تحديد أولوية الميزات والتحسينات التي يجب علينا العمل عليها من خلال إرسال معلومات إلى Google حول الملفات، والتطبيقات، والخدمات التي تعمل عندما تواجه عطلاً.
-
-        يتضمن استخدام الإحصاءات معلومات، مثل التفضيلات، وعدد النقرات على الزر، واستخدام الذاكرة. ولا تتضمن عناوين URL لصفحات الويب أو أي معلومات شخصية. تحتوي تقارير الأعطال على معلومات النظام في وقت العطل، وقد تحتوي على عناوين URL لصفحات ويب أو معلومات شخصية، بناءً على ما كان يجري وقت حدوث العطل.</translation>
 <translation id="4042870126885713738">عرض اقتراحات عند تعذر فتح عنوان ويب أو تعذر إجراء اتصال</translation>
 <translation id="8237438615979997762">‏ستظل البيانات المخزنة على هذا الجهاز بالإضافة إلى البيانات المخزنة في حساب Google في كلا الموضعين. إلا أنه لن تتم مزامنة البيانات الجديدة أو التغييرات التي تجريها على بياناتك بينهما.</translation>
 <translation id="6831043979455480757">ترجمة</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_bg.xtb b/chrome/android/java/strings/translations/android_chrome_strings_bg.xtb
index 1ea70eb..5143ce8 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_bg.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_bg.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Търсене на изображението със: <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Добавяне на адрес</translation>
 <translation id="4816465935029283692">Типове данни</translation>
-<translation id="5098185943924922330">Помогнете ни да разберем над кои функции и подобрения трябва да работим първо, като изпращате до Google информация за файловете, приложенията и услугите, които се изпълняват при настъпване на срив.
-
-Статистическите данни за употребата съдържат информация като предпочитания, кликвания върху бутони и използвана памет. Те не включват URL адреси на уеб страници, нито каквато и да е лична информация. Сигналите за сривове съдържат системни данни от момента на срива и може да включват URL адреси на уеб страници или лична информация в зависимост от това, какво се е случвало по време на срива.</translation>
 <translation id="4042870126885713738">Показване на предложения, когато даден уеб адрес не може да бъде преобразуван или не може да бъде осъществена връзка</translation>
 <translation id="8237438615979997762">Съхраняваните на това устройство данни, както и тези, съхранявани в профила ви в Google, ще останат и на двете места. Новата информация или извършените в данните ви промени обаче няма да се синхронизират помежду им.</translation>
 <translation id="6831043979455480757">Превод</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb
index 457504f..a8268463 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ca.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Cerca aquesta imatge a <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Afegeix una adreça</translation>
 <translation id="4816465935029283692">Tipus de dades</translation>
-<translation id="5098185943924922330">Ajudeu-nos a prioritzar les funcions i les millores en les quals hem de treballar enviant-nos informació sobre els fitxers, les aplicacions i els serveis que s'executaven en el moment de l'error.
-
-        Les estadístiques d'ús inclouen dades com ara les preferències, els clics en botons i l'ús de la memòria. No inclouen els URL de les pàgines web ni cap informació personal. Els informes d'error contenen informació del sistema en el moment de l'error i poden incloure els URL de pàgines web o informació personal en funció de l'activitat existent en el moment de l'error.</translation>
 <translation id="4042870126885713738">Mostra suggeriments quan no es resol una adreça web o quan no es pot establir una connexió</translation>
 <translation id="8237438615979997762">Les dades emmagatzemades en aquest dispositiu i les que s'emmagatzemin al compte de Google es conservaran en totes dues ubicacions. Tanmateix, les dades noves o els canvis que hi feu no se sincronitzaran entre si.</translation>
 <translation id="6831043979455480757">Tradueix</translation>
@@ -184,9 +181,9 @@
 <translation id="8481940801237642152">La vostra connexió amb aquest lloc és privada, però és possible que algun usuari de la xarxa pugui canviar l'aspecte de la pàgina.</translation>
 <translation id="2593272815202181319">Monospace</translation>
 <translation id="4807098396393229769">Titular de la targeta</translation>
-<translation id="6036158371062192100">Si activeu No segueixis, s'inclourà una sol·licitud al trànsit de navegació. Que s'apliqui o no dependrà de si algun lloc web respon a la sol·licitud i de com s'interpreta la sol·licitud.
+<translation id="6036158371062192100">Si activeu No segueixis, s'inclourà una sol·licitud al trànsit de navegació. Que s'apliqui o no dependrà de si algun lloc web respon a la sol·licitud i de com s'interpreta.
 
-Per exemple, és possible que alguns llocs web responguin a aquesta sol·licitud i us mostrin anuncis que no es basen en altres llocs web que heu visitat. Molts llocs web continuaran recopilant i utilitzant les vostres dades de navegació, per exemple, per millorar la seguretat, per proporcionar contingut, anuncis i recomanacions als seus llocs web, i per generar estadístiques d'informes.</translation>
+Per exemple, és possible que alguns llocs web responguin a aquesta sol·licitud mostrant-vos anuncis que no basats en altres llocs web que heu visitat. Molts llocs web continuaran recopilant i utilitzant les vostres dades de navegació, per exemple, per millorar la seguretat, per proporcionar contingut, anuncis i recomanacions als seus llocs web, i per generar estadístiques.</translation>
 <translation id="6710213216561001401">Anterior</translation>
 <translation id="656628257199996201">Tradueix sempre: <ph name="SOURCE_LANGUAGE"/></translation>
 <translation id="2387895666653383613">Canvia la mida del text</translation>
@@ -209,7 +206,7 @@
 <translation id="3328801116991980348">Informació del lloc</translation>
 <translation id="7987073022710626672">Condicions del servei de Chrome</translation>
 <translation id="588258955323874662">Pantalla completa</translation>
-<translation id="5668404140385795438">Substitueix la sol·licitud d'un lloc web per evitar que s'apropi</translation>
+<translation id="5668404140385795438">Ignora la sol·licitud d'un lloc web per evitar que s'apropi la imatge</translation>
 <translation id="8428213095426709021">Configuració</translation>
 <translation id="7493994139787901920"><ph name="VERSION"/> (última actualització: <ph name="TIME_SINCE_UPDATE"/>)</translation>
 <translation id="7711895876052978264">Aquest lloc es mostra en pantalla completa
@@ -269,7 +266,7 @@
 <translation id="4698413471314543145">Falta una funcionalitat crítica necessària per executar Chrome; la vostra instal·lació de Chrome no està completa o bé no és compatible amb aquesta versió d'Android.</translation>
 <translation id="1943432128510653496">Desa les contrasenyes</translation>
 <translation id="4113030288477039509">Gestionat per l'administrador</translation>
-<translation id="9100610230175265781">Es necessita una frase de contrasenya.</translation>
+<translation id="9100610230175265781">S'ha d'introduir una frase de contrasenya </translation>
 <translation id="1829244130665387512">Cerca a la pàgina</translation>
 <translation id="4148957013307229264">S'està instal·lant...</translation>
 <translation id="7096034533295549981">Carregant vídeo</translation>
@@ -365,7 +362,7 @@
 <translation id="6040143037577758943">Tanca</translation>
 <translation id="4943872375798546930">No hi ha resultats</translation>
 <translation id="2139186145475833000">Afegeix a pantalla d'inici</translation>
-<translation id="2888126860611144412">Quan a Chrome</translation>
+<translation id="2888126860611144412">Quant a Chrome </translation>
 <translation id="7876243839304621966">Suprimeix-ho tot</translation>
 <translation id="5138299137310274655">La pàgina està en <ph name="SOURCE_LANGUAGE"/>. Voleu traduir-la i que es mostri en <ph name="TARGET_LANGUAGE"/>?</translation>
 <translation id="2913331724188855103">Permet que els llocs desin i llegeixin les dades de les galetes (recomanat)</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_cs.xtb b/chrome/android/java/strings/translations/android_chrome_strings_cs.xtb
index 2f453705..b51cd95 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_cs.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_cs.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Hledat obrázek pomocí <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Přidat adresu</translation>
 <translation id="4816465935029283692">Typy dat</translation>
-<translation id="5098185943924922330">Pomozte nám upřednostnit funkce a vylepšení, na kterých bychom měli pracovat. Odesílejte do Googlu informace o souborech, aplikacích a službách spuštěných při selhání.
-
-        Statistiky využití obsahují informace, jako jsou předvolby, kliknutí na tlačítka a využití paměti. Neobsahují adresy URL webových stránek ani žádné osobní údaje. Zprávy o selhání obsahují informace o systému v době selhání a mohou obsahovat adresy URL webových stránek nebo osobní údaje (v závislosti na činnosti, kterou jste v době selhání právě prováděli).</translation>
 <translation id="4042870126885713738">Zobrazovat návrhy, pokud nelze vyhledat webovou adresu nebo navázat připojení.</translation>
 <translation id="8237438615979997762">Data uložená v tomto zařízení i data uložená ve vašem účtu Google zůstanou na obou místech. Pokud však přidáte nová data nebo v datech provedete změny, nedojde k synchronizaci.</translation>
 <translation id="6831043979455480757">Přeložit</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_da.xtb b/chrome/android/java/strings/translations/android_chrome_strings_da.xtb
index cc05402f..988384d 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_da.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_da.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Søg efter billedet på <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Tilføj adresse</translation>
 <translation id="4816465935029283692">Datatyper</translation>
-<translation id="5098185943924922330">Hjælp os med at prioritere de funktioner og forbedringer, vi bør arbejde på, ved at sende oplysninger til Google om, hvilke filer, applikationer og tjenester, der kører, når du oplever et nedbrud.
-
-        Brugsstatistik indeholder oplysninger såsom indstillinger, antal klik på knappen og hukommelsesforbrug. De omfatter ikke webadresser eller personlige oplysninger. Nedbrudsrapporter indeholder systemoplysninger på tidspunktet for nedbruddet og kan indeholde webadresser eller personlige oplysninger, afhængigt af hvad der skete på tidspunktet for nedbruddet.</translation>
 <translation id="4042870126885713738">Vis forslag, hvis en webadresse ikke bliver fundet, eller hvis der ikke kan oprettes forbindelse</translation>
 <translation id="8237438615979997762">De data, som er gemt på denne enhed og på din Google-konto, vil fortsat være gemt begge steder. Nye data eller ændringer, som du foretager, synkroniseres dog ikke imellem de to.</translation>
 <translation id="6831043979455480757">Oversæt</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_de.xtb b/chrome/android/java/strings/translations/android_chrome_strings_de.xtb
index 38b83f5..f3b04e6b 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_de.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_de.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">In <ph name="SEARCH_ENGINE"/> nach dem Bild suchen</translation>
 <translation id="7764225426217299476">Adresse hinzufügen</translation>
 <translation id="4816465935029283692">Datentypen</translation>
-<translation id="5098185943924922330">Helfen Sie uns dabei, den Funktionen und Verbesserungen Priorität einzuräumen, die Ihnen wichtig sind, indem Sie Informationen über die Dateien, Anwendungen und Dienste, die zum Zeitpunkt eines Absturzes ausgeführt wurden, an Google senden.
-
-        Nutzungsstatistiken enthalten Informationen wie Einstellungen, Klicks auf Schaltflächen und Speicherauslastung. Sie enthalten keine URLs von Webseiten oder personenbezogenen Daten. Absturzberichte enthalten Systeminformationen zum Zeitpunkt des Absturzes. Je nachdem, was zu diesem Zeitpunkt gerade geschah, können auch URLs von Webseiten oder personenbezogene Daten erfasst werden.</translation>
 <translation id="4042870126885713738">Vorschläge einblenden, wenn eine Webadresse nicht gefunden oder keine Verbindung hergestellt werden kann</translation>
 <translation id="8237438615979997762">Sowohl die auf diesem Gerät gespeicherten Daten als auch die Daten in Ihrem Google-Konto verbleiben an ihren jeweiligen Speicherorten. Neue Daten und Änderungen werden jedoch nicht synchronisiert.</translation>
 <translation id="6831043979455480757">Übersetzen</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_el.xtb b/chrome/android/java/strings/translations/android_chrome_strings_el.xtb
index bf77fe51..aac5b07 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_el.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_el.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Αναζήτηση <ph name="SEARCH_ENGINE"/> για την εικόνα</translation>
 <translation id="7764225426217299476">Προσθήκη διεύθυνσης</translation>
 <translation id="4816465935029283692">Τύποι δεδομένων</translation>
-<translation id="5098185943924922330">Βοηθήστε μας να ορίσουμε προτεραιότητες στις λειτουργίες και τις βελτιώσεις, πάνω στις οποίες πρέπει να εργαστούμε, αποστέλλοντας στην Google πληροφορίες σχετικά με τα αρχεία, τις εφαρμογές και τις υπηρεσίες που εκτελούνται κάθε φορά που προκύπτει κάποιο σφάλμα.
-
-        Τα στατιστικά χρήσης περιλαμβάνουν πληροφορίες όπως οι προτιμήσεις, τα κλικ κουμπιών και η χρήση της μνήμης. Αυτές δεν περιλαμβάνουν διευθύνσεις URL ιστοσελίδων ή προσωπικές πληροφορίες. Οι αναφορές σφαλμάτων περιέχουν πληροφορίες συστήματος για τη χρονική στιγμή που παρουσιάστηκε το σφάλμα και ενδέχεται να περιλαμβάνουν διευθύνσεις URL ιστοσελίδων ή προσωπικές πληροφορίες, ανάλογα με το τι συνέβαινε στον υπολογιστή τη χρονική στιγμή που παρουσιάστηκε το σφάλμα.</translation>
 <translation id="4042870126885713738">Εμφάνιση προτάσεων όταν μια διεύθυνση ιστού δεν αναλύεται σωστά ή δεν είναι δυνατό να πραγματοποιηθεί σύνδεση</translation>
 <translation id="8237438615979997762">Τα δεδομένα που αποθηκεύτηκαν σε αυτήν τη συσκευή, καθώς και τα δεδομένα που αποθηκεύτηκαν στο Λογαριασμό σας Google θα παραμείνουν και στα δύο μέρη. Ωστόσο, τα νέα δεδομένα ή οι αλλαγές που πραγματοποιήσατε στα δεδομένα σας δεν θα συγχρονιστούν μεταξύ τους.</translation>
 <translation id="6831043979455480757">Μετάφραση</translation>
@@ -280,7 +277,8 @@
 <translation id="7521387064766892559">JavaScript</translation>
 <translation id="1974060860693918893">Σύνθετες</translation>
 <translation id="8168435359814927499">Περιεχόμενο</translation>
-<translation id="5424715742813396254">Επεξεργασία αποθηκευμένου ονόματος/κωδικού πρόσβασης ή εξαίρεσης</translation>
+<translation id="5424715742813396254">Επεξεργασία ονόματος/κωδικού πρόσβασης ή εξαίρεσης
+</translation>
 <translation id="6978479750597523876">Επαναφορά ρυθμίσεων μετάφρασης</translation>
 <translation id="2476578072172137802">Ρυθμίσεις ιστότοπου</translation>
 <translation id="6820686453637990663">CVC</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_en-GB.xtb b/chrome/android/java/strings/translations/android_chrome_strings_en-GB.xtb
index 8ca6845..eb12512 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_en-GB.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_en-GB.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Search <ph name="SEARCH_ENGINE"/> for this image</translation>
 <translation id="7764225426217299476">Add address</translation>
 <translation id="4816465935029283692">Data types</translation>
-<translation id="5098185943924922330">Help us to prioritise the features and improvements that we should work on by sending Google information about the files, applications and services running whenever you experience a crash.
-
-        Usage statistics include information such as preferences, button clicks and memory usage. They do not include web page URLs or any personal information. Crash reports contain system information at the time of the crash, and may contain web page URLs or personal information, depending on what was happening at the time of the crash.</translation>
 <translation id="4042870126885713738">Show suggestions when a web address does not resolve or a connection cannot be made</translation>
 <translation id="8237438615979997762">The data stored on this device as well as the data stored in your Google Account will remain in both places. However, new data or changes that you make to your data will not be synchronised between them.</translation>
 <translation id="6831043979455480757">Translate</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb b/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb
index 2c19435..d9dc5f8 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_es-419.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Buscar esta imagen en <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Agregar dirección</translation>
 <translation id="4816465935029283692">Tipos de datos</translation>
-<translation id="5098185943924922330">Ayúdanos a establecer prioridades entre las características y las mejoras en las que debemos trabajar: envía información a Google acerca de los archivos, las aplicaciones y los servicios en ejecución cuando se produce un bloqueo.
-
-        Las Estadísticas de uso incluyen información, como las preferencias, los clics en los botones y el uso de memoria. No incluyen las URL de las páginas web ni ninguna información personal. Los informes de fallos incluyen la información del sistema en el momento del bloqueo y pueden contener URL de páginas web o información personal, según lo que haya ocurrido en el momento del bloqueo.</translation>
 <translation id="4042870126885713738">Mostrar sugerencias cuando no se resuelve una dirección web o cuando no se puede establecer una conexión</translation>
 <translation id="8237438615979997762">Los datos que almacenaste en este dispositivo o en tu cuenta de Google no se perderán. Sin embargo, los datos que agregues o los cambios que realices no se sincronizarán entre ellos.</translation>
 <translation id="6831043979455480757">Traducir</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_es.xtb b/chrome/android/java/strings/translations/android_chrome_strings_es.xtb
index 64351e3..b229bce1 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_es.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_es.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Buscar esta imagen en <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Añadir dirección</translation>
 <translation id="4816465935029283692">Tipos de datos</translation>
-<translation id="5098185943924922330">Ayúdanos a priorizar las funciones y las mejoras en las que debemos trabajar enviando información a Google sobre los archivos, las aplicaciones y los servicios utilizados cuando se produce un error.
-
-Las estadísticas de uso incluyen información como, por ejemplo, preferencias, clics en botones y uso de la memoria. No incluyen las URL de páginas web ni información personal. Los informes sobre fallos contienen información del sistema en el momento del error y pueden incluir las URL de páginas web o información personal, en función de lo que haya sucedido en el momento del fallo.</translation>
 <translation id="4042870126885713738">Muestra sugerencias cuando no se puede resolver una dirección web o no se puede establecer una conexión</translation>
 <translation id="8237438615979997762">Los datos almacenados en este dispositivo y los datos asociados a tu cuenta de Google se mantendrán en ambos sitios. Sin embargo, los datos nuevos o los cambios que realices en tus datos no se sincronizarán entre ellos.</translation>
 <translation id="6831043979455480757">Traducir</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_fa.xtb b/chrome/android/java/strings/translations/android_chrome_strings_fa.xtb
index d49f4177..aafc585 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_fa.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_fa.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">جستجوی <ph name="SEARCH_ENGINE"/> برای این تصویر</translation>
 <translation id="7764225426217299476">افزودن آدرس</translation>
 <translation id="4816465935029283692">انواع داده</translation>
-<translation id="5098185943924922330">‏هر زمان که فایل‌ها، برنامه‌ها و سرویس‌های در حال اجرا خراب می‌شوند، اطلاعاتی را درباره آن‌ها به Google ارسال کنید و به ما در اولویت‌بندی ویژگی‌ها و بهبودهایی که باید روی آن‌ها کار کنیم، کمک کنید.
-
-        آمار کاربرد شامل اطلاعاتی مانند تنظیمات برگزیده، کلیک‌های روی دکمه و مصرف حافظه می‌شود. آن‌ها شامل نشانی‌های اینترنتی صفحه وب یا هر اطلاعات شخصی دیگری نمی‌شوند. گزارش‌های خرابی شامل اطلاعات سیستم در زمان خراب شدن است و ممکن است بسته به آنچه که در زمان خرابی اتفاق افتاده است، نشانی‌های اینترنتی صفحه وب یا اطلاعات شخصی را در برگیرد.</translation>
 <translation id="4042870126885713738">وقتی آدرس وب شناسایی نمی‌شود یا اتصال برقرار نمی‌شود، پیشنهاداتی نشان داده می‌شود</translation>
 <translation id="8237438615979997762">‏داده‌های ذخیره‌شده در این دستگاه و داده‌های ذخیره‌شده در حساب Google شما همچنان در هر دو مکان خواهند بود. اما داده‌های جدید یا تغییراتی که در داده‌هایتان ایجاد می‌کنید بین آنها همگام‌سازی نمی‌شود.</translation>
 <translation id="6831043979455480757">ترجمه</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_fi.xtb b/chrome/android/java/strings/translations/android_chrome_strings_fi.xtb
index a9ce2e6f..6495443 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_fi.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_fi.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Etsi tätä kuvaa palvelusta <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Lisää osoite</translation>
 <translation id="4816465935029283692">Tietotyypit</translation>
-<translation id="5098185943924922330">Voit auttaa Googlea suunnittelemaan ominaisuuksien ja parannuksien tärkeysjärjestystä, jos lähetät meille jokaisen kaatumisen jälkeen tietoja käynnissä olleista tiedostoista, sovelluksista palveluista.
-
-        Käyttötilastot sisältävät tietoja esimerkiksi asetuksista, painetuista painikkeista ja muistin käytöstä. Ne eivät sisällä verkkosivujen URL-osoitteita tai henkilötietoja. Virheraportit sisältävät tietoja järjestelmästä virheen aikana, ja niihin voi sisältyä verkkosivujen URL-osoitteita tai henkilökohtaisia tietoja riippuen siitä, mitä virheen aikana tapahtui.</translation>
 <translation id="4042870126885713738">Näytä ehdotuksia, jos verkko-osoitetta ei tunnisteta tai yhteyttä ei voi muodostaa.</translation>
 <translation id="8237438615979997762">Tälle laitteelle sekä Google-tiliisi tallennetut tiedot säilyvät molemmissa paikoissa. Uusia tietoja tai tietoihin tekemiäsi muutoksia ei kuitenkaan synkronoida.</translation>
 <translation id="6831043979455480757">Käännä</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_fil.xtb b/chrome/android/java/strings/translations/android_chrome_strings_fil.xtb
index ab72281..2fec684 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_fil.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_fil.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Hanapin sa <ph name="SEARCH_ENGINE"/> ang larawan</translation>
 <translation id="7764225426217299476">Magdagdag ng address</translation>
 <translation id="4816465935029283692">Mga uri ng data</translation>
-<translation id="5098185943924922330">Tulungan kaming unahin ang mga feature at pagpapahusay na dapat naming gawin sa pamamagitan ng pagpapadala sa Google ng impormasyon tungkol sa mga file, application at serbisyo na tumatakbo kapag nakaranas ka ng pag-crash.
-
-        Kasama sa mga istatistika sa paggamit ang impormasyon tulad ng mga kagustuhan, pag-click ng button at paggamit ng memory. Hindi kasama sa mga ito ang mga URL ng webpage o anumang personal na impormasyon. Naglalaman ang mga ulat ng pag-crash ng mga impormasyon ng system sa oras ng pag-crash, at maaaring maglaman ng mga URL ng web page o personal na impormasyon, depende sa kung ano ang nangyayari sa oras ng pag-crash.</translation>
 <translation id="4042870126885713738">Magpakita ng mga suhestyon kapag hindi ma-resolve ang isang website o kung hindi makakonekta</translation>
 <translation id="8237438615979997762">Ang data na nakaimbak sa device na ito pati na rin ang data na nakaimbak sa iyong Google Account ay mananatili sa dalawang lugar. Gayunpaman, hindi isi-synchronize sa pagitan ng mga ito ang bagong data o mga pagbabagong gagawin mo sa iyong data.</translation>
 <translation id="6831043979455480757">Isalin</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_fr.xtb b/chrome/android/java/strings/translations/android_chrome_strings_fr.xtb
index 9bb92672..b0631b49 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_fr.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_fr.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Rechercher l'image sur <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Ajouter une adresse</translation>
 <translation id="4816465935029283692">Types de données</translation>
-<translation id="5098185943924922330">Aidez-nous à identifier les fonctionnalités et les améliorations sur lesquelles nous devons travailler en priorité en nous envoyant des informations sur les fichiers, les applications et les services en cours d'exécution au moment où vous constatez un plantage.
-
-        Les statistiques d'utilisation englobent des informations telles que les préférences, les clics sur les boutons et l'utilisation de la mémoire. Elles n'incluent pas d'URL de pages Web ni d'informations personnelles. Les rapports d'erreur contiennent des informations relatives au système au moment du plantage, et peuvent contenir des URL de pages Web ou des informations personnelles, en fonction des activités en cours lors de l'incident.</translation>
 <translation id="4042870126885713738">Afficher d'autres solutions lorsqu'une adresse Web ne peut pas être résolue ou qu'une connexion ne peut pas être établie</translation>
 <translation id="8237438615979997762">Les données stockées sur cet appareil et dans votre compte Google seront conservées. Toutefois, les nouvelles données ou les modifications apportées aux données ne seront pas synchronisées entre ces deux emplacements.</translation>
 <translation id="6831043979455480757">Traduire</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_hi.xtb b/chrome/android/java/strings/translations/android_chrome_strings_hi.xtb
index e4126e6..5e7b6ca 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_hi.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_hi.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">इस चित्र के लिए <ph name="SEARCH_ENGINE"/> खोजें</translation>
 <translation id="7764225426217299476">पता जोड़ें</translation>
 <translation id="4816465935029283692">डेटा प्रकार</translation>
-<translation id="5098185943924922330">जब भी क्रैश हो, तो उस दौरान चलने वाली फ़ाइल, ऐप्लिकेशन और सेवाओं के बारे में जानकारी Google को भेजकर उन सुविधाओं और सुधारों को प्राथमिकता देने में हमारी सहायता करें जिन पर हमें काम करना चाहिए.
-
-        उपयोग के आंकड़ों में प्राथमिकताएं, बटन क्लिक और मेमोरी उपयोग जैसी जानकारी शामिल की जाती है. उनमें वेबपृष्ठ URL या कोई व्यक्तिगत जानकारी शामिल नहीं की जाती है. क्रैश रिपोर्ट में क्रैश के समय की सिस्टम जानकारी होती है और क्रैश के समय जो हो रहा था, उसके आधार पर वेब पृष्ठ के URL की या व्यक्तिगत जानकारी हो सकती है.</translation>
 <translation id="4042870126885713738">किसी वेब पते का समाधान ना होने या कनेक्शन ना हो सकने पर सुझाव दिखाएं</translation>
 <translation id="8237438615979997762">इस डिवाइस पर संग्रहीत डेटा के साथ ही आपके Google खाते में संग्रहीत डेटा दोनों स्थानों में बना रहेगा. हालांकि, नया डेटा या आपके द्वारा अपने डेटा में किए जाने वाले बदलाव उनके बीच समन्वयित नहीं किए जाएंगे.</translation>
 <translation id="6831043979455480757">अनुवाद करें</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_hr.xtb b/chrome/android/java/strings/translations/android_chrome_strings_hr.xtb
index bd91634fc..f49c145d 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_hr.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_hr.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Potraži sliku na usluzi <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Dodaj adresu</translation>
 <translation id="4816465935029283692">Vrste podataka</translation>
-<translation id="5098185943924922330">Svaki put kada se nešto sruši, pošaljite Googleu informacije o datotekama, aplikacijama i uslugama koje se izvode kako biste nam pomogli odrediti kojim bismo značajkama i poboljšanjima trebali dati prednost.
-
-        Statistika upotrebe uključuje informacije kao što su postavke, klikovi na gumbe i upotreba memorije. Ne uključuje URL-ove web-stranica ni osobne podatke. Izvješća o rušenju programa sadrže informacije o sustavu u trenutku rušenja i mogu sadržavati URL-ove web-stranica ili osobne podatke, ovisno o tome što se događalo u trenutku rušenja.</translation>
 <translation id="4042870126885713738">Prikaži prijedloge kada se ne razriješi web-adresa ili nije moguće uspostaviti vezu</translation>
 <translation id="8237438615979997762">Podaci spremljeni na ovom uređaju, kao i podaci spremljeni na vašem Google računu ostat će na oba mjesta. Međutim, novi podaci ili promjene podataka neće se sinkronizirati između ta dva mjesta.</translation>
 <translation id="6831043979455480757">Prevedi</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_hu.xtb b/chrome/android/java/strings/translations/android_chrome_strings_hu.xtb
index 154eac65..c8e42de8 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_hu.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_hu.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">A kép keresése a(z) <ph name="SEARCH_ENGINE"/> keresővel</translation>
 <translation id="7764225426217299476">Cím hozzáadása</translation>
 <translation id="4816465935029283692">Adattípusok</translation>
-<translation id="5098185943924922330">Segítsen nekünk annak eldöntésében, hogy mely funkciókon és fejlesztéseken kell előbb dolgoznunk – küldje el a Google-nak a böngésző lefagyásakor éppen futó fájlokkal, alkalmazásokkal és szolgáltatásokkal kapcsolatos információkat.
-
-        A használati statisztika részét alkotják például a beállítások, a gombokra kattintások és a memóriahasználat. Nem tartalmazzák weboldalak URL-jeit és semmilyen személyes adatot. A hibajelentések a hiba időpontjában aktuális rendszer-információkat tartalmazzák, de tartalmazhatják weboldalak URL-címeit vagy személyes adatokat is, attól függően, hogy mi történt a hiba időpontjában.</translation>
 <translation id="4042870126885713738">Javaslatok megjelenítése, ha egy internetcímet nem lehet feloldani, vagy nem lehet kapcsolódni</translation>
 <translation id="8237438615979997762">A jelen eszközön, valamint az Ön Google-fiókjában tárolt adatok mindkét helyen megmaradnak, azonban az új adatok, illetve a meglévő adatokban végrehajtott módosítások nem lesznek szinkronizálva.</translation>
 <translation id="6831043979455480757">Fordítás</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_id.xtb b/chrome/android/java/strings/translations/android_chrome_strings_id.xtb
index d3fa1fea..86d8e4c0 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_id.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_id.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Telusuri <ph name="SEARCH_ENGINE"/> untuk gambar ini</translation>
 <translation id="7764225426217299476">Tambahkan alamat</translation>
 <translation id="4816465935029283692">Jenis data</translation>
-<translation id="5098185943924922330">Bantu kami memprioritaskan fitur dan penyempurnaan yang harus dikerjakan dengan mengirimkan informasi tentang file, aplikasi, dan layanan yang sedang berjalan kepada Google kapan pun aplikasi mogok.
-
-        Statistik penggunaan mencakup informasi seperti preferensi, klik tombol, dan penggunaan memori. Statistik ini tidak mencakup URL laman web atau informasi pribadi apa pun. Laporan kerusakan berisi informasi sistem saat terjadi mogok dan dapat berisi URL laman web atau informasi pribadi, bergantung pada apa yang terjadi saat aplikasi mogok.</translation>
 <translation id="4042870126885713738">Tampilkan saran saat alamat web tidak dapat menyelesaikan masalah atau sambungan tidak dapat dibuat</translation>
 <translation id="8237438615979997762">Data yang tersimpan di perangkat ini, serta data yang tersimpan di Akun Google, akan tetap berada di tempatnya masing-masing. Namun, data baru atau perubahan yang dibuat pada data tidak akan disinkronkan di antara keduanya.</translation>
 <translation id="6831043979455480757">Terjemahkan</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_it.xtb b/chrome/android/java/strings/translations/android_chrome_strings_it.xtb
index a0e2869..d02c2fd5 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_it.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_it.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Cerca questa immagine su <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Aggiungi indirizzo</translation>
 <translation id="4816465935029283692">Tipi di dati</translation>
-<translation id="5098185943924922330">Aiutaci a scegliere le funzioni e i miglioramenti a cui dare la priorità inviando a Google informazioni sui file, sulle applicazioni e sui servizi in esecuzione quando si verifica un arresto anomalo.
-
-        Le statistiche sull'utilizzo includono informazioni quali preferenze, clic sui pulsanti e utilizzo della memoria. Non includono gli URL delle pagine web o le informazioni personali. I rapporti sugli arresti anomali contengono informazioni sul sistema al momento dell'arresto anomalo e potrebbero includere URL di pagine web o informazioni personali, in base alle attività in corso al momento dell'arresto.</translation>
 <translation id="4042870126885713738">Mostra suggerimenti quando un indirizzo web non viene risolto o non è possibile stabilire una connessione</translation>
 <translation id="8237438615979997762">I dati memorizzati su questo dispositivo e quelli memorizzati nel tuo account Google rimarranno nelle rispettive posizioni. Tuttavia, i nuovi dati o le modifiche apportate ai tuoi dati non verranno sincronizzati tra loro.</translation>
 <translation id="6831043979455480757">Traduci</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_iw.xtb b/chrome/android/java/strings/translations/android_chrome_strings_iw.xtb
index ac59c098..8501679 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_iw.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_iw.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">חפש את התמונה הזו ב-<ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">הוסף כתובת</translation>
 <translation id="4816465935029283692">סוגי נתונים</translation>
-<translation id="5098185943924922330">‏כדי לעזור לנו לקבוע את סדר העדיפויות לגבי תכונות ושיפורים שעלינו לעבוד עליהם, שלח ל-Google מידע על הקבצים, על האפליקציות ועל השירותים הפועלים בזמן שאתה נתקל בקריסה.
-
-        סטטיסטיקות השימוש כוללות מידע כגון העדפות, לחיצות על לחצנים ושימוש בזיכרון. הן אינן כוללות כתובות של דפי אינטרנט או מידע אישי. דוחות קריסה מכילים מידע על המערכת בזמן הקריסה, והם עשויים להכיל כתובות של דפי אינטרנט או מידע אישי, בהתאם למתרחש בזמן הקריסה.</translation>
 <translation id="4042870126885713738">הצג הצעות כאשר כתובת אינטרנט אינה מזוהה או כשלא ניתן ליצור חיבור</translation>
 <translation id="8237438615979997762">‏הנתונים השמורים במכשיר הזה והנתונים השמורים בחשבון Google שלך יישארו בשני המקומות. עם זאת, לא יתבצע בין השניים סנכרון של נתונים חדשים שתוסיף או של שינויים שתבצע בנתונים הקיימים.</translation>
 <translation id="6831043979455480757">תרגם</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ja.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ja.xtb
index 7faad09..38719c4 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ja.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ja.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">この画像を <ph name="SEARCH_ENGINE"/> で検索</translation>
 <translation id="7764225426217299476">住所を追加</translation>
 <translation id="4816465935029283692">データタイプ</translation>
-<translation id="5098185943924922330">Google では優先度の高い機能から順に開発や改善に取り組みたいと考えています。そのため、障害が発生した場合は、実行していたファイル、アプリケーション、サービスに関する情報を Google に送信していただけますと幸いです。
-
-使用統計データには、設定、ボタンのクリック数、メモリの使用状況などの情報が含まれ、ウェブページの URL や個人情報は含まれません。障害レポートには、障害発生時のシステム情報が含まれ、障害発生時の状況によってはウェブページの URL や個人情報が含まれることもあります。</translation>
 <translation id="4042870126885713738">ウェブアドレスが解決されない場合や接続を確立できない場合にアドバイスを表示します</translation>
 <translation id="8237438615979997762">このデバイスに保存されているデータと Google アカウントに保存されているデータはそのまま残ります。ただし、データを追加したり変更したりしてもデバイス間での同期は行われません。</translation>
 <translation id="6831043979455480757">翻訳</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ko.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ko.xtb
index 1d4dac3..4ece516 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ko.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ko.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820"><ph name="SEARCH_ENGINE"/>에서 이 이미지 검색</translation>
 <translation id="7764225426217299476">주소 추가</translation>
 <translation id="4816465935029283692">데이터 유형</translation>
-<translation id="5098185943924922330">다운이 발생할 때마다 실행 중인 파일, 애플리케이션, 서비스에 관한 정보를 Google에 전송하여 우선적으로 구현해야 할 기능과 개선사항을 정할 수 있도록 도와주세요.
-
-        사용 통계에는 환경설정, 버튼 클릭수, 메모리 사용량과 같은 정보가 포함되며 웹페이지 URL이나 개인정보는 포함되어 있지 않습니다. 오류 보고서에는 문제가 발생했을 당시의 시스템 정보가 포함되며 발생 당시 상황에 따라 웹페이지 URL이나 개인정보가 포함될 수도 있습니다.</translation>
 <translation id="4042870126885713738">웹 주소가 확인되지 않거나 연결되지 않는 경우 추천 주소 표시</translation>
 <translation id="8237438615979997762">이 기기에 저장된 데이터뿐만 아니라 Google 계정에 저장된 데이터도 그대로 유지됩니다. 그러나 데이터에 새로 추가하거나 변경한 사항은 서로 동기화되지 않습니다.</translation>
 <translation id="6831043979455480757">번역</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_lt.xtb b/chrome/android/java/strings/translations/android_chrome_strings_lt.xtb
index 4507fcd..81a069444 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_lt.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_lt.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Ieškoti „<ph name="SEARCH_ENGINE"/>“ šio vaizdo</translation>
 <translation id="7764225426217299476">Pridėti adresą</translation>
 <translation id="4816465935029283692">Duomenų tipai</translation>
-<translation id="5098185943924922330">Padėkite pirmiausia sutelkti dėmesį į funkcijas ir patobulinimus, ties kuriais turėtume padirbėti, į sistemą „Google“ siųsdami informacijos apie failus, programas ir paslaugas, kurios buvo vykdomos per strigtį.
-
-        Naudojimo statistika yra įvairi informacija, įskaitant nuostatas, mygtukų paspaudimus ir atminties naudojimą. Tinklalapių URL adresai ar kita asmeninė informacija neįtraukiama. Strigčių ataskaitose pateikiama užstrigusios sistemos informacija ir jose gali būti tinklalapių URL adresų ar asmeninės informacijos, atsižvelgiant į tai, kas vyko per strigtį.</translation>
 <translation id="4042870126885713738">Rodyti pasiūlymus, kai žiniatinklio adresas nepasiekiamas arba nepavyksta užmegzti ryšio</translation>
 <translation id="8237438615979997762">Šiame įrenginyje ir „Google“ paskyroje saugomi duomenys liks abiejose vietose. Tačiau nauji duomenys ar atlikti duomenų pakeitimai nebus sinchronizuojami.</translation>
 <translation id="6831043979455480757">Vertėjas</translation>
@@ -280,7 +277,8 @@
 <translation id="7521387064766892559">„JavaScript“</translation>
 <translation id="1974060860693918893">Išplėstiniai</translation>
 <translation id="8168435359814927499">Turinys</translation>
-<translation id="5424715742813396254">Išsaugoto vardo / slaptažodžio arba išimties redagavimas</translation>
+<translation id="5424715742813396254">Išs. vardo, slaptaž. ar išimt. red. 
+</translation>
 <translation id="6978479750597523876">Nustatyti vertimo nustatymus iš naujo</translation>
 <translation id="2476578072172137802">Svetainės nustatymai</translation>
 <translation id="6820686453637990663">CVC</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_lv.xtb b/chrome/android/java/strings/translations/android_chrome_strings_lv.xtb
index a8421f9..9608af3 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_lv.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_lv.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Meklēt šo attēlu ar <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Pievienot adresi</translation>
 <translation id="4816465935029283692">Datu tipi</translation>
-<translation id="5098185943924922330">Nosūtot Google serveriem informāciju par failiem, lietojumprogrammām un pakalpojumiem, kuri darbojas brīdī, kad notiek avārija, palīdziet mums noteikt to funkciju un uzlabojumu prioritāti, pie kā mums ir jāstrādā.
-
-        Lietojuma statistikas datos tiek ietverta tāda informācija kā preferences, klikšķi uz pogām un atmiņas lietojums. Datos netiek ietverti tīmekļa lapu URL un nekāda veida personas informācija. Avāriju pārskatos tiek ietverta avārijas brīdī pieejamā informācija par sistēmu, kā arī var tikt ietverti tīmekļa lapu URL vai personas informācija atkarībā no tā, kas avārijas brīdī ir noticis.</translation>
 <translation id="4042870126885713738">Rādīt ieteikumus, ja nedarbojas tīmekļa adrese vai nevar izveidot savienojumu.</translation>
 <translation id="8237438615979997762">Šajā ierīcē un Google kontā glabātie dati joprojām būs pieejami abās vietās, taču jauni dati vai datos veiktās izmaiņas netiks sinhronizētas.</translation>
 <translation id="6831043979455480757">Tulkot</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_nl.xtb b/chrome/android/java/strings/translations/android_chrome_strings_nl.xtb
index 401b8af..6ddf6af 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_nl.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_nl.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Zoeken op <ph name="SEARCH_ENGINE"/> naar afbeelding</translation>
 <translation id="7764225426217299476">Adres toevoegen</translation>
 <translation id="4816465935029283692">Gegevenstypen</translation>
-<translation id="5098185943924922330">Help ons prioriteit aan te geven in de functies en verbeteringen waaraan we moeten werken door Google informatie te sturen over de bestanden, apps en services die worden uitgevoerd op het moment waarop een crash plaatsvindt.
-
-        Gebruiksstatistieken omvatten informatie zoals voorkeuren, klikken op knoppen en geheugengebruik. Ze bevatten geen URL's van webpagina's of persoonlijke gegevens. Crashrapporten bevatten systeeminformatie ten tijde van de crash en kunnen URL's van webpagina's of persoonlijke gegevens bevatten, afhankelijk van wat er gebeurde op het moment van de crash.</translation>
 <translation id="4042870126885713738">Suggesties weergeven wanneer een webadres onjuist is of er geen verbinding kan worden gemaakt</translation>
 <translation id="8237438615979997762">De gegevens die op dit apparaat zijn opgeslagen en de gegevens die in je Google-account zijn opgeslagen, blijven op die plaatsen staan. Nieuwe gegevens of wijzigingen die je aanbrengt, worden echter niet gesynchroniseerd.</translation>
 <translation id="6831043979455480757">Vertalen</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_no.xtb b/chrome/android/java/strings/translations/android_chrome_strings_no.xtb
index 0e6cadb..0606357 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_no.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_no.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Søk etter dette bildet i <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Legg til adresse</translation>
 <translation id="4816465935029283692">Datatyper</translation>
-<translation id="5098185943924922330">Hjelp oss med å prioritere funksjonene og forbedringene vi skal jobbe på, ved å sende Google informasjon om filene, appene og tjenestene som kjører når du opplever et krasj.
-
-        Bruksstatistikken inneholder informasjon om for eksempel innstillinger, knappeklikk og minnebruk. Den inneholder ikke nettadresser eller personopplysninger. Programstopprapporter inneholder systeminformasjon fra krasjtidspunktet, og de kan inneholde nettadresser eller personopplysninger, avhengig av hva som skjedde på krasjtidspunktet.</translation>
 <translation id="4042870126885713738">Vis forslag når en nettadresse ikke fungerer eller en tilkobling ikke kan opprettes</translation>
 <translation id="8237438615979997762">Data som er lagret på denne enheten, samt data som er lagret i Google-kontoen din, blir værende på begge steder. Nye data eller eventuelle endringer i eksisterende data blir imidlertid ikke synkronisert mellom enheten og kontoen din.</translation>
 <translation id="6831043979455480757">Oversett</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_pl.xtb b/chrome/android/java/strings/translations/android_chrome_strings_pl.xtb
index f48cfe5..fbdfc49 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_pl.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_pl.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Szukaj tej grafiki w <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Dodaj adres</translation>
 <translation id="4816465935029283692">Typy danych</translation>
-<translation id="5098185943924922330">Pomóż nam określić najważniejsze funkcje i ulepszenia, nad którymi powinniśmy pracować, wysyłając do Google przy każdej awarii informacje o plikach, aplikacjach oraz uruchomionych usługach.
-
-        Statystyki użytkowania obejmują np. dane o ustawieniach, kliknięciach przycisków i wykorzystaniu pamięci. Nie zawierają one adresów URL stron internetowych ani żadnych informacji osobistych. Raporty o awariach zawierają informacje systemowe z chwili awarii i mogą obejmować adresy URL stron internetowych lub informacje osobiste w zależności od okoliczności awarii.</translation>
 <translation id="4042870126885713738">Pokazuj podpowiedzi, gdy nie można znaleźć adresu internetowego lub nawiązać połączenia</translation>
 <translation id="8237438615979997762">Dane przechowywane na tym urządzeniu oraz na Twoim koncie Google pozostaną w obu tych miejscach. Jednak nowe dane i przyszłe zmiany nie będą już synchronizowane z kontem.</translation>
 <translation id="6831043979455480757">Tłumacz</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_pt-BR.xtb b/chrome/android/java/strings/translations/android_chrome_strings_pt-BR.xtb
index a602664..390ef105 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_pt-BR.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_pt-BR.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Pesquisar imagem no <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Adicionar endereço</translation>
 <translation id="4816465935029283692">Tipos de dados</translation>
-<translation id="5098185943924922330">Ajude-nos a priorizar os recursos e aprimoramentos nos quais deveríamos trabalhar, enviando informações ao Google sobre os arquivos, aplicativos e serviços que estão sendo executados quando ocorre uma falha.
-
-        As estatísticas de uso incluem informações como preferências, cliques em botões e uso da memória. Elas não incluem URLs de páginas da Web ou qualquer informação pessoal. Relatórios de erros contêm informações do sistema do momento da falha e podem conter URLs de páginas da Web ou informações pessoais, dependendo de o que estava acontecendo no momento da falha.</translation>
 <translation id="4042870126885713738">Mostrar sugestões quando um endereço da Web não for convertido ou uma conexão não puder ser estabelecida</translation>
 <translation id="8237438615979997762">Os dados armazenados neste dispositivo e na sua Conta do Google permanecerão nos dois locais. Entretanto, dados novos ou alterações feitas nos seus dados não serão sincronizados entre eles.</translation>
 <translation id="6831043979455480757">Traduzir</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_pt-PT.xtb b/chrome/android/java/strings/translations/android_chrome_strings_pt-PT.xtb
index 21ad478..c55fd7a 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_pt-PT.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_pt-PT.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Pesquisar a imagem no <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Adicionar endereço</translation>
 <translation id="4816465935029283692">Tipos de dados</translation>
-<translation id="5098185943924922330">Ajude-nos a dar prioridade às funcionalidades e às melhorias nas quais devemos trabalhar ao enviar à Google informações sobre os ficheiros, as aplicações e os serviços em execução sempre que ocorrer uma falha.
-
-        As estatísticas de utilização incluem informações como preferências, cliques em botões e utilização da memória. Estas não incluem URLs de páginas Web nem quaisquer informações pessoais. Os relatórios de falhas contêm informações do sistema no momento em que as falhas ocorreram e podem conter URLs de páginas Web ou informações pessoais, consoante as operações em curso no momento da falha.</translation>
 <translation id="4042870126885713738">Mostrar sugestões quando um endereço Web não responder ou não for possível estabelecer ligação</translation>
 <translation id="8237438615979997762">Os dados armazenados neste dispositivo, bem como os dados armazenados na sua Conta Google, permanecem em ambos os locais. No entanto, os novos dados ou as alterações efetuadas aos dados não são sincronizados entre si.</translation>
 <translation id="6831043979455480757">Traduzir</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ro.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ro.xtb
index 612d72d..d6811299 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ro.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ro.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Căutați imaginea cu <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Adaugă o adresă</translation>
 <translation id="4816465935029283692">Tipuri de date</translation>
-<translation id="5098185943924922330">Trimite la Google informații despre fișierele, aplicațiile și serviciile care rulează când te confrunți cu o blocare, pentru a ne ajuta să stabilim la care funcții și îmbunătățiri ar trebui să lucrăm.
-
-        Statisticile de utilizare includ informații precum preferințele, clicurile pe butoane și utilizarea memoriei. Acestea nu includ adresele URL ale paginilor web sau alte informații personale. Rapoartele de blocare includ informații despre sistem din momentul blocării și pot include adresele URL ale paginilor web sau informații personale, în funcție de ceea ce s-a întâmplat în momentul blocării.</translation>
 <translation id="4042870126885713738">Afișează sugestii atunci când o adresă web nu se rezolvă sau nu poate fi stabilită o conexiune</translation>
 <translation id="8237438615979997762">Datele stocate pe acest dispozitiv, precum și datele stocate în Contul Google se vor păstra în ambele locații. Cu toate acestea, datele noi sau modificările datelor nu se vor sincroniza între aceste locații.</translation>
 <translation id="6831043979455480757">Tradu</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb b/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb
index 6df42be8..4c67894 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_ru.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Найти это изображение в <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Добавить адрес</translation>
 <translation id="4816465935029283692">Типы данных</translation>
-<translation id="5098185943924922330">Расскажите, на какие проблемы нам стоит обратить внимание прежде всего. Для этого отправляйте в Google сведения о файлах, приложениях и сервисах, в работе которых возникли сбои.
-
-        В статистику использования включаются сведения о настройках, нажатиях кнопок и использовании памяти, но не входят URL веб-страниц и личная информация. Отчеты о сбоях содержат системную информацию на момент сбоя, а иногда также URL веб-страниц и личные данные (в зависимости от того, как использовался браузер).</translation>
 <translation id="4042870126885713738">Предлагать альтернативы, если веб-адрес недоступен или с ним не удается установить соединение</translation>
 <translation id="8237438615979997762">Данные, находящиеся на этом устройстве и в аккаунте Google, сохранятся, однако новые данные и вносимые изменения синхронизироваться не будут.</translation>
 <translation id="6831043979455480757">Перевести</translation>
@@ -413,7 +410,7 @@
 <translation id="4056223980640387499">Сепия</translation>
 <translation id="8310344678080805313">Обычные вкладки</translation>
 <translation id="8396312449826231789">Только одобренные сайты</translation>
-<translation id="17513872634828108">Открыть вкладки</translation>
+<translation id="17513872634828108">Открытые вкладки</translation>
 <translation id="411254640334432676">Ошибка при скачивании</translation>
 <translation id="6277522088822131679">Не удалось распечатать страницу. Повторите попытку.</translation>
 <translation id="7634554953375732414">Подключение к веб-сайту не защищено</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sk.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sk.xtb
index c67f0fb..6d5b8bc6 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sk.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sk.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Hľadať obrázok v službe <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Pridať adresu</translation>
 <translation id="4816465935029283692">Typy údajov</translation>
-<translation id="5098185943924922330">Pomôžte nám určiť tie funkcie a zlepšenia, na ktorých by sme mali pracovať. Odosielajte spoločnosti Google informácie o súboroch, aplikáciách a službách spustených pri zlyhaní.
-
-        Štatistiky používania obsahujú informácie, ako sú predvoľby, kliknutia na tlačidlá a využitie pamäte. Nie sú v nich však zahrnuté webové adresy stránok ani osobné informácie. Správy o zlyhaní obsahujú systémové informácie z času, kedy došlo k zlyhaniu. V závislosti od toho, aké aplikácie a služby boli v čase zlyhania spustené, môžu obsahovať webové adresy stránok alebo osobné informácie.</translation>
 <translation id="4042870126885713738">Zobrazte návrhy v prípade, že webovú adresu nie je možné vyhľadať alebo nie je možné nadviazať spojenie</translation>
 <translation id="8237438615979997762">Údaje uložené na tomto zariadení aj údaje uložené v účte Google zostanú na oboch miestach. Nové údaje ani zmeny súčasných údajov sa už však medzi týmito miestami synchronizovať nebudú.</translation>
 <translation id="6831043979455480757">Preložiť</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb
index 8e552d6b..194051a 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sl.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Uporabi <ph name="SEARCH_ENGINE"/> za to sliko</translation>
 <translation id="7764225426217299476">Dodaj naslov</translation>
 <translation id="4816465935029283692">Vrste podatkov</translation>
-<translation id="5098185943924922330">Pomagajte nam izdelati prednostni seznam funkcij in izboljšav, ki naj jih razvijamo, tako da pošiljate Googlu podatke o datotekah, aplikacijah in storitvah, ki se izvajajo, ko pride do zrušitve.
-
-        Statistični podatki o uporabi vključujejo podatke, kot so nastavitve, kliki gumbov in uporaba pomnilnika. Ne vključujejo URL-jev spletnih mest ali kakršnih koli osebnih podatkov. Poročila o zrušitvah vsebujejo podatke o sistemu v trenutku zrušitve in glede na dogajanje v trenutku zrušitve morda vsebujejo tudi URL-je spletnih strani ali osebne podatke.</translation>
 <translation id="4042870126885713738">Pokaži predloge, ko spletnega naslova ni mogoče razrešiti ali povezave ni mogoče vzpostaviti</translation>
 <translation id="8237438615979997762">Podatki, shranjeni v tej napravi, in podatki v Google Računu bodo ostali na obeh mestih, pri čemer novi ali spremenjeni podatki ne bodo sinhronizirani z njima.</translation>
 <translation id="6831043979455480757">Prevedi</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sr.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sr.xtb
index cad07b8..24512689 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sr.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sr.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Потражи ову слику на <ph name="SEARCH_ENGINE"/>-у</translation>
 <translation id="7764225426217299476">Додајте адресу</translation>
 <translation id="4816465935029283692">Типови података</translation>
-<translation id="5098185943924922330">Помозите нам да одредимо приоритет функција и побољшања на којима би требало да радимо тако што ћете слати Google-у информације о датотекама, апликацијама и услугама које сте користили у тренутку отказивања.
-
-        Статистика коришћења обухвата информације попут подешавања, кликова на дугмад и коришћења меморије. Не обухвата URL-ове веб-страница нити личне податке. Извештаји о отказивању садрже информације о систему у тренутку отказивања и могу да садрже URL-ове веб-страница или личне податке, у зависности од тога шта се дешавало у тренутку отказивања.</translation>
 <translation id="4042870126885713738">Приказивање предлога када се веб-адреса не разреши или када није могуће успоставити везу</translation>
 <translation id="8237438615979997762">Подаци сачувани на овом уређају, као и на Google налогу, остаће на оба места. Међутим, нови подаци или промене података неће бити синхронизовани.</translation>
 <translation id="6831043979455480757">Преведи</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sv.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sv.xtb
index 5b64c19..1310f7b7c 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sv.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sv.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Sök på <ph name="SEARCH_ENGINE"/> efter denna bild</translation>
 <translation id="7764225426217299476">Lägg till adress</translation>
 <translation id="4816465935029283692">Datatyper</translation>
-<translation id="5098185943924922330">Hjälp oss att prioritera vilka funktioner och förbättringar vi ska arbeta med genom att skicka information om vilka filer, program och tjänster som körs när en krasch inträffar.
-
-        Användningsstatistiken innehåller information som inställningar, knappklick och minnesanvändning. De innehåller inte webbadresser eller personliga uppgifter. Felrapporter innehåller information om systemet vid tidpunkten för kraschen och kan innehålla webbadresser eller personliga uppgifter beroende på vad som hände vid kraschen.</translation>
 <translation id="4042870126885713738">Visa förslag när det inte går att öppna en webbadress eller upprätta en anslutning</translation>
 <translation id="8237438615979997762">Data som sparats på enheten och data som sparats i Google-kontot finns kvar på båda ställena. Ny data och ändringar som du gör kommer dock inte att synkroniseras dem emellan.</translation>
 <translation id="6831043979455480757">Översätt</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_sw.xtb b/chrome/android/java/strings/translations/android_chrome_strings_sw.xtb
index 1ad586d8..848ab9ae 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_sw.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_sw.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Tafuta picha hii kwenye <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Ongeza anwani</translation>
 <translation id="4816465935029283692">Aina za data</translation>
-<translation id="5098185943924922330">Tusaidie kuweka kipaumbele katika vipengele na maboresho tunayopaswa kushughulikia kwa kuitumia Google maelezo kuhusu faili, programu, na huduma zinazofanya kazi unapokumbwa na hitilafu ya kuacha kufanya kazi.
-
-        Takwimu za matumizi zinajumuisha maelezo kama vile mapendeleo, mibofyo ya vitufe, na matumuzi ya hifadhi. Hazijumuishi URL za ukurasa wa wavuti au maelezo yoyote ya kibinafsi. Ripoti za kuacha kufanya kazi zina maelezo ya mfumo ya wakati wa kuacha kufanya kazi, na zinaweza kuwa na URL za ukurasa wa wavuti au maelezo ya kibinafsi, kutegemea na kilichokuwa kikitendeka wakati wa kuacha kufanya kazi.</translation>
 <translation id="4042870126885713738">Onyesha mapendekezo wakati anwani ya wavuti inaposhindwa kutatuliwa au muunganisho ukiwa hauwezi kufanyika</translation>
 <translation id="8237438615979997762">Data iliyohifadhiwa kwenye kifaa hiki pamoja na data iliyohifadhiwa katika Akaunti yako ya Google itasalia katika sehemu zote mbili. Hata hivyo, data au mabadiliko mapya utakayofanya kwenye data yako hayatasawazishwa.</translation>
 <translation id="6831043979455480757">Tafsiri</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_th.xtb b/chrome/android/java/strings/translations/android_chrome_strings_th.xtb
index 289c4ca0..4c0bef83 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_th.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_th.xtb
@@ -21,10 +21,6 @@
 <translation id="5578795271662203820">ค้นหาภาพนี้ใน <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">เพิ่มที่อยู่</translation>
 <translation id="4816465935029283692">ชนิดข้อมูล</translation>
-<translation id="5098185943924922330">ช่วยเราจัดลำดับความสำคัญของคุณลักษณะและการปรับปรุงที่เราควรทำโดยการส่งข้อมูล
-เกี่ยวกับไฟล์ แอปพลิเคชัน และบริการที่ทำงานอยู่ในขณะที่เกิดการขัดข้องไปยัง Google
-
-        สถิติการใช้งานจะรวมถึงข้อมูลอย่างเช่น ค่ากำหนด การคลิกปุ่ม และการใช้หน่วยความจำ สถิติเหล่านี้ไม่รวม URL ของหน้าเว็บหรือข้อมูลส่วนบุคคล ส่วนรายงานข้อขัดข้องนั้นจะประกอบด้วยข้อมูลระบบในเวลาที่มีการขัดข้อง และอาจประกอบด้วย URL ของหน้าเว็บหรือข้อมูลส่วนบุคคล ซึ่งขึ้นอยู่กับสิ่งที่เกิดขึ้นในขณะที่มีการขัดข้อง</translation>
 <translation id="4042870126885713738">แสดงคำแนะนำเมื่อไม่สามารถระบุที่อยู่เว็บหรือไม่สามารถเชื่อมต่อได้</translation>
 <translation id="8237438615979997762">ข้อมูลที่จัดเก็บไว้ในอุปกรณ์นี้และข้อมูลที่จัดเก็บในบัญชี Google ของคุณจะยังคงอยู่ทั้ง 2 ที่ แต่จะไม่มีการซิงค์ข้อมูลใหม่หรือการเปลี่ยนแปลงที่คุณทำระหว่างที่เก็บข้อมูลทั้ง 2 แห่งนี้</translation>
 <translation id="6831043979455480757">แปลภาษา</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_tr.xtb b/chrome/android/java/strings/translations/android_chrome_strings_tr.xtb
index c23956220..77e2227 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_tr.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_tr.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Bu resmi, <ph name="SEARCH_ENGINE"/> üzerinde ara</translation>
 <translation id="7764225426217299476">Adres ekle</translation>
 <translation id="4816465935029283692">Veri türleri</translation>
-<translation id="5098185943924922330">Bir kilitlenme yaşadığınız her defasında, çalışan dosyalarla, uygulamalarla ve hizmetlerle ilgili bilgileri Google'a göndererek, üzerinde çalışmamız gereken özellikler ve iyileştirmelerle ilgili öncelikleri belirlememize yardım edin.
-
-        Kullanım istatistikleri; tercihler, tıklanan düğmeler ve bellek kullanımı gibi bilgileri içerir. Web sayfası URL'lerini veya hiçbir kişisel bilgiyi içermez. Kilitlenme raporları, kilitlenme sırasında geçerli olan sistem bilgilerini kapsar ve kilitlenme sırasında olanlara bağlı olarak web sayfası URL'lerini veya kişisel bilgilerinizi içerebilir.</translation>
 <translation id="4042870126885713738">Bir web adresi çözümlenemezse veya bağlantı yapılamazsa öneriler göster</translation>
 <translation id="8237438615979997762">Bu cihazda ve Google Hesabınızda depolanan veriler her iki yerde de kalır. Ancak, yeni veriler veya verilerinizde yapacağınız değişiklikler bu ikisi arasında senkronize edilmez.</translation>
 <translation id="6831043979455480757">Çevir</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_uk.xtb b/chrome/android/java/strings/translations/android_chrome_strings_uk.xtb
index 57624ec..c1ca365 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_uk.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_uk.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Шукати зображення в <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Додати адресу</translation>
 <translation id="4816465935029283692">Типи даних</translation>
-<translation id="5098185943924922330">Допоможіть нам визначити, що слід покращити, надсилаючи в Google інформацію про файли, додатки та сервіси, які працювали на момент аварійного завершення роботи.
-
-        Статистика використання містить дані про налаштування, натискання кнопок і використання пам’яті. Вона не включає URL-адреси веб-сторінок або особисту інформацію. Звіти про аварійне завершення роботи містять дані про систему на момент збою та можуть включати URL-адреси веб-сторінок або особисту інформацію – залежно від активності на момент аварійного завершення роботи.</translation>
 <translation id="4042870126885713738">Показувати пропозиції, коли неможливо перейти за веб-адресою чи не вдається встановити з’єднання</translation>
 <translation id="8237438615979997762">Дані, які зберігаються на цьому пристрої й у вашому обліковому записі Google, залишаться в обох місцях. Однак нові або змінені дані не синхронізуватимуться.</translation>
 <translation id="6831043979455480757">Перекласти</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_vi.xtb b/chrome/android/java/strings/translations/android_chrome_strings_vi.xtb
index c3ca46cf..74b215d 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_vi.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_vi.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">Tìm ảnh này trên <ph name="SEARCH_ENGINE"/></translation>
 <translation id="7764225426217299476">Thêm địa chỉ</translation>
 <translation id="4816465935029283692">Loại dữ liệu</translation>
-<translation id="5098185943924922330">Giúp chúng tôi ưu tiên các tính năng và cải tiến mà chúng tôi nên giải quyết bằng cách gửi cho Google thông tin về các tệp, ứng dụng và dịch vụ đang chạy bất cứ khi nào bạn gặp sự cố.
-
-        Số liệu thống kê sử dụng bao gồm thông tin như tùy chọn, lần nhấp nút và mức sử dụng bộ nhớ. Số liệu này không bao gồm URL trang web hoặc bất kỳ thông tin cá nhân nào. Báo cáo sự cố chứa thông tin hệ thống tại thời điểm xảy ra sự cố và có thể bao gồm URL của trang web hoặc thông tin cá nhân, tùy thuộc vào hiện tượng tại thời điểm xảy ra sự cố.</translation>
 <translation id="4042870126885713738">Hiển thị các đề xuất khi địa chỉ web không khắc phục được hoặc kết nối không thể được thực hiện</translation>
 <translation id="8237438615979997762">Dữ liệu đã lưu trên thiết bị này cũng như dữ liệu đã lưu trong tài khoản Google của bạn sẽ vẫn ở cả hai vị trí. Tuy nhiên, dữ liệu mới hoặc các thay đổi mà bạn thực hiện đối với dữ liệu sẽ không được đồng bộ hóa giữa hai vị trí.</translation>
 <translation id="6831043979455480757">Dịch</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb b/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb
index 5810a3f..f66cde0 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_zh-CN.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">在<ph name="SEARCH_ENGINE"/>中搜索此图片</translation>
 <translation id="7764225426217299476">添加地址</translation>
 <translation id="4816465935029283692">数据类型</translation>
-<translation id="5098185943924922330">将发生崩溃时正在运行的文件、应用和服务的相关信息发送给 Google,协助我们确定应优先处理哪些功能和改进方面的事宜。
-
-        使用情况统计信息包含偏好设置、按钮点击次数和内存使用情况之类的信息,但不包含网页网址或任何个人信息。崩溃报告包含发生崩溃时的系统信息,并可能包含网页网址或个人信息,具体取决于发生崩溃时的情况。</translation>
 <translation id="4042870126885713738">无法解析网址或无法建立连接时显示建议</translation>
 <translation id="8237438615979997762">此设备中以及您的 Google 帐户中存储的数据都会保留在原位置。但是,新的数据或您对数据进行的更改将不会在此设备和您的 Google 帐户之间同步。</translation>
 <translation id="6831043979455480757">翻译</translation>
diff --git a/chrome/android/java/strings/translations/android_chrome_strings_zh-TW.xtb b/chrome/android/java/strings/translations/android_chrome_strings_zh-TW.xtb
index b1cd7345..b55e636 100644
--- a/chrome/android/java/strings/translations/android_chrome_strings_zh-TW.xtb
+++ b/chrome/android/java/strings/translations/android_chrome_strings_zh-TW.xtb
@@ -21,9 +21,6 @@
 <translation id="5578795271662203820">透過 <ph name="SEARCH_ENGINE"/> 搜尋這張圖片</translation>
 <translation id="7764225426217299476">新增地址</translation>
 <translation id="4816465935029283692">資料類型</translation>
-<translation id="5098185943924922330">發生當機情形時,如果您將當下正在執行的檔案、應用程式和服務的相關資訊傳送給 Google,即可協助我們優先提供重要的功能與改進項目。
-
-        使用統計資料包括偏好設定、按鈕點擊次數和記憶體使用量等資訊,不含網頁網址或任何個人資訊。當機報告則包括當機時的系統資訊;而且根據當機時發生的狀況,可能會包含網頁網址和個人資訊。</translation>
 <translation id="4042870126885713738">在無法解析網址或建立連線時顯示建議</translation>
 <translation id="8237438615979997762">儲存在這個裝置上和 Google 帳戶中的資料將各自保持原狀,但當您新增資料或變更資料時,兩者之間的資料將不會保持同步。</translation>
 <translation id="6831043979455480757">翻譯</translation>
diff --git a/chrome/android/java_staging/AndroidManifest.xml b/chrome/android/java_staging/AndroidManifest.xml
index d2742d86..17a0d0a 100644
--- a/chrome/android/java_staging/AndroidManifest.xml
+++ b/chrome/android/java_staging/AndroidManifest.xml
@@ -205,7 +205,7 @@
             android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc"
             android:hardwareAccelerated="true">
         </activity>
-        <activity android:name="org.chromium.chrome.browser.hosted.HostedActivity"
+        <activity android:name="org.chromium.chrome.browser.customtabs.CustomTabActivity"
             android:theme="@style/MainTheme"
             android:exported="false"
             android:windowSoftInputMode="adjustResize"
@@ -515,7 +515,7 @@
         <service android:name="org.chromium.chrome.browser.prerender.ChromePrerenderService"
             android:exported="true"
             tools:ignore="ExportedService" />
-        <service android:name="org.chromium.chrome.browser.hosted.ChromeConnectionService"
+        <service android:name="org.chromium.chrome.browser.customtabs.ChromeConnectionService"
              android:exported="{{ 'true' if channel in ['dev', 'canary', 'default'] else 'false' }}"
              tools:ignore="ExportedService">
             <intent-filter>
diff --git a/chrome/android/java_staging/res/layout/hosted_control_container.xml b/chrome/android/java_staging/res/layout/custom_tabs_control_container.xml
similarity index 84%
rename from chrome/android/java_staging/res/layout/hosted_control_container.xml
rename to chrome/android/java_staging/res/layout/custom_tabs_control_container.xml
index b45ef33..87b45c7 100644
--- a/chrome/android/java_staging/res/layout/hosted_control_container.xml
+++ b/chrome/android/java_staging/res/layout/custom_tabs_control_container.xml
@@ -6,7 +6,7 @@
     android:id="@+id/control_container"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:minHeight="@dimen/hosted_control_container_height" >
+    android:minHeight="@dimen/custom_tabs_control_container_height" >
     <view
         class="org.chromium.chrome.browser.toolbar.ToolbarControlContainer$ToolbarViewResourceFrameLayout"
         android:id="@+id/toolbar_container"
@@ -15,14 +15,14 @@
         <include
             android:id="@+id/toolbar"
             android:layout_width="match_parent"
-            android:layout_height="@dimen/hosted_control_container_height"
-            layout="@layout/hosted_toolbar" />
+            android:layout_height="@dimen/custom_tabs_control_container_height"
+            layout="@layout/custom_tabs_toolbar" />
         <ImageView
             android:id="@+id/toolbar_shadow"
             android:src="@drawable/toolbar_shadow"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/hosted_control_container_height"
+            android:layout_marginTop="@dimen/custom_tabs_control_container_height"
             android:scaleType="fitXY"
             android:contentDescription="@null" />
         <ViewStub
@@ -31,7 +31,7 @@
             android:visibility="gone"
             android:layout_marginTop="@dimen/tab_strip_height"
             android:layout_width="match_parent"
-            android:layout_height="@dimen/hosted_control_container_height"
+            android:layout_height="@dimen/custom_tabs_control_container_height"
             android:layout="@layout/find_toolbar" />
         <ViewStub
             android:id="@+id/find_toolbar_tablet_stub"
diff --git a/chrome/android/java_staging/res/layout/hosted_toolbar.xml b/chrome/android/java_staging/res/layout/custom_tabs_toolbar.xml
similarity index 85%
rename from chrome/android/java_staging/res/layout/hosted_toolbar.xml
rename to chrome/android/java_staging/res/layout/custom_tabs_toolbar.xml
index 6c2bd7eb..42b2ad2 100644
--- a/chrome/android/java_staging/res/layout/hosted_toolbar.xml
+++ b/chrome/android/java_staging/res/layout/custom_tabs_toolbar.xml
@@ -3,7 +3,7 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
-<org.chromium.chrome.browser.toolbar.HostedToolbar xmlns:android="http://schemas.android.com/apk/res/android">
+<org.chromium.chrome.browser.toolbar.CustomTabToolbar xmlns:android="http://schemas.android.com/apk/res/android">
     <org.chromium.chrome.browser.widget.TintedImageButton
         android:id="@+id/back_button"
         style="@style/ToolbarButton"
@@ -34,7 +34,7 @@
             android:layout_gravity="top"
             android:maxLines="1"
             android:paddingEnd="@dimen/toolbar_edge_padding"
-            android:textSize="@dimen/hosted_title_text_size"
+            android:textSize="@dimen/custom_tabs_title_text_size"
             android:inputType="none" />
         <org.chromium.chrome.browser.omnibox.UrlBar
             android:id="@+id/url_bar"
@@ -44,16 +44,16 @@
             android:layout_gravity ="bottom"
             android:maxLines="1"
             android:paddingEnd="@dimen/toolbar_edge_padding"
-            android:textSize="@dimen/hosted_url_text_size"
+            android:textSize="@dimen/custom_tabs_url_text_size"
             android:inputType="none" />
     </FrameLayout>
     <ImageButton
         android:id="@+id/action_button"
         style="@style/ToolbarButton"
         android:layout_width="wrap_content"
-        android:maxWidth="@dimen/hosted_toolbar_maxWidth"
-        android:paddingTop="@dimen/hosted_toolbar_vertical_padding"
-        android:paddingBottom="@dimen/hosted_toolbar_vertical_padding"
+        android:maxWidth="@dimen/custom_tabs_toolbar_maxWidth"
+        android:paddingTop="@dimen/custom_tabs_toolbar_vertical_padding"
+        android:paddingBottom="@dimen/custom_tabs_toolbar_vertical_padding"
         android:adjustViewBounds="true"
         android:scaleType="centerInside"
         android:layout_marginEnd="42dp"
@@ -76,4 +76,4 @@
         android:layout_width="match_parent"
         android:layout_height="2dp"
         android:progress="0" />
-</org.chromium.chrome.browser.toolbar.HostedToolbar>
+</org.chromium.chrome.browser.toolbar.CustomTabToolbar>
diff --git a/chrome/android/java_staging/res/menu/hosted_menu.xml b/chrome/android/java_staging/res/menu/custom_tabs_menu.xml
similarity index 100%
rename from chrome/android/java_staging/res/menu/hosted_menu.xml
rename to chrome/android/java_staging/res/menu/custom_tabs_menu.xml
diff --git a/chrome/android/java_staging/res/values-sw600dp/dimens_staging.xml b/chrome/android/java_staging/res/values-sw600dp/dimens_staging.xml
index c5b4617..262b9722 100644
--- a/chrome/android/java_staging/res/values-sw600dp/dimens_staging.xml
+++ b/chrome/android/java_staging/res/values-sw600dp/dimens_staging.xml
@@ -9,7 +9,7 @@
 
     <!-- Full Screen Dimensions -->
     <dimen name="control_container_height">96dp</dimen>
-    <dimen name="hosted_control_container_height">64dp</dimen>
+    <dimen name="custom_tabs_control_container_height">64dp</dimen>
 
     <!-- The combined height of the tab strip and toolbar. -->
     <dimen name="tab_strip_and_toolbar_height">96dp</dimen>
diff --git a/chrome/android/java_staging/res/values/dimens_staging.xml b/chrome/android/java_staging/res/values/dimens_staging.xml
index 63817e2..6124cb11 100644
--- a/chrome/android/java_staging/res/values/dimens_staging.xml
+++ b/chrome/android/java_staging/res/values/dimens_staging.xml
@@ -10,7 +10,7 @@
     <!-- Full Screen Dimensions -->
     <!-- Should match toolbar_height_no_shadow -->
     <dimen name="control_container_height">56dp</dimen>
-    <dimen name="hosted_control_container_height">56dp</dimen>
+    <dimen name="custom_tabs_control_container_height">56dp</dimen>
     <dimen name="webapp_control_container_height">22dp</dimen>
 
     <!-- The combined height of the tab strip and toolbar. -->
@@ -145,12 +145,12 @@
     <dimen name="enhanced_bookmark_list_mode_background_margin">10dp</dimen>
     <dimen name="enhanced_bookmark_drawer_drawable_padding">18dp</dimen>
 
-        <!-- Hosted Mode dimensions -->
-    <dimen name="hosted_toolbar_maxWidth">60dp</dimen>
-    <dimen name="hosted_toolbar_vertical_padding">16dp</dimen>
+        <!-- Custom Tabs dimensions -->
+    <dimen name="custom_tabs_toolbar_maxWidth">60dp</dimen>
+    <dimen name="custom_tabs_toolbar_vertical_padding">16dp</dimen>
     <dimen name="toolbar_icon_height">24dp</dimen>
     <dimen name="min_toolbar_icon_side_padding">6dp</dimen>
-    <dimen name="hosted_url_text_size">12sp</dimen>
-    <dimen name="hosted_title_text_size">16sp</dimen>
+    <dimen name="custom_tabs_url_text_size">12sp</dimen>
+    <dimen name="custom_tabs_title_text_size">16sp</dimen>
 
 </resources>
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeActivity.java
index 21e13f9..84a57b34 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -15,6 +15,7 @@
 import android.os.Build;
 import android.os.Looper;
 import android.os.MessageQueue;
+import android.os.StrictMode;
 import android.os.SystemClock;
 import android.preference.PreferenceManager;
 import android.provider.Settings;
@@ -96,8 +97,8 @@
 
     private TabModelSelector mTabModelSelector;
     private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
-    private ChromeTabCreator mRegularTabCreator;
-    private ChromeTabCreator mIncognitoTabCreator;
+    private TabCreatorManager.TabCreator mRegularTabCreator;
+    private TabCreatorManager.TabCreator mIncognitoTabCreator;
     private TabContentManager mTabContentManager;
     private UmaSessionStats mUmaSessionStats;
     private ContextReporter mContextReporter;
@@ -176,7 +177,7 @@
     }
 
     @Override
-    public ChromeTabCreator getTabCreator(boolean incognito) {
+    public TabCreatorManager.TabCreator getTabCreator(boolean incognito) {
         return incognito ? mIncognitoTabCreator : mRegularTabCreator;
     }
 
@@ -184,8 +185,8 @@
      * Sets the {@link ChromeTabCreator}s owned by this {@link ChromeActivity}.
      * @param regularTabCreator A {@link ChromeTabCreator} instance.
      */
-    public void setTabCreators(ChromeTabCreator regularTabCreator,
-            ChromeTabCreator incognitoTabCreator) {
+    public void setTabCreators(TabCreatorManager.TabCreator regularTabCreator,
+            TabCreatorManager.TabCreator incognitoTabCreator) {
         mRegularTabCreator = regularTabCreator;
         mIncognitoTabCreator = incognitoTabCreator;
     }
@@ -194,7 +195,7 @@
      * Convenience method that returns a tab creator for the currently selected {@link TabModel}.
      * @return A tab creator for the currently selected {@link TabModel}.
      */
-    public ChromeTabCreator getCurrentTabCreator() {
+    public TabCreatorManager.TabCreator getCurrentTabCreator() {
         return getTabCreator(getTabModelSelector().isIncognitoSelected());
     }
 
@@ -284,8 +285,14 @@
         // Low end device UI should be allowed only after a fresh install or when the data has
         // been cleared. This must happen before anyone calls SysUtils.isLowEndDevice() or
         // SysUtils.isLowEndDevice() will always return the wrong value.
-        if (OmahaClient.isFreshInstallOrDataHasBeenCleared(this)) {
-            ChromePreferenceManager.getInstance(this).setAllowLowEndDeviceUi();
+        // Temporarily allowing disk access. TODO: Fix. See http://crbug.com/473352
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        try {
+            if (OmahaClient.isFreshInstallOrDataHasBeenCleared(this)) {
+                ChromePreferenceManager.getInstance(this).setAllowLowEndDeviceUi();
+            }
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
         }
 
         if (!ChromePreferenceManager.getInstance(this).getAllowLowEndDeviceUi()) {
@@ -737,6 +744,7 @@
         });
 
         getChromeApplication().getUpdateInfoBarHelper().checkForUpdateOnBackgroundThread(this);
+
         removeSnapshotDatabase();
     }
 
@@ -779,10 +787,17 @@
      * in Chrome M41.
      */
     private void removeSnapshotDatabase() {
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
-        if (!prefs.getBoolean(SNAPSHOT_DATABASE_REMOVED, false)) {
-            deleteDatabase(SNAPSHOT_DATABASE_NAME);
-            prefs.edit().putBoolean(SNAPSHOT_DATABASE_REMOVED, true).apply();
+        // Temporarily allowing disk access. TODO: Fix. See http://crbug.com/493181
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        StrictMode.allowThreadDiskWrites();
+        try {
+            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+            if (!prefs.getBoolean(SNAPSHOT_DATABASE_REMOVED, false)) {
+                deleteDatabase(SNAPSHOT_DATABASE_NAME);
+                prefs.edit().putBoolean(SNAPSHOT_DATABASE_REMOVED, true).apply();
+            }
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
         }
     }
 
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 35f4d1d..1234a93 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -74,7 +74,9 @@
 import org.chromium.chrome.browser.snackbar.undo.UndoBarPopupController;
 import org.chromium.chrome.browser.sync.SyncController;
 import org.chromium.chrome.browser.tab.ChromeTab;
+import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager.TabCreator;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModelObserver;
@@ -343,6 +345,20 @@
         }
     }
 
+    @Override
+    public ChromeTabCreator getTabCreator(boolean incognito) {
+        TabCreator tabCreator = super.getTabCreator(incognito);
+        assert tabCreator instanceof ChromeTabCreator;
+        return (ChromeTabCreator) tabCreator;
+    }
+
+    @Override
+    public ChromeTabCreator getCurrentTabCreator() {
+        TabCreator tabCreator = super.getCurrentTabCreator();
+        assert tabCreator instanceof ChromeTabCreator;
+        return (ChromeTabCreator) tabCreator;
+    }
+
     private void handleDebugIntent(Intent intent) {
         if (ACTION_CLOSE_TABS.equals(intent.getAction())) {
             getTabModelSelector().closeAllTabs();
@@ -869,7 +885,7 @@
             private boolean mIsFirstPageLoadStart = true;
 
             @Override
-            public void onPageLoadStarted(Tab tab) {
+            public void onPageLoadStarted(Tab tab, String url) {
                 // Discard startup navigation measurements when the user interfered and started the
                 // 2nd navigation (in activity lifetime) in parallel.
                 if (!mIsFirstPageLoadStart) {
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java
index 342e5d1..9b9e7c59 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java
@@ -55,7 +55,7 @@
 import org.chromium.chrome.browser.snackbar.LoFiBarPopupController;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarManageable;
-import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager.TabCreator;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
@@ -219,7 +219,9 @@
                     boolean isNavigationToDifferentPage, boolean isFragmentNavigation,
                     int statusCode) {
                 if (!tab.isNativePage()
-                        && DataReductionProxySettings.getInstance().isLoFiEnabled()) {
+                        && DataReductionProxySettings.getInstance().wasLoFiModeActiveOnMainFrame()
+                        && DataReductionProxySettings.getInstance().canUseDataReductionProxy(
+                                url)) {
                     mLoFiBarPopupController.showLoFiBar(tab);
                 }
             }
@@ -559,7 +561,7 @@
         Tab currentTab = getActivityTab();
         if (currentTab == null) return false;
 
-        ChromeTabCreator tabCreator = getTabCreator(currentTab.isIncognito());
+        TabCreator tabCreator = getTabCreator(currentTab.isIncognito());
         if (tabCreator == null) return false;
 
         tabCreator.createTabWithWebContents(searchContentViewCore.getWebContents(),
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/CustomSelectionActionModeCallback.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/CustomSelectionActionModeCallback.java
index d1cf7f8..f226cd5 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/CustomSelectionActionModeCallback.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/CustomSelectionActionModeCallback.java
@@ -8,11 +8,19 @@
 import android.view.Menu;
 import android.view.MenuItem;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
 /**
  * A class that represents a custom ActionMode.Callback.
  */
 public class CustomSelectionActionModeCallback implements ActionMode.Callback {
 
+    private static boolean sInitializedTypeMethods;
+    private static Method sGetTypeMethod;
+    private static int sTypeFloating;
+
     private ContextualMenuBar mContextualMenuBar;
 
     /**
@@ -29,11 +37,13 @@
 
     @Override
     public void onDestroyActionMode(ActionMode mode) {
+        if (isFloatingActionMode(mode)) return;
         mContextualMenuBar.hideControls();
     }
 
     @Override
     public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+        if (isFloatingActionMode(mode)) return true;
         mContextualMenuBar.showControls();
         return true;
     }
@@ -42,4 +52,59 @@
     public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
         return false;
     }
+
+    // TODO(tedchoc): Delete this method and replace with just getType() when a public M SDK is
+    //                available.
+    private static boolean isFloatingActionMode(ActionMode mode) {
+        initializeGetTypeMethods();
+
+        if (sGetTypeMethod == null) return false;
+
+        Object retVal = null;
+        try {
+            retVal = sGetTypeMethod.invoke(mode);
+        } catch (IllegalAccessException e) {
+            return false;
+        } catch (IllegalArgumentException e) {
+            return false;
+        } catch (InvocationTargetException e) {
+            return false;
+        }
+        if (!(retVal instanceof Integer)) return false;
+
+        return ((Integer) retVal).intValue() == sTypeFloating;
+    }
+
+    private static void initializeGetTypeMethods() {
+        if (sInitializedTypeMethods) return;
+        sInitializedTypeMethods = true;
+
+        Method getType = null;
+        int typeFloating = -1;
+        try {
+            getType = ActionMode.class.getMethod("getType");
+        } catch (NoSuchMethodException e) {
+            return;
+        }
+
+        try {
+            Field field = ActionMode.class.getField("TYPE_FLOATING");
+            Object value = field.get(null);
+
+            if (value instanceof Integer) {
+                typeFloating = (Integer) value;
+            } else {
+                return;
+            }
+        } catch (NoSuchFieldException e) {
+            return;
+        } catch (IllegalAccessException e) {
+            return;
+        } catch (IllegalArgumentException e) {
+            return;
+        }
+
+        sGetTypeMethod = getType;
+        sTypeFloating = typeFloating;
+    }
 }
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/KeyboardShortcuts.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/KeyboardShortcuts.java
index 3bc7fb2..5da1c41 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/KeyboardShortcuts.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/KeyboardShortcuts.java
@@ -9,7 +9,7 @@
 import com.google.android.apps.chrome.R;
 
 import org.chromium.base.annotations.SuppressFBWarnings;
-import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager.TabCreator;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
@@ -138,7 +138,7 @@
                 if (currentTab != null && isCurrentTabVisible) {
                     currentTab.loadUrl(new LoadUrlParams(url, PageTransition.AUTO_BOOKMARK));
                 } else {
-                    ChromeTabCreator tabCreator = activity.getCurrentTabCreator();
+                    TabCreator tabCreator = activity.getCurrentTabCreator();
                     if (tabCreator != null) {
                         tabCreator.launchUrl(url, TabLaunchType.FROM_KEYBOARD);
                     }
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
index 6874e55..0e06cd1 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
@@ -265,7 +265,7 @@
             }
 
             @Override
-            public void onPageLoadStarted(Tab tab) {
+            public void onPageLoadStarted(Tab tab, String url) {
                 tabPageLoadStarted(tab.getId(), tab.isIncognito());
             }
 
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index 4f4a1cb..5d4bdd3 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -497,7 +497,7 @@
             // the user activates a Voice Search.
             nativeGatherSurroundingText(mNativeContextualSearchManagerPtr,
                     mSelectionController.getSelectedText(), NEVER_USE_RESOLVED_SEARCH_TERM,
-                    getBaseContentView());
+                    getBaseContentView(), mPolicy.maySendBasePageUrl());
         }
 
         mWereSearchResultsSeen = false;
@@ -524,7 +524,8 @@
         ContentViewCore baseContentView = getBaseContentView();
         if (baseContentView != null) {
             nativeStartSearchTermResolutionRequest(mNativeContextualSearchManagerPtr, selection,
-                    true, getBaseContentView());
+                    ALWAYS_USE_RESOLVED_SEARCH_TERM, getBaseContentView(),
+                    mPolicy.maySendBasePageUrl());
         }
     }
 
@@ -558,8 +559,8 @@
         // Saved in the case a search needs to be made after first run.
         if (mSelectionController.getSelectionType() == SelectionType.TAP) {
             nativeGatherSurroundingText(mNativeContextualSearchManagerPtr,
-                    mSelectionController.getSelectedText(),
-                    ALWAYS_USE_RESOLVED_SEARCH_TERM, getBaseContentView());
+                    mSelectionController.getSelectedText(), ALWAYS_USE_RESOLVED_SEARCH_TERM,
+                    getBaseContentView(), mPolicy.maySendBasePageUrl());
         }
     }
 
@@ -604,7 +605,7 @@
 
         mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(selector) {
             @Override
-            public void onPageLoadStarted(Tab tab) {
+            public void onPageLoadStarted(Tab tab, String url) {
                 hideContextualSearch(StateChangeReason.UNKNOWN);
                 mDidBasePageLoadJustStart = true;
             }
@@ -1354,12 +1355,12 @@
 
     private native long nativeInit();
     private native void nativeDestroy(long nativeContextualSearchManager);
-    private native void nativeStartSearchTermResolutionRequest(
-            long nativeContextualSearchManager, String selection, boolean useResolvedSearchTerm,
-            ContentViewCore baseContentViewCore);
-    private native void nativeGatherSurroundingText(
-            long nativeContextualSearchManager, String selection, boolean useResolvedSearchTerm,
-            ContentViewCore baseContentViewCore);
+    private native void nativeStartSearchTermResolutionRequest(long nativeContextualSearchManager,
+            String selection, boolean useResolvedSearchTerm, ContentViewCore baseContentViewCore,
+            boolean maySendBasePageUrl);
+    private native void nativeGatherSurroundingText(long nativeContextualSearchManager,
+            String selection, boolean useResolvedSearchTerm, ContentViewCore baseContentViewCore,
+            boolean maySendBasePageUrl);
     private native void nativeContinueSearchTermResolutionRequest(
             long nativeContextualSearchManager);
     private native void nativeRemoveLastSearchVisit(
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
index 17f8ec61..39298e3 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
@@ -264,6 +264,19 @@
         }
     }
 
+    /**
+     * Whether sending the URL of the base page to the server may be done for policy reasons.
+     * NOTE: There may be additional privacy reasons why the base page URL should not be sent.
+     * TODO(donnd): Update this API to definitively determine if it's OK to send the URL,
+     * by merging the checks in the native contextual_search_delegate here.
+     * @return {@code true} if the URL may be sent for policy reasons.
+     *         Note that a return value of {@code true} may still require additional checks
+     *         to see if all privacy-related conditions are met to send the base page URL.
+     */
+    boolean maySendBasePageUrl() {
+        return !isUserUndecided();
+    }
+
     // --------------------------------------------------------------------------------------------
     // Testing support.
     // --------------------------------------------------------------------------------------------
@@ -314,16 +327,6 @@
     }
 
     // --------------------------------------------------------------------------------------------
-    // Persistent "promo opens" counter.
-    // --------------------------------------------------------------------------------------------
-
-    /**
-     * Updates a persistent counter of how many times the promo was opened.
-     */
-    private void incrementPromoOpenedCount() {
-    }
-
-    // --------------------------------------------------------------------------------------------
     // Private helpers.
     // --------------------------------------------------------------------------------------------
 
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java
index 4976125..d438eb0 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTabHelper.java
@@ -55,7 +55,7 @@
     }
 
     @Override
-    public void onPageLoadStarted(Tab tab) {
+    public void onPageLoadStarted(Tab tab, String url) {
         if (tab.getContentViewCore() == null) {
             // Nothing to do yet.
             return;
@@ -181,4 +181,4 @@
 
     private native long nativeInit(Profile profile);
     private native void nativeDestroy(long nativeContextualSearchTabHelper);
-}
\ No newline at end of file
+}
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ChromeBrowserConnection.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ChromeBrowserConnection.java
new file mode 100644
index 0000000..0857518c
--- /dev/null
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ChromeBrowserConnection.java
@@ -0,0 +1,532 @@
+// 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.customtabs;
+
+import android.annotation.SuppressLint;
+import android.app.ActivityManager;
+import android.app.Application;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.net.ConnectivityManager;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.LongSparseArray;
+import android.util.SparseArray;
+import android.view.WindowManager;
+
+import com.google.android.apps.chrome.R;
+
+import org.chromium.base.Log;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.annotations.SuppressFBWarnings;
+import org.chromium.base.library_loader.ProcessInitException;
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.chrome.browser.ChromiumApplication;
+import org.chromium.chrome.browser.WarmupManager;
+import org.chromium.chrome.browser.prerender.ExternalPrerenderHandler;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.content.browser.ChildProcessLauncher;
+import org.chromium.content_public.browser.WebContents;
+
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Implementation of the IBrowserConnectionService interface.
+ */
+class ChromeBrowserConnection extends IBrowserConnectionService.Stub {
+    private static final String TAG = Log.makeTag("ChromeConnection");
+    private static final long RESULT_OK = 0;
+    private static final long RESULT_ERROR = -1;
+    private static final String KEY_CUSTOM_TABS_REFERRER = "android.support.CUSTOM_TABS:referrer";
+
+    // Values for the "CustomTabs.PredictionStatus" UMA histogram. Append-only.
+    private static final int NO_PREDICTION = 0;
+    private static final int GOOD_PREDICTION = 1;
+    private static final int BAD_PREDICTION = 2;
+    private static final int PREDICTION_STATUS_COUNT = 3;
+
+    private static final Object sConstructionLock = new Object();
+    private static ChromeBrowserConnection sInstance;
+
+    private static final class PrerenderedUrlParams {
+        public final long mSessionId;
+        public final WebContents mWebContents;
+        public final String mUrl;
+        public final Bundle mExtras;
+
+        PrerenderedUrlParams(long sessionId, WebContents webContents, String url, Bundle extras) {
+            mSessionId = sessionId;
+            mWebContents = webContents;
+            mUrl = url;
+            mExtras = extras;
+        }
+    }
+
+    private final Application mApplication;
+    private final AtomicBoolean mWarmupHasBeenCalled;
+    private ExternalPrerenderHandler mExternalPrerenderHandler;
+    private PrerenderedUrlParams mPrerender;
+
+    /** Per-sessionId values. */
+    private static class SessionParams {
+        public final int mUid;
+        private ServiceConnection mServiceConnection;
+        private String mPredictedUrl;
+        private long mLastMayLaunchUrlTimestamp;
+
+        public SessionParams(int uid) {
+            mUid = uid;
+            mServiceConnection = null;
+            mPredictedUrl = null;
+            mLastMayLaunchUrlTimestamp = 0;
+        }
+
+        public ServiceConnection getServiceConnection() {
+            return mServiceConnection;
+        }
+
+        public void setServiceConnection(ServiceConnection serviceConnection) {
+            mServiceConnection = serviceConnection;
+        }
+
+        public void setPredictionMetrics(String predictedUrl, long lastMayLaunchUrlTimestamp) {
+            mPredictedUrl = predictedUrl;
+            mLastMayLaunchUrlTimestamp = lastMayLaunchUrlTimestamp;
+        }
+
+        public String getPredictedUrl() {
+            return mPredictedUrl;
+        }
+
+        public long getLastMayLaunchUrlTimestamp() {
+            return mLastMayLaunchUrlTimestamp;
+        }
+    }
+
+    private final Object mLock;
+    private final SparseArray<IBrowserConnectionCallback> mUidToCallback;
+    private final LongSparseArray<SessionParams> mSessionParams;
+
+    private ChromeBrowserConnection(Application application) {
+        super();
+        mApplication = application;
+        mWarmupHasBeenCalled = new AtomicBoolean();
+        mLock = new Object();
+        mUidToCallback = new SparseArray<IBrowserConnectionCallback>();
+        mSessionParams = new LongSparseArray<SessionParams>();
+    }
+
+    /**
+     * @return The unique instance of ChromeBrowserConnection.
+     */
+    public static ChromeBrowserConnection getInstance(Application application) {
+        synchronized (sConstructionLock) {
+            if (sInstance == null) sInstance = new ChromeBrowserConnection(application);
+        }
+        return sInstance;
+    }
+
+    @Override
+    public long finishSetup(IBrowserConnectionCallback callback) {
+        if (callback == null) return RESULT_ERROR;
+        final int uid = Binder.getCallingUid();
+        synchronized (mLock) {
+            if (mUidToCallback.get(uid) != null) return RESULT_ERROR;
+            try {
+                callback.asBinder().linkToDeath(new IBinder.DeathRecipient() {
+                    @Override
+                    public void binderDied() {
+                        synchronized (mLock) {
+                            cleanupAlreadyLocked(uid);
+                        }
+                    }
+                }, 0);
+            } catch (RemoteException e) {
+                // The return code doesn't matter, because this executes when
+                // the caller has died.
+                return RESULT_ERROR;
+            }
+            mUidToCallback.put(uid, callback);
+        }
+        return RESULT_OK;
+    }
+
+    @Override
+    public long warmup(long flags) {
+        // Here and in mayLaunchUrl(), don't do expensive work for background applications.
+        if (!isUidForeground(Binder.getCallingUid())) return RESULT_ERROR;
+        if (!mWarmupHasBeenCalled.compareAndSet(false, true)) return RESULT_OK;
+        // The call is non-blocking and this must execute on the UI thread, post a task.
+        ThreadUtils.postOnUiThread(new Runnable() {
+            @Override
+            @SuppressFBWarnings("DM_EXIT")
+            public void run() {
+                try {
+                    // TODO(lizeb): Warm up more of the browser.
+                    ChromiumApplication app = (ChromiumApplication) mApplication;
+                    app.startBrowserProcessesAndLoadLibrariesSync(
+                            app.getApplicationContext(), true);
+                    final Context context = app.getApplicationContext();
+                    new AsyncTask<Void, Void, Void>() {
+                        @Override
+                        protected Void doInBackground(Void... params) {
+                            ChildProcessLauncher.warmUp(context);
+                            return null;
+                        }
+                    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+                } catch (ProcessInitException e) {
+                    Log.e(TAG, "ProcessInitException while starting the browser process.");
+                    // Cannot do anything without the native library, and cannot show a
+                    // dialog to the user.
+                    System.exit(-1);
+                }
+            }
+        });
+        return RESULT_OK;
+    }
+
+    @Override
+    @SuppressLint("TrulyRandom") // TODO(lizeb): Figure out whether using SecureRandom is OK.
+    public long newSession() {
+        synchronized (mLock) {
+            long sessionId;
+            SecureRandom randomSource = new SecureRandom();
+            do {
+                sessionId = randomSource.nextLong();
+                // Because Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE.
+                if (sessionId == Long.MIN_VALUE) continue;
+                sessionId = Math.abs(sessionId);
+            } while (sessionId == 0 || mSessionParams.get(sessionId) != null);
+            mSessionParams.put(sessionId, new SessionParams(Binder.getCallingUid()));
+            return sessionId;
+        }
+    }
+
+    @Override
+    public long mayLaunchUrl(final long sessionId, final String url, final Bundle extras,
+            List<Bundle> otherLikelyBundles) {
+        int uid = Binder.getCallingUid();
+        // Don't do anything for unknown schemes. Not having a scheme is
+        // allowed, as we allow "www.example.com".
+        String scheme = Uri.parse(url).normalizeScheme().getScheme();
+        if (scheme != null && !scheme.equals("http") && !scheme.equals("https")) {
+            return RESULT_ERROR;
+        }
+        if (!isUidForeground(uid)) return RESULT_ERROR;
+        synchronized (mLock) {
+            SessionParams sessionParams = mSessionParams.get(sessionId);
+            if (sessionParams == null || sessionParams.mUid != uid) return RESULT_ERROR;
+            sessionParams.setPredictionMetrics(url, SystemClock.elapsedRealtime());
+        }
+        ThreadUtils.postOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (!TextUtils.isEmpty(url)) {
+                    WarmupManager.getInstance().maybePrefetchDnsForUrlInBackground(
+                            mApplication.getApplicationContext(), url);
+                }
+                // Calling with a null or empty url cancels a current prerender.
+                prerenderUrl(sessionId, url, extras);
+            }
+        });
+        return sessionId;
+    }
+
+    /**
+     * Registers a launch of a |url| for a given |sessionId|.
+     *
+     * This is used for accounting.
+     */
+    void registerLaunch(long sessionId, String url) {
+        int outcome;
+        long elapsedTimeMs = -1;
+        synchronized (mLock) {
+            SessionParams sessionParams = mSessionParams.get(sessionId);
+            if (sessionParams == null) {
+                outcome = NO_PREDICTION;
+            } else {
+                String predictedUrl = sessionParams.getPredictedUrl();
+                outcome = predictedUrl == null ? NO_PREDICTION
+                        : predictedUrl.equals(url) ? GOOD_PREDICTION : BAD_PREDICTION;
+                elapsedTimeMs = SystemClock.elapsedRealtime()
+                        - sessionParams.getLastMayLaunchUrlTimestamp();
+                sessionParams.setPredictionMetrics(null, 0);
+            }
+        }
+        RecordHistogram.recordEnumeratedHistogram(
+                "CustomTabs.PredictionStatus", outcome, PREDICTION_STATUS_COUNT);
+        if (outcome == GOOD_PREDICTION) {
+            RecordHistogram.recordCustomTimesHistogram("CustomTabs.PredictionToLaunch",
+                    elapsedTimeMs, 1, TimeUnit.MINUTES.toMillis(3), TimeUnit.MILLISECONDS, 100);
+        }
+    }
+
+    /**
+     * Transfers a prerendered WebContents if one exists.
+     *
+     * This resets the internal WebContents; a subsequent call to this method
+     * returns null. Must be called from the UI thread.
+     * If a prerender exists for a different URL with the same sessionId, then
+     * this is treated as a mispredict from the client application, and cancels
+     * the previous prerender. This is done to avoid keeping resources laying
+     * around for too long, but is subject to a race condition, as the following
+     * scenario is possible:
+     * The application calls:
+     * 1. mayLaunchUrl(url1) <- IPC
+     * 2. loadUrl(url2) <- Intent
+     * 3. mayLaunchUrl(url3) <- IPC
+     * If the IPC for url3 arrives before the intent for url2, then this methods
+     * cancels the prerender for url3, which is unexpected. On the other
+     * hand, not cancelling the previous prerender leads to wasted resources, as
+     * a WebContents is lingering. This can be solved by requiring applications
+     * to call mayLaunchUrl(null) to cancel a current prerender before 2, that
+     * is for a mispredict.
+     *
+     * @param sessionId The session ID, returned by {@link newSession}.
+     * @param url The URL the WebContents is for.
+     * @param extras from the intent.
+     * @return The prerendered WebContents, or null.
+     */
+    WebContents takePrerenderedUrl(long sessionId, String url, Bundle extras) {
+        ThreadUtils.assertOnUiThread();
+        if (mPrerender == null || mPrerender.mSessionId != sessionId) return null;
+        WebContents webContents = mPrerender.mWebContents;
+        String prerenderedUrl = mPrerender.mUrl;
+        mPrerender = null;
+        // TODO(lizeb): Referrer
+        if (TextUtils.equals(prerenderedUrl, url)) return webContents;
+        mExternalPrerenderHandler.cancelCurrentPrerender();
+        webContents.destroy();
+        return null;
+    }
+
+    private IBrowserConnectionCallback getCallbackForSessionIdAlreadyLocked(long sessionId) {
+        SessionParams sessionParams = mSessionParams.get(sessionId);
+        if (sessionParams == null) return null;
+        return mUidToCallback.get(sessionParams.mUid);
+    }
+
+    /**
+     * Notifies the application that a page load has started.
+     *
+     * Delivers the {@link IBrowserConnectionCallback#onUserNavigationStarted}
+     * callback to the aplication.
+     *
+     * @param sessionId The session ID.
+     * @param url The URL the tab is navigating to.
+     * @return true for success.
+     */
+    boolean notifyPageLoadStarted(long sessionId, String url) {
+        synchronized (mLock) {
+            IBrowserConnectionCallback cb = getCallbackForSessionIdAlreadyLocked(sessionId);
+            if (cb == null) return false;
+            try {
+                cb.onUserNavigationStarted(sessionId, url, null);
+            } catch (RemoteException e) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Notifies the application that a page load has finished.
+     *
+     * Delivers the {@link IBrowserConnectionCallback#onUserNavigationFinished}
+     * callback to the aplication.
+     *
+     * @param sessionId The session ID.
+     * @param url The URL the tab has navigated to.
+     * @return true for success.
+     */
+    boolean notifyPageLoadFinished(long sessionId, String url) {
+        synchronized (mLock) {
+            IBrowserConnectionCallback cb = getCallbackForSessionIdAlreadyLocked(sessionId);
+            if (cb == null) return false;
+            try {
+                cb.onUserNavigationFinished(sessionId, url, null);
+            } catch (RemoteException e) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Keeps the application linked with sessionId alive.
+     *
+     * The application is kept alive (that is, raised to at least the current
+     * process priority level) until {@link dontKeepAliveForSessionId()} is
+     * called.
+     *
+     * @param sessionId Session ID provided in the intent.
+     * @param intent Intent describing the service to bind to.
+     * @return true for success.
+     */
+    boolean keepAliveForSessionId(long sessionId, Intent intent) {
+        // When an application is bound to a service, its priority is raised to
+        // be at least equal to the application's one. This binds to a dummy
+        // service (no calls to this service are made).
+        if (intent == null || intent.getComponent() == null) return false;
+        SessionParams sessionParams;
+        synchronized (mLock) {
+            sessionParams = mSessionParams.get(sessionId);
+            if (sessionParams == null) return false;
+        }
+        String packageName = intent.getComponent().getPackageName();
+        PackageManager pm = mApplication.getApplicationContext().getPackageManager();
+        // Only binds to the application associated to this session ID.
+        int uid = sessionParams.mUid;
+        if (!Arrays.asList(pm.getPackagesForUid(uid)).contains(packageName)) return false;
+        Intent serviceIntent = new Intent().setComponent(intent.getComponent());
+        // This ServiceConnection doesn't handle disconnects. This is on
+        // purpose, as it occurs when the remote process has died. Since the
+        // only use of this connection is to keep the application alive,
+        // re-connecting would just re-create the process, but the application
+        // state has been lost at that point, the callbacks invalidated, etc.
+        ServiceConnection connection = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {}
+            @Override
+            public void onServiceDisconnected(ComponentName name) {}
+        };
+        boolean ok;
+        try {
+            ok = mApplication.getApplicationContext().bindService(
+                    serviceIntent, connection, Context.BIND_AUTO_CREATE);
+        } catch (SecurityException e) {
+            return false;
+        }
+        if (ok) sessionParams.setServiceConnection(connection);
+        return ok;
+    }
+
+    /**
+     * Lets the lifetime of the process linked to a given sessionId be managed normally.
+     *
+     * Without a matching call to {@link keepAliveForSessionId}, this is a no-op.
+     *
+     * @param sessionId Session ID, as provided to {@link keepAliveForSessionId}.
+     */
+    void dontKeepAliveForSessionId(long sessionId) {
+        SessionParams sessionParams;
+        synchronized (mLock) {
+            sessionParams = mSessionParams.get(sessionId);
+        }
+        if (sessionParams == null || sessionParams.getServiceConnection() == null) return;
+        ServiceConnection serviceConnection = sessionParams.getServiceConnection();
+        sessionParams.setServiceConnection(null);
+        mApplication.getApplicationContext().unbindService(serviceConnection);
+    }
+
+    /**
+     * @return true iff the UID is associated with a process having a foreground importance.
+     */
+    private boolean isUidForeground(int uid) {
+        ActivityManager am =
+                (ActivityManager) mApplication.getSystemService(Context.ACTIVITY_SERVICE);
+        List<ActivityManager.RunningAppProcessInfo> running = am.getRunningAppProcesses();
+        for (ActivityManager.RunningAppProcessInfo rpi : running) {
+            boolean isForeground =
+                    rpi.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+            if (rpi.uid == uid && isForeground) return true;
+        }
+        return false;
+    }
+
+    /**
+     * Called when a remote client has died.
+     */
+    private void cleanupAlreadyLocked(int uid) {
+        List<Long> keysToRemove = new ArrayList<Long>();
+        // TODO(lizeb): If iterating through all the session IDs is too costly,
+        // use two mappings.
+        for (int i = 0; i < mSessionParams.size(); i++) {
+            if (mSessionParams.valueAt(i).mUid == uid) keysToRemove.add(mSessionParams.keyAt(i));
+        }
+        for (Long sessionId : keysToRemove) {
+            mSessionParams.remove(sessionId);
+        }
+        mUidToCallback.remove(uid);
+    }
+
+    private boolean mayPrerender() {
+        ConnectivityManager cm =
+                (ConnectivityManager) mApplication.getApplicationContext().getSystemService(
+                        Context.CONNECTIVITY_SERVICE);
+        return !cm.isActiveNetworkMetered();
+    }
+
+    private void prerenderUrl(long sessionId, String url, Bundle extras) {
+        ThreadUtils.assertOnUiThread();
+        // TODO(lizeb): Prerendering through ChromePrerenderService is
+        // incompatible with prerendering through this service. Remove this
+        // limitation, or remove ChromePrerenderService.
+        WarmupManager.getInstance().disallowPrerendering();
+
+        if (!mayPrerender()) return;
+        if (!mWarmupHasBeenCalled.get()) return;
+        // Last one wins and cancels the previous prerender.
+        if (mPrerender != null) {
+            mExternalPrerenderHandler.cancelCurrentPrerender();
+            mPrerender.mWebContents.destroy();
+            mPrerender = null;
+        }
+        if (TextUtils.isEmpty(url)) return;
+        if (mExternalPrerenderHandler == null) {
+            mExternalPrerenderHandler = new ExternalPrerenderHandler();
+        }
+        Point contentSize = estimateContentSize();
+        String referrer = "";
+        if (extras != null) referrer = extras.getString(KEY_CUSTOM_TABS_REFERRER, "");
+        WebContents webContents = mExternalPrerenderHandler.addPrerender(
+                Profile.getLastUsedProfile(), url, referrer, contentSize.x, contentSize.y);
+        mPrerender = new PrerenderedUrlParams(sessionId, webContents, url, extras);
+    }
+
+    /**
+     * Provides an estimate of the contents size.
+     *
+     * The estimate is likely to be incorrect. This is not a problem, as the aim
+     * is to avoid getting a different layout and resources than needed at
+     * render time.
+     */
+    private Point estimateContentSize() {
+        // The size is estimated as:
+        // X = screenSizeX
+        // Y = screenSizeY - top bar - bottom bar - custom tabs bar
+        Point screenSize = new Point();
+        WindowManager wm = (WindowManager) mApplication.getSystemService(Context.WINDOW_SERVICE);
+        wm.getDefaultDisplay().getSize(screenSize);
+        Resources resources = mApplication.getResources();
+        int statusBarId = resources.getIdentifier("status_bar_height", "dimen", "android");
+        int navigationBarId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
+        try {
+            screenSize.y -=
+                    resources.getDimensionPixelSize(R.dimen.custom_tabs_control_container_height);
+            screenSize.y -= resources.getDimensionPixelSize(statusBarId);
+            screenSize.y -= resources.getDimensionPixelSize(navigationBarId);
+        } catch (Resources.NotFoundException e) {
+            // Nothing, this is just a best effort estimate.
+        }
+        return screenSize;
+    }
+}
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/ChromeConnectionService.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ChromeConnectionService.java
similarity index 93%
rename from chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/ChromeConnectionService.java
rename to chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ChromeConnectionService.java
index 500fb42..59bf8b2 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/ChromeConnectionService.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/ChromeConnectionService.java
@@ -2,7 +2,7 @@
 // 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.hosted;
+package org.chromium.chrome.browser.customtabs;
 
 import android.app.Service;
 import android.content.Intent;
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/HostedTab.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTab.java
similarity index 64%
rename from chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/HostedTab.java
rename to chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTab.java
index 50fb9bc..b3c5665f 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/HostedTab.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTab.java
@@ -2,7 +2,7 @@
 // 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.hosted;
+package org.chromium.chrome.browser.customtabs;
 
 import android.content.Context;
 import android.text.TextUtils;
@@ -13,6 +13,7 @@
 
 import org.chromium.chrome.browser.CompositorChromeActivity;
 import org.chromium.chrome.browser.ContentViewUtil;
+import org.chromium.chrome.browser.EmptyTabObserver;
 import org.chromium.chrome.browser.Tab;
 import org.chromium.chrome.browser.UrlUtilities;
 import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator;
@@ -20,13 +21,49 @@
 import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator;
 import org.chromium.chrome.browser.tab.ChromeTab;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
+import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.WindowAndroid;
 
 /**
- * A chrome tab that is only used in hosted mode.
+ * A chrome tab that is only used as a custom tab.
  */
-public class HostedTab extends ChromeTab {
+public class CustomTab extends ChromeTab {
+    private static class LoadUrlTabObserver extends EmptyTabObserver {
+        private ChromeBrowserConnection mChromeBrowserConnection;
+        private long mSessionId;
+
+        @Override
+        public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) {
+            mChromeBrowserConnection.registerLaunch(mSessionId, params.getUrl());
+        }
+
+        public LoadUrlTabObserver(ChromeBrowserConnection chromeBrowserConnection, long sessionId) {
+            mChromeBrowserConnection = chromeBrowserConnection;
+            mSessionId = sessionId;
+        }
+    }
+
+    private static class CallbackTabObserver extends EmptyTabObserver {
+        private final ChromeBrowserConnection mChromeBrowserConnection;
+        private final long mSessionId;
+
+        public CallbackTabObserver(
+                ChromeBrowserConnection chromeBrowserConnection, long sessionId) {
+            mChromeBrowserConnection = chromeBrowserConnection;
+            mSessionId = sessionId;
+        }
+
+        @Override
+        public void onPageLoadStarted(Tab tab, String url) {
+            mChromeBrowserConnection.notifyPageLoadStarted(mSessionId, url);
+        }
+
+        @Override
+        public void onPageLoadFinished(Tab tab) {
+            mChromeBrowserConnection.notifyPageLoadFinished(mSessionId, tab.getUrl());
+        }
+    }
 
     private TabChromeContextMenuItemDelegate
             mContextMenuDelegate = new TabChromeContextMenuItemDelegate() {
@@ -38,20 +75,23 @@
             };
 
     /**
-     * Construct an HostedTab. It might load a prerendered {@link WebContents} for the URL, if
-     * the hosted mode service has successfully warmed up for the url.
+     * Construct an CustomTab. It might load a prerendered {@link WebContents} for the URL, if
+     * {@link ChromeConnectionService} has successfully warmed up for the url.
      */
-    public HostedTab(CompositorChromeActivity activity, WindowAndroid windowAndroid,
+    public CustomTab(CompositorChromeActivity activity, WindowAndroid windowAndroid,
             long sessionId, String url, int parentTabId) {
         super(Tab.generateValidId(Tab.INVALID_TAB_ID), activity, false, windowAndroid,
                 TabLaunchType.FROM_EXTERNAL_APP, parentTabId, null, null);
-        WebContents webContents = ChromeBrowserConnection.getInstance(activity.getApplication())
-                                          .takePrerenderedUrl(sessionId, url, null);
+        ChromeBrowserConnection browserConnection =
+                ChromeBrowserConnection.getInstance(activity.getApplication());
+        WebContents webContents = browserConnection.takePrerenderedUrl(sessionId, url, null);
         if (webContents == null) {
             webContents = ContentViewUtil.createWebContents(isIncognito(), false);
         }
         initialize(webContents, activity.getTabContentManager(), false);
         getView().requestFocus();
+        addObserver(new LoadUrlTabObserver(browserConnection, sessionId));
+        addObserver(new CallbackTabObserver(browserConnection, sessionId));
     }
 
     @Override
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/HostedActivity.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
similarity index 80%
rename from chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/HostedActivity.java
rename to chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index a7c15c6..477e3492 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/HostedActivity.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -2,9 +2,10 @@
 // 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.hosted;
+package org.chromium.chrome.browser.customtabs;
 
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.net.Uri;
 import android.text.TextUtils;
 import android.view.MenuItem;
@@ -31,19 +32,19 @@
 import org.chromium.content_public.browser.LoadUrlParams;
 
 /**
- * The activity for hosted mode. It will be launched on top of a client's task.
+ * The activity for custom tabs. It will be launched on top of a client's task.
  */
-public class HostedActivity extends CompositorChromeActivity {
-    private static HostedContentHandler sActiveContentHandler;
+public class CustomTabActivity extends CompositorChromeActivity {
+    private static CustomTabContentHandler sActiveContentHandler;
 
-    private HostedTab mTab;
+    private CustomTab mTab;
     private ToolbarHelper mToolbarHelper;
-    private HostedAppMenuPropertiesDelegate mAppMenuPropertiesDelegate;
+    private CustomTabAppMenuPropertiesDelegate mAppMenuPropertiesDelegate;
     private AppMenuHandler mAppMenuHandler;
     private FindToolbarManager mFindToolbarManager;
-    private HostedIntentDataProvider mIntentDataProvider;
+    private CustomTabIntentDataProvider mIntentDataProvider;
     private long mSessionId;
-    private HostedContentHandler mHostedContentHandler;
+    private CustomTabContentHandler mCustomTabContentHandler;
 
     // This is to give the right package name while using the client's resources during an
     // overridePendingTransition call.
@@ -52,24 +53,25 @@
     private boolean mShouldOverridePackage;
 
     /**
-     * Sets the currently active {@link HostedContentHandler} in focus.
-     * @param contentHandler {@link HostedContentHandler} to set.
+     * Sets the currently active {@link CustomTabContentHandler} in focus.
+     * @param contentHandler {@link CustomTabContentHandler} to set.
      */
-    public static void setActiveContentHandler(HostedContentHandler contentHandler) {
+    public static void setActiveContentHandler(CustomTabContentHandler contentHandler) {
         sActiveContentHandler = contentHandler;
     }
 
     /**
      * Used to check whether an incoming intent can be handled by the
-     * current {@link HostedContentHandler}.
-     * @return Whether the active {@link HostedContentHandler} has handled the intent.
+     * current {@link CustomTabContentHandler}.
+     * @return Whether the active {@link CustomTabContentHandler} has handled the intent.
      */
     public static boolean handleInActiveContentIfNeeded(Intent intent) {
         if (sActiveContentHandler == null) return false;
 
-        long intentSessionId = intent.getLongExtra(HostedIntentDataProvider.EXTRA_HOSTED_SESSION_ID,
-                        HostedIntentDataProvider.INVALID_SESSION_ID);
-        if (intentSessionId == HostedIntentDataProvider.INVALID_SESSION_ID) return false;
+        long intentSessionId = intent.getLongExtra(
+                CustomTabIntentDataProvider.EXTRA_CUSTOM_TABS_SESSION_ID,
+                CustomTabIntentDataProvider.INVALID_SESSION_ID);
+        if (intentSessionId == CustomTabIntentDataProvider.INVALID_SESSION_ID) return false;
 
         if (sActiveContentHandler.getSessionId() != intentSessionId) return false;
         String url = IntentHandler.getUrlFromIntent(intent);
@@ -97,7 +99,7 @@
     public void preInflationStartup() {
         super.preInflationStartup();
         setTabModelSelector(new SingleTabModelSelector(this, false, true));
-        mIntentDataProvider = new HostedIntentDataProvider(getIntent(), this);
+        mIntentDataProvider = new CustomTabIntentDataProvider(getIntent(), this);
     }
 
     @Override
@@ -105,9 +107,10 @@
         super.postInflationStartup();
         ToolbarControlContainer controlContainer =
                 ((ToolbarControlContainer) findViewById(R.id.control_container));
-        mAppMenuPropertiesDelegate = new HostedAppMenuPropertiesDelegate(this,
+        mAppMenuPropertiesDelegate = new CustomTabAppMenuPropertiesDelegate(this,
                 mIntentDataProvider.getMenuTitles());
-        mAppMenuHandler = new AppMenuHandler(this, mAppMenuPropertiesDelegate, R.menu.hosted_menu);
+        mAppMenuHandler =
+                new AppMenuHandler(this, mAppMenuPropertiesDelegate, R.menu.custom_tabs_menu);
         mToolbarHelper = new ToolbarHelper(this, controlContainer,
                 mAppMenuHandler, mAppMenuPropertiesDelegate,
                 getCompositorViewHolder().getInvalidator());
@@ -137,7 +140,7 @@
     public void finishNativeInitialization() {
         String url = IntentHandler.getUrlFromIntent(getIntent());
         mSessionId = mIntentDataProvider.getSessionId();
-        mTab = new HostedTab(this, getWindowAndroid(), mSessionId, url, Tab.INVALID_TAB_ID);
+        mTab = new CustomTab(this, getWindowAndroid(), mSessionId, url, Tab.INVALID_TAB_ID);
         getTabModelSelector().setTab(mTab);
 
         ToolbarControlContainer controlContainer = (ToolbarControlContainer) findViewById(
@@ -153,13 +156,13 @@
                 new OnClickListener() {
                     @Override
                     public void onClick(View v) {
-                        HostedActivity.this.finish();
+                        CustomTabActivity.this.finish();
                     }
                 });
 
         mTab.setFullscreenManager(getFullscreenManager());
         mTab.loadUrl(new LoadUrlParams(url));
-        mHostedContentHandler = new HostedContentHandler() {
+        mCustomTabContentHandler = new CustomTabContentHandler() {
             @Override
             public void loadUrl(LoadUrlParams params) {
                 mTab.loadUrl(params);
@@ -176,11 +179,12 @@
     @Override
     public void onStartWithNative() {
         super.onStartWithNative();
-        setActiveContentHandler(mHostedContentHandler);
+        setActiveContentHandler(mCustomTabContentHandler);
     }
 
     @Override
     public void onStopWithNative() {
+        if (mAppMenuHandler != null) mAppMenuHandler.hideAppMenu();
         super.onStopWithNative();
         setActiveContentHandler(null);
     }
@@ -196,6 +200,12 @@
         return mToolbarHelper.hasDoneFirstDraw();
     }
 
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        if (mAppMenuHandler != null) mAppMenuHandler.hideAppMenu();
+        super.onConfigurationChanged(newConfig);
+    }
+
     /**
      * Calculate the proper color for status bar and update it. Only works on L and future versions.
      */
@@ -214,12 +224,12 @@
 
     @Override
     protected int getControlContainerLayoutId() {
-        return R.layout.hosted_control_container;
+        return R.layout.custom_tabs_control_container;
     }
 
     @Override
     protected int getControlContainerHeightResource() {
-        return R.dimen.hosted_control_container_height;
+        return R.dimen.custom_tabs_control_container_height;
     }
 
     @Override
@@ -292,7 +302,7 @@
      *         purposes only.
      */
     @VisibleForTesting
-    HostedAppMenuPropertiesDelegate getAppMenuPropertiesDelegate() {
+    CustomTabAppMenuPropertiesDelegate getAppMenuPropertiesDelegate() {
         return mAppMenuPropertiesDelegate;
     }
 
@@ -303,11 +313,11 @@
     }
 
     /**
-     * @return The {@link HostedIntentDataProvider} for this {@link HostedActivity}. For test
+     * @return The {@link CustomTabIntentDataProvider} for this {@link CustomTabActivity}. For test
      *         purposes only.
      */
     @VisibleForTesting
-    HostedIntentDataProvider getIntentDataProvider() {
+    CustomTabIntentDataProvider getIntentDataProvider() {
         return mIntentDataProvider;
     }
 }
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/HostedAppMenuPropertiesDelegate.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
similarity index 84%
rename from chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/HostedAppMenuPropertiesDelegate.java
rename to chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
index 3a0dd897..1d7a7e4 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/HostedAppMenuPropertiesDelegate.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
@@ -2,7 +2,7 @@
 // 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.hosted;
+package org.chromium.chrome.browser.customtabs;
 
 import android.view.Menu;
 import android.view.MenuItem;
@@ -19,16 +19,16 @@
 import java.util.Map;
 
 /**
- * App menu properties delegate for {@link HostedActivity}.
+ * App menu properties delegate for {@link CustomTabActivity}.
  */
-public class HostedAppMenuPropertiesDelegate extends ChromeAppMenuPropertiesDelegate {
+public class CustomTabAppMenuPropertiesDelegate extends ChromeAppMenuPropertiesDelegate {
     private boolean mIsCustomEntryAdded;
     private List<String> mMenuEntries;
     private Map<MenuItem, Integer> mItemToIndexMap = new HashMap<MenuItem, Integer>();
     /**
-     * Creates an {@link HostedAppMenuPropertiesDelegate} instance.
+     * Creates an {@link CustomTabAppMenuPropertiesDelegate} instance.
      */
-    public HostedAppMenuPropertiesDelegate(ChromeActivity activity,
+    public CustomTabAppMenuPropertiesDelegate(ChromeActivity activity,
             List<String> menuEntries) {
         super(activity);
         mMenuEntries = menuEntries;
@@ -59,7 +59,7 @@
 
     /**
      * @return The index that the given menu item should appear in the result of
-     *         {@link HostedIntentDataProvider#getMenuTitles()}. Returns -1 if item not found.
+     *         {@link CustomTabIntentDataProvider#getMenuTitles()}. Returns -1 if item not found.
      */
     public int getIndexOfMenuItem(MenuItem menuItem) {
         if (!mItemToIndexMap.containsKey(menuItem)) {
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabContentHandler.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabContentHandler.java
new file mode 100644
index 0000000..2207b14
--- /dev/null
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabContentHandler.java
@@ -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.
+
+package org.chromium.chrome.browser.customtabs;
+
+import org.chromium.content_public.browser.LoadUrlParams;
+
+/**
+ * Interface to handle custom tab calls whenever the session id matched.
+ * TODO(yusufo): Add a way to handle mayLaunchUrl as well.
+ */
+public interface CustomTabContentHandler {
+    /**
+     * Load a new url inside the {@link CustomTabContentHandler}.
+     * @param params The params to use while loading the url.
+     */
+    void loadUrl(LoadUrlParams params);
+
+    /**
+     * @return The session id this {@link CustomTabContentHandler} is associated with.
+     */
+    long getSessionId();
+}
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/HostedIntentDataProvider.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
similarity index 79%
rename from chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/HostedIntentDataProvider.java
rename to chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
index 7f269b62..647f3a5 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/HostedIntentDataProvider.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -2,7 +2,7 @@
 // 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.hosted;
+package org.chromium.chrome.browser.customtabs;
 
 import android.app.Activity;
 import android.app.PendingIntent;
@@ -27,69 +27,77 @@
 
 /**
  * A model class that parses intent from third-party apps and provides results to
- * {@link HostedActivity}.
+ * {@link CustomTabActivity}.
  */
-public class HostedIntentDataProvider {
-    private static final String TAG = "HostedIntentDataProvider";
+public class CustomTabIntentDataProvider {
+    private static final String TAG = "CustomTabIntentDataProvider";
 
     /**
-     * The category name that the service intent has to have for hosted mode. This
+     * The category name that the service intent has to have for custom tabs. This
      * category can also be used to generically resolve to the service component for custom tabs.
      */
     public static final String CATEGORY_CUSTOM_TABS = "android.intent.category.CUSTOM_TABS";
 
     /**
      * Extra used to match the session. This has to be included in the intent to open in
-     * hosted mode. Can be -1 if there is no session id taken. Its value is a long returned
+     * a custom tab. Can be -1 if there is no session id taken. Its value is a long returned
      * by {@link IBrowserConnectionService#newSession}.
      */
-    public static final String EXTRA_HOSTED_SESSION_ID = "hosted:session_id";
+    public static final String EXTRA_CUSTOM_TABS_SESSION_ID =
+            "android.support.CUSTOM_TABS:session_id";
 
     /**
      * Extra used to keep the caller alive. Its value is an Intent.
      */
-    public static final String EXTRA_HOSTED_KEEP_ALIVE = "hosted:keep_alive";
+    public static final String EXTRA_CUSTOM_TABS_KEEP_ALIVE =
+            "android.support.CUSTOM_TABS:keep_alive";
 
     /**
      * Extra that changes the background color for the omnibox. colorRes is an int that specifies a
      * color
      */
-    public static final String EXTRA_HOSTED_TOOLBAR_COLOR = "hosted:toolbar_color";
+    public static final String EXTRA_CUSTOM_TABS_TOOLBAR_COLOR =
+            "android.support.CUSTOM_TABS:toolbar_color";
 
     /**
      * Bundle used for the action button parameters.
      */
-    public static final String EXTRA_HOSTED_ACTION_BUTTON_BUNDLE = "hosted:action_button_bundle";
+    public static final String EXTRA_CUSTOM_TABS_ACTION_BUTTON_BUNDLE =
+            "android.support.CUSTOM_TABS:action_button_bundle";
 
     /**
      * Key that specifies the Bitmap to be used as the image source for the action button.
      */
-    public static final String KEY_HOSTED_ICON = "hosted:icon";
+    public static final String KEY_CUSTOM_TABS_ICON = "android.support.CUSTOM_TABS:icon";
 
     /**
      * Key that specifies the PendingIntent to launch when the action button or menu item was
      * clicked. Chrome will be calling {@link PendingIntent#send()} on clicks after adding the url
      * as data. The client app can call {@link Intent#getDataString()} to get the url.
      */
-    public static final String KEY_HOSTED_PENDING_INTENT = "hosted:pending_intent";
+    public static final String KEY_CUSTOM_TABS_PENDING_INTENT =
+            "android.support.CUSTOM_TABS:pending_intent";
 
     /**
      * Use an {@code ArrayList<Bundle>} for specifying menu related params. There should be a
      * separate Bundle for each custom menu item.
      */
-    public static final String EXTRA_HOSTED_MENU_ITEMS = "hosted:menu_items";
+    public static final String EXTRA_CUSTOM_TABS_MENU_ITEMS =
+            "android.support.CUSTOM_TABS:menu_items";
 
     /**
      * Key for the title of a menu item.
      */
-    public static final String KEY_HOSTED_MENU_TITLE = "hosted:menu_title";
+    public static final String KEY_CUSTOM_TABS_MENU_TITLE =
+            "android.support.CUSTOM_TABS:menu_title";
 
     /**
      * Bundle constructed out of ActivityOptions that Chrome will be running when it finishes
-     * HostedActivity. A similar ActivityOptions for starting Chrome should be constructed and
-     * given to the startActivity() call that launches Chrome.
+     * {@link CustomTabActivity}. A similar ActivityOptions for starting Chrome should be
+     * constructed and given to the startActivity() call that launches Chrome.
      */
-    public static final String EXTRA_HOSTED_EXIT_ANIMATION_BUNDLE = "hosted:exit_animation_bundle";
+    public static final String EXTRA_CUSTOM_TABS_EXIT_ANIMATION_BUNDLE =
+            "android.support.CUSTOM_TABS:exit_animation_bundle";
 
     /**
      * An invalid session ID, used when none is provided in the intent.
@@ -109,52 +117,52 @@
     private PendingIntent.OnFinished mOnFinished;
 
     /**
-     * Constructs a {@link HostedIntentDataProvider}.
+     * Constructs a {@link CustomTabIntentDataProvider}.
      */
-    public HostedIntentDataProvider(Intent intent, Context context) {
+    public CustomTabIntentDataProvider(Intent intent, Context context) {
         if (intent == null) assert false;
 
         mSessionId = IntentUtils.safeGetLongExtra(
-                intent, EXTRA_HOSTED_SESSION_ID, INVALID_SESSION_ID);
+                intent, EXTRA_CUSTOM_TABS_SESSION_ID, INVALID_SESSION_ID);
         retrieveToolbarColor(intent, context);
 
         mKeepAliveServiceIntent = IntentUtils.safeGetParcelableExtra(
-                intent, EXTRA_HOSTED_KEEP_ALIVE);
+                intent, EXTRA_CUSTOM_TABS_KEEP_ALIVE);
 
         Bundle actionButtonBundle = IntentUtils.safeGetBundleExtra(
-                intent, EXTRA_HOSTED_ACTION_BUTTON_BUNDLE);
+                intent, EXTRA_CUSTOM_TABS_ACTION_BUTTON_BUNDLE);
         if (actionButtonBundle != null) {
-            mIcon = IntentUtils.safeGetParcelable(actionButtonBundle, KEY_HOSTED_ICON);
+            mIcon = IntentUtils.safeGetParcelable(actionButtonBundle, KEY_CUSTOM_TABS_ICON);
             if (!checkBitmapSizeWithinBounds(context, mIcon)) {
                 mIcon.recycle();
                 mIcon = null;
             } else {
                 mActionButtonPendingIntent = IntentUtils.safeGetParcelable(
-                        actionButtonBundle, KEY_HOSTED_PENDING_INTENT);
+                        actionButtonBundle, KEY_CUSTOM_TABS_PENDING_INTENT);
             }
         }
 
         List<Bundle> menuItems = IntentUtils.getParcelableArrayListExtra(
-                intent, EXTRA_HOSTED_MENU_ITEMS);
+                intent, EXTRA_CUSTOM_TABS_MENU_ITEMS);
         if (menuItems != null) {
             for (Bundle bundle : menuItems) {
-                String title = IntentUtils.safeGetString(bundle, KEY_HOSTED_MENU_TITLE);
+                String title = IntentUtils.safeGetString(bundle, KEY_CUSTOM_TABS_MENU_TITLE);
                 PendingIntent pendingIntent = IntentUtils.safeGetParcelable(
-                        bundle, KEY_HOSTED_PENDING_INTENT);
+                        bundle, KEY_CUSTOM_TABS_PENDING_INTENT);
                 if (TextUtils.isEmpty(title) || pendingIntent == null) continue;
                 mMenuEntries.add(new Pair<String, PendingIntent>(title, pendingIntent));
             }
         }
 
         mAnimationBundle = IntentUtils.safeGetBundleExtra(
-                intent, EXTRA_HOSTED_EXIT_ANIMATION_BUNDLE);
+                intent, EXTRA_CUSTOM_TABS_EXIT_ANIMATION_BUNDLE);
     }
 
     /**
      * Processes the color passed from the client app and updates {@link #mToolbarColor}.
      */
     private void retrieveToolbarColor(Intent intent, Context context) {
-        int color = IntentUtils.safeGetIntExtra(intent, EXTRA_HOSTED_TOOLBAR_COLOR,
+        int color = IntentUtils.safeGetIntExtra(intent, EXTRA_CUSTOM_TABS_TOOLBAR_COLOR,
                 context.getResources().getColor(R.color.default_primary_color));
         int defaultColor = context.getResources().getColor(R.color.default_primary_color);
 
@@ -227,7 +235,7 @@
             PendingIntent pendingIntent = mMenuEntries.get(menuIndex).second;
             pendingIntent.send(context, 0, addedIntent, mOnFinished, null);
         } catch (CanceledException e) {
-            Log.e(TAG, "Hosted chrome failed to send pending intent.");
+            Log.e(TAG, "Custom tab in Chrome failed to send pending intent.");
         }
     }
 
@@ -278,7 +286,7 @@
         try {
             mActionButtonPendingIntent.send(context, 0, addedIntent);
         } catch (CanceledException e) {
-            Log.e(TAG, "CanceledException while sending pending intent in hosted mode");
+            Log.e(TAG, "CanceledException while sending pending intent in custom tab");
         }
     }
 
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionCallback.aidl b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionCallback.aidl
new file mode 100644
index 0000000..dd52f15
--- /dev/null
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionCallback.aidl
@@ -0,0 +1,30 @@
+// 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.customtabs;
+
+import android.os.Bundle;
+
+/**
+ * Interface for the client-provided callback on user navigation.
+ */
+interface IBrowserConnectionCallback {
+    /**
+     * To be called when a page navigation starts.
+     *
+     * @param sessionId As returned by {@link IBrowserConnectionService#newSession}.
+     * @param url URL the user has navigated to.
+     * @param extras Reserved for future use.
+     */
+    oneway void onUserNavigationStarted(long sessionId, String url, in Bundle extras);
+
+    /**
+     * To be called when a page navigation finishes.
+     *
+     * @param sessionId As returned by {@link IBrowserConnectionService#newSession}.
+     * @param url URL the user has navigated to.
+     * @param extras Reserved for future use.
+     */
+    oneway void onUserNavigationFinished(long sessionId, String url, in Bundle extras);
+}
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/IBrowserConnectionService.aidl b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionService.aidl
similarity index 97%
rename from chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/IBrowserConnectionService.aidl
rename to chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionService.aidl
index 077bded..647b366b 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/IBrowserConnectionService.aidl
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/IBrowserConnectionService.aidl
@@ -2,7 +2,7 @@
 // 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.hosted;
+package org.chromium.chrome.browser.customtabs;
 
 import android.os.Bundle;
 
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/OWNERS b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/OWNERS
similarity index 100%
rename from chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/OWNERS
rename to chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/OWNERS
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/common.aidl b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/common.aidl
similarity index 60%
rename from chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/common.aidl
rename to chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/common.aidl
index 317a02e..f3a0fc0 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/common.aidl
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/customtabs/common.aidl
@@ -4,5 +4,5 @@
 
 // This file is needed to compile IBrowserConnectionService.aidl.
 
-interface org.chromium.chrome.browser.hosted.IBrowserConnectionService;
-interface org.chromium.chrome.browser.hosted.IBrowserConnectionCallback;
+interface org.chromium.chrome.browser.customtabs.IBrowserConnectionService;
+interface org.chromium.chrome.browser.customtabs.IBrowserConnectionCallback;
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
index 23f967a..0a19e65 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
@@ -37,9 +37,9 @@
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.WarmupManager;
 import org.chromium.chrome.browser.WebappAuthenticator;
+import org.chromium.chrome.browser.customtabs.CustomTabActivity;
+import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
 import org.chromium.chrome.browser.firstrun.FirstRunFlowSequencer;
-import org.chromium.chrome.browser.hosted.HostedActivity;
-import org.chromium.chrome.browser.hosted.HostedIntentDataProvider;
 import org.chromium.chrome.browser.metrics.LaunchHistogram;
 import org.chromium.chrome.browser.metrics.LaunchMetrics;
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
@@ -155,7 +155,7 @@
         mIntentHandler = new IntentHandler(this, getPackageName());
         maybePerformMigrationTasks();
 
-        if (handleHostedActivityIntent()) {
+        if (handleCustomTabActivityIntent()) {
             finish();
             return;
         }
@@ -249,26 +249,29 @@
     }
 
     /**
-     * Handles launching an hosted activity, which will sit on top of a client's activity in the
-     * same task.
+     * Handles launching a {@link CustomTabActivity}, which will sit on top of a client's activity
+     * in the same task.
      * @return True if the intent is handled here.
      */
-    private boolean handleHostedActivityIntent() {
+    private boolean handleCustomTabActivityIntent() {
         if (getIntent() == null) return false;
 
-        if (!getIntent().hasExtra(HostedIntentDataProvider.EXTRA_HOSTED_SESSION_ID)) return false;
+        if (!getIntent().hasExtra(
+                CustomTabIntentDataProvider.EXTRA_CUSTOM_TABS_SESSION_ID)) {
+            return false;
+        }
 
         String url = IntentHandler.getUrlFromIntent(getIntent());
         if (url == null) return false;
 
-        boolean handled = HostedActivity.handleInActiveContentIfNeeded(getIntent());
+        boolean handled = CustomTabActivity.handleInActiveContentIfNeeded(getIntent());
         if (handled) return true;
 
         // Create and fire a launch intent. Use the copy constructor to carry over the myriad of
         // extras.
         Intent newIntent = new Intent(getIntent());
         newIntent.setAction(Intent.ACTION_VIEW);
-        newIntent.setClassName(this, HostedActivity.class.getName());
+        newIntent.setClassName(this, CustomTabActivity.class.getName());
         newIntent.setData(Uri.parse(url));
         startActivity(newIntent);
         return true;
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentActivity.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentActivity.java
index 8b6b614b..0651c6b0 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentActivity.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentActivity.java
@@ -627,7 +627,7 @@
 
         mDocumentTab.addObserver(new DocumentTabObserver() {
             @Override
-            public void onPageLoadStarted(Tab tab) {
+            public void onPageLoadStarted(Tab tab, String url) {
                 // Discard startup navigation measurements when the user interfered and started the
                 // 2nd navigation (in activity lifetime) in parallel.
                 if (!sIsFirstPageLoadStart) {
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentMigrationHelper.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentMigrationHelper.java
index 824620c..07f2d62 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentMigrationHelper.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentMigrationHelper.java
@@ -16,6 +16,7 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.os.Build;
+import android.os.StrictMode;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
@@ -273,16 +274,24 @@
      */
     public static boolean migrateTabsToDocumentForUpgrade(Activity activity,
             int finalizeMode) {
-        ChromePreferenceManager.getInstance(activity).setAttemptedMigrationOnUpgrade();
-        File[] fileList = TabPersistentStore.getStateDirectory(activity, 0).listFiles();
-        if (fileList == null || fileList.length == 0
-                || (fileList.length == 1
-                && fileList[0].getName().equals(TabPersistentStore.SAVED_STATE_FILE))) {
-            return false;
-        }
+        // Temporarily allowing disk access. TODO: Fix. See http://crbug.com/493157
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        StrictMode.allowThreadDiskWrites();
+        try {
+            ChromePreferenceManager.getInstance(activity).setAttemptedMigrationOnUpgrade();
 
-        migrateTabsFromClassicToDocument(activity, finalizeMode);
-        return true;
+            File[] fileList = TabPersistentStore.getStateDirectory(activity, 0).listFiles();
+            if (fileList == null || fileList.length == 0
+                    || (fileList.length == 1
+                    && fileList[0].getName().equals(TabPersistentStore.SAVED_STATE_FILE))) {
+                return false;
+            }
+
+            migrateTabsFromClassicToDocument(activity, finalizeMode);
+            return true;
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
     }
 
     private static void finalizeMigration(Activity activity, final int mode) {
@@ -449,11 +458,19 @@
      */
     public static void migrateTabs(boolean toDocumentMode, final Activity activity,
             boolean terminate) {
-        int terminateMode = terminate ? FINALIZE_MODE_RESTART_APP : FINALIZE_MODE_FINISH_ACTIVITY;
-        if (toDocumentMode) {
-            migrateTabsFromClassicToDocument(activity, terminateMode);
-        } else {
-            migrateTabsFromDocumentToClassic(activity, terminateMode);
+        // Temporarily allowing disk access. TODO: Fix. See http://crbug.com/493157
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        StrictMode.allowThreadDiskWrites();
+        try {
+            int terminateMode =
+                    terminate ? FINALIZE_MODE_RESTART_APP : FINALIZE_MODE_FINISH_ACTIVITY;
+            if (toDocumentMode) {
+                migrateTabsFromClassicToDocument(activity, terminateMode);
+            } else {
+                migrateTabsFromDocumentToClassic(activity, terminateMode);
+            }
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
         }
     }
 }
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentTab.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentTab.java
index ce3203ab..7ae18bf 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentTab.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentTab.java
@@ -244,6 +244,8 @@
         @Override
         public void webContentsCreated(WebContents sourceWebContents, long openerRenderFrameId,
                 String frameName, String targetUrl, WebContents newWebContents) {
+            // TODO(dfalcantara): Replace with TabObserver, combine with FullScreenActivityTab's
+            //                    WebContentsDelegateAndroidImpl.
             super.webContentsCreated(sourceWebContents, openerRenderFrameId, frameName,
                     targetUrl, newWebContents);
             long nativeNewWebContents =
@@ -255,6 +257,7 @@
         @Override
         public boolean addNewContents(WebContents sourceWebContents, WebContents webContents,
                 int disposition, Rect initialPosition, boolean userGesture) {
+            // TODO(dfalcantara): Set TabCreators on DocumentActivity, replace with super method.
             if (isClosing()) return false;
             long nativeWebContents =
                     ContentViewUtil.getNativeWebContentsFromWebContents(webContents);
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentWebContentsDelegate.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentWebContentsDelegate.java
index 9b3455cd..e47771e 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentWebContentsDelegate.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentWebContentsDelegate.java
@@ -8,7 +8,10 @@
 import org.chromium.content_public.browser.WebContents;
 
 /**
- * Stubs out calls to the WebContentsDelegateAndroid.
+ * Stubs out calls to the WebContentsDelegateAndroid.  Attaching a WebContentsDelegateAndroid to a
+ * newly created WebContents signals to Chrome that it was created properly, which is needed in
+ * situations where Chrome on Android needs to create the Activity for the WebContents
+ * asynchronously.
  */
 public class DocumentWebContentsDelegate extends WebContentsDelegateAndroid {
     /**
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
index e6716e4..2a2f0ed 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
@@ -22,6 +22,9 @@
 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.infobar.InfoBar;
+import org.chromium.chrome.browser.infobar.InfoBarContainer;
+import org.chromium.chrome.browser.infobar.InfoBarContainer.InfoBarContainerObserver;
 import org.chromium.chrome.browser.tab.ChromeTab;
 import org.chromium.components.dom_distiller.content.DistillablePageUtils;
 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
@@ -35,7 +38,7 @@
  * top controls when a reader mode page has finished loading.
  */
 public class ReaderModeManager extends EmptyTabObserver
-        implements ContextualSearchObserver, ReaderModePanelHost {
+        implements ContextualSearchObserver, InfoBarContainerObserver, ReaderModePanelHost {
 
     /**
      * Observer for changes to the current status of reader mode.
@@ -124,6 +127,8 @@
         ContextualSearchManager contextualSearchManager = getContextualSearchManager(tab);
         if (contextualSearchManager != null) contextualSearchManager.removeObserver(this);
 
+        if (mTab.getInfoBarContainer() != null) mTab.getInfoBarContainer().removeObserver(this);
+
         if (mReaderModePanel != null) mReaderModePanel.onDestroy();
 
         if (mWebContentsObserver != null) {
@@ -150,6 +155,19 @@
         }
         ContextualSearchManager contextualSearchManager = getContextualSearchManager(tab);
         if (contextualSearchManager != null) contextualSearchManager.addObserver(this);
+
+        if (tab.getInfoBarContainer() != null) tab.getInfoBarContainer().addObserver(this);
+    }
+
+    @Override
+    public void onToggleFullscreenMode(Tab tab, boolean enable) {
+        if (mReaderModePanel == null) return;
+
+        if (enable) {
+            mReaderModePanel.onEnterFullscreen();
+        } else {
+            mReaderModePanel.onExitFullscreen();
+        }
     }
 
     // ContextualSearchObserver:
@@ -163,6 +181,17 @@
         if (mReaderModePanel != null) mReaderModePanel.unhideButtonBar();
     }
 
+    // InfoBarContainerObserver:
+    @Override
+    public void onAddInfoBar(InfoBarContainer container, InfoBar infoBar, boolean isFirst) {
+        if (isFirst && mReaderModePanel != null) mReaderModePanel.onShowInfobarContainer();
+    }
+
+    @Override
+    public void onRemoveInfoBar(InfoBarContainer container, InfoBar infoBar, boolean isLast) {
+        if (isLast && mReaderModePanel != null) mReaderModePanel.onHideInfobarContainer();
+    }
+
     // ReaderModePanelHost:
 
     // TODO(aruslan): use the one in ChromeSwitches once it's rolled.
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModePanel.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModePanel.java
index 4f16a19..63bbc066 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModePanel.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModePanel.java
@@ -20,9 +20,11 @@
 import org.chromium.chrome.browser.tab.ChromeTab;
 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.content_public.common.TopControlsState;
 import org.chromium.ui.base.WindowAndroid;
 
 import java.util.concurrent.TimeUnit;
@@ -143,7 +145,12 @@
 
     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;
@@ -154,6 +161,13 @@
     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;
@@ -180,7 +194,6 @@
      * Destroys the panel and associated resources.
      */
     public void onDestroy() {
-        mLayoutAnimations = null;
         hideButtonBar();
     }
 
@@ -527,20 +540,23 @@
         animateTo(mX, 1.0f, true);
     }
 
+    private boolean isReaderModeCurrentlyAllowed() {
+        return !mIsReaderModePanelHidden && !mIsReaderModePanelDismissed
+                && !mIsFullscreenModeEntered && !mIsInfobarContainerShown;
+    }
+
     private void nonAnimatedUpdateButtomButtonBar() {
         final int status = mReaderModeHost.getReaderModeStatus();
         final Tab tab = mReaderModeHost.getTab();
 
         if (mReaderModeButtonView != null
-                && (status != ReaderModeManager.POSSIBLE || mIsReaderModePanelHidden
-                        || mIsReaderModePanelDismissed)) {
+                && (status != ReaderModeManager.POSSIBLE || !isReaderModeCurrentlyAllowed())) {
             mReaderModeButtonView.dismiss(true);
             mReaderModeButtonView = null;
             return;
         }
         if (mReaderModeButtonView == null
-                && (status == ReaderModeManager.POSSIBLE && !mIsReaderModePanelHidden
-                        && !mIsReaderModePanelDismissed)) {
+                && (status == ReaderModeManager.POSSIBLE && isReaderModeCurrentlyAllowed())) {
             mReaderModeButtonView = ReaderModeButtonView.create(tab.getContentViewCore(),
                     new ReaderModeButtonViewDelegate() {
                         @Override
@@ -572,8 +588,7 @@
 
         final int status = mReaderModeHost.getReaderModeStatus();
         if (isPanelWithinScreenBounds()
-                && (status != ReaderModeManager.POSSIBLE
-                        || mIsReaderModePanelHidden || mIsReaderModePanelDismissed)) {
+                && (status != ReaderModeManager.POSSIBLE || !isReaderModeCurrentlyAllowed())) {
             animateTo(0.0f, -1.0f, true);
             mReaderModeHost.destroyReaderModeControl();
             destroyDistilledContentViewCore();
@@ -582,8 +597,7 @@
         }
 
         if (!isPanelWithinScreenBounds()
-                && (status == ReaderModeManager.POSSIBLE
-                        && !mIsReaderModePanelHidden && !mIsReaderModePanelDismissed)) {
+                && (status == ReaderModeManager.POSSIBLE && isReaderModeCurrentlyAllowed())) {
             animateTo(0.0f, 0.0f, true);
             mReaderModeHost.createReaderModeControl();
             requestUpdate();
@@ -591,11 +605,22 @@
         }
     }
 
-    private static ContentViewCore createDistillerContentViewCore(
+    private ContentViewCore createDistillerContentViewCore(
             Context context, WindowAndroid windowAndroid) {
         ContentViewCore cvc = new ContentViewCore(context);
         ContentView cv = new ContentView(context, cvc);
         cvc.initialize(cv, cv, ContentViewUtil.createWebContents(false, 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;
     }
 
@@ -608,6 +633,8 @@
         if (mDistilledContentViewCore != null) return;
 
         mDidFirstNonEmptyDistilledPaint = false;
+        mDidStartLoad = false;
+        mDidFinishLoad = false;
         mDistilledContentViewCore = createDistillerContentViewCore(
                 mReaderModeHost.getTab().getContentViewCore().getContext(),
                 mReaderModeHost.getTab().getWindowAndroid());
@@ -621,6 +648,18 @@
                 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);
@@ -628,25 +667,49 @@
                 mReaderModeHost.getTab().getContentViewCore().getWebContents(),
                 mDistilledContentViewCore.getWebContents());
         mDistilledContentViewCore.onShow();
-
-        mReaderModeHost.getTab().updateTopControlsState(TopControlsState.BOTH, false);
     }
 
     private void nonAnimatedEnterDistilledMode() {
         RecordUserAction.record("DomDistiller_DistilledPageOpened");
         DomDistillerTabUtils.distillCurrentPageAndView(mReaderModeHost.getTab().getWebContents());
-        mReaderModeHost.getTab().updateTopControlsState(TopControlsState.SHOWN, false);
         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();
 
-        mReaderModeHost.getTab().updateTopControlsState(TopControlsState.HIDDEN, false);
-        DomDistillerTabUtils.distillCurrentPageAndView(mReaderModeHost.getTab().getWebContents());
+        mDistilledContentViewCore.getWebContents().updateTopControlsState(true, false, false);
+
+        mReaderModeHost.getTab().detachOverlayContentViewCore(mDistilledContentViewCore);
+        mDistilledContentObserver.destroy();
+        mDistilledContentObserver = null;
+
+        mDistilledContentViewCore.setContentViewClient(new ContentViewClient());
+        mergeNavigationHistory(mDistilledContentViewCore.getWebContents(),
+                mReaderModeHost.getTab().getWebContents());
+        mReaderModeHost.getTab().swapContentViewCore(mDistilledContentViewCore, true,
+                mDidStartLoad, mDidFinishLoad);
+        mDistilledContentViewCore.getContentViewClient().onOffsetsForFullscreenChanged(
+                mTopControlsOffsetYPix, mContentOffsetYPix, mOverdrawBottomHeightPix);
+
+        mDistilledContentViewCore = null;
         destroyDistilledContentViewCore();
+
         if (mLayoutDelegate != null) {
             mLayoutDelegate.setLayoutTabBrightness(1.0f);
             mLayoutDelegate.setLayoutTabY(0.0f);
@@ -656,10 +719,13 @@
     }
 
     private void destroyDistilledContentViewCore() {
+        if (mDistilledContentObserver != null) {
+            mDistilledContentObserver.destroy();
+            mDistilledContentObserver = null;
+        }
+
         if (mDistilledContentViewCore == null) return;
 
-        mDistilledContentObserver.destroy();
-        mDistilledContentObserver = null;
         mReaderModeHost.getTab().detachOverlayContentViewCore(mDistilledContentViewCore);
 
         mDistilledContentViewCore.getWebContents().destroy();
@@ -671,9 +737,8 @@
      * Hides the reader mode button bar if shown.
      */
     public void hideButtonBar() {
-        if (mIsReaderModePanelHidden) return;
-
         mIsReaderModePanelHidden = true;
+        mLayoutAnimations = null;
         updateBottomButtonBar();
     }
 
@@ -681,9 +746,8 @@
      * Dismisses the reader mode button bar if shown.
      */
     public void dismissButtonBar() {
-        if (mIsReaderModePanelDismissed) return;
-
         mIsReaderModePanelDismissed = true;
+        mLayoutAnimations = null;
         updateBottomButtonBar();
     }
 
@@ -696,6 +760,40 @@
     }
 
     /**
+     * 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.
       */
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java
index 62950c4..c62c3329 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java
@@ -24,9 +24,11 @@
 import org.chromium.chrome.browser.BookmarksBridge.BookmarkItem;
 import org.chromium.chrome.browser.BookmarksBridge.BookmarkModelObserver;
 import org.chromium.chrome.browser.UrlConstants;
+import org.chromium.chrome.browser.enhanced_bookmarks.EnhancedBookmarksBridge;
 import org.chromium.chrome.browser.enhanced_bookmarks.EnhancedBookmarksBridge.FiltersObserver;
 import org.chromium.chrome.browser.enhanced_bookmarks.EnhancedBookmarksModel;
 import org.chromium.chrome.browser.enhanced_bookmarks.LaunchLocation;
+import org.chromium.chrome.browser.enhanced_bookmarks.ViewMode;
 import org.chromium.chrome.browser.ntp.NewTabPageUma;
 import org.chromium.chrome.browser.partnerbookmarks.PartnerBookmarksShim;
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarManageable;
@@ -50,11 +52,6 @@
 public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate {
     private static final String PREF_LAST_USED_URL = "enhanced_bookmark_last_used_url";
     static final String PREF_WAS_IN_LIST_MODE = "enhanced_bookmark_list_mode_choice";
-    // TODO(ianwen): upstream these metrics upstream.
-    // UI modes for bookmarks presentation. Default option is grid mode.
-    static final int DEFAULT_MODE = 0;
-    static final int LIST_MODE = 1;
-    static final int GRID_MODE = 2;
 
     private Activity mActivity;
     private ViewGroup mMainView;
@@ -289,13 +286,17 @@
 
     private void saveListModePreference() {
         PreferenceManager.getDefaultSharedPreferences(mActivity).edit()
-                .putInt(PREF_WAS_IN_LIST_MODE, mListModeEnabled ? LIST_MODE : GRID_MODE).apply();
+                .putInt(PREF_WAS_IN_LIST_MODE, mListModeEnabled ? ViewMode.LIST : ViewMode.GRID)
+                .apply();
     }
 
     private boolean getListModePreference() {
         int mode = PreferenceManager.getDefaultSharedPreferences(mActivity).getInt(
-                PREF_WAS_IN_LIST_MODE, DEFAULT_MODE);
-        return mode == LIST_MODE ? true : false;
+                PREF_WAS_IN_LIST_MODE, ViewMode.DEFAULT);
+
+        if (mode == ViewMode.DEFAULT) mode = EnhancedBookmarksBridge.getDefaultViewMode();
+
+        return mode == ViewMode.LIST ? true : false;
     }
 
     private void initListModeOptionTo(boolean isListModeEnabled) {
@@ -307,7 +308,7 @@
         // toggle, we record the list view state.
         int listViewstate = PreferenceManager.getDefaultSharedPreferences(getView().getContext())
                 .getInt(EnhancedBookmarkManager.PREF_WAS_IN_LIST_MODE,
-                        EnhancedBookmarkManager.DEFAULT_MODE);
+                        ViewMode.DEFAULT);
         RecordHistogram.recordEnumeratedHistogram("EnhancedBookmarks.ViewMode", listViewstate, 3);
     }
 
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkPromoHeader.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkPromoHeader.java
index e8f5a41b..37df0ff 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkPromoHeader.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkPromoHeader.java
@@ -22,7 +22,6 @@
 import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
 import org.chromium.sync.AndroidSyncSettings;
 import org.chromium.sync.AndroidSyncSettings.AndroidSyncSettingsObserver;
-import org.chromium.sync.signin.ChromeSigninController;
 
 /**
  * Class that manages all the logic and UI behind the signin promo header in the enhanced bookmark
@@ -134,7 +133,7 @@
     private void updateShowing(boolean notifyUI) {
         boolean oldIsShowing = mIsShowing;
         mIsShowing = AndroidSyncSettings.isMasterSyncEnabled(mContext)
-                && !ChromeSigninController.get(mContext).isSignedIn()
+                && mSignInManager.isSignInAllowed()
                 && !wasSigninPromoDeclined();
 
         if (oldIsShowing != mIsShowing && notifyUI) {
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/ChromeBrowserConnection.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/ChromeBrowserConnection.java
deleted file mode 100644
index ebab5bac..0000000
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/ChromeBrowserConnection.java
+++ /dev/null
@@ -1,335 +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.hosted;
-
-import android.annotation.SuppressLint;
-import android.app.ActivityManager;
-import android.app.Application;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.LongSparseArray;
-import android.util.SparseArray;
-
-import org.chromium.base.Log;
-import org.chromium.base.ThreadUtils;
-import org.chromium.base.annotations.SuppressFBWarnings;
-import org.chromium.base.library_loader.ProcessInitException;
-import org.chromium.chrome.browser.ChromiumApplication;
-import org.chromium.chrome.browser.WarmupManager;
-import org.chromium.content.browser.ChildProcessLauncher;
-import org.chromium.content_public.browser.WebContents;
-
-import java.security.SecureRandom;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Implementation of the IBrowserConnectionService interface.
- */
-class ChromeBrowserConnection extends IBrowserConnectionService.Stub {
-    private static final String TAG = Log.makeTag("ChromeConnection");
-    private static final long RESULT_OK = 0;
-    private static final long RESULT_ERROR = -1;
-
-    private static final Object sConstructionLock = new Object();
-    private static ChromeBrowserConnection sInstance;
-
-    private final Application mApplication;
-    private final AtomicBoolean mWarmupHasBeenCalled;
-
-    /** Per-sessionId values. */
-    private static class SessionParams {
-        public final int mUid;
-        private ServiceConnection mServiceConnection;
-
-        public SessionParams(int uid) {
-            mUid = uid;
-            mServiceConnection = null;
-        }
-
-        public ServiceConnection getServiceConnection() {
-            return mServiceConnection;
-        }
-
-        public void setServiceConnection(ServiceConnection serviceConnection) {
-            mServiceConnection = serviceConnection;
-        }
-    }
-
-    private final Object mLock;
-    private final SparseArray<IBrowserConnectionCallback> mUidToCallback;
-    private final LongSparseArray<SessionParams> mSessionParams;
-
-    private ChromeBrowserConnection(Application application) {
-        super();
-        mApplication = application;
-        mWarmupHasBeenCalled = new AtomicBoolean();
-        mLock = new Object();
-        mUidToCallback = new SparseArray<IBrowserConnectionCallback>();
-        mSessionParams = new LongSparseArray<SessionParams>();
-    }
-
-    /**
-     * @return The unique instance of ChromeBrowserConnection.
-     */
-    public static ChromeBrowserConnection getInstance(Application application) {
-        synchronized (sConstructionLock) {
-            if (sInstance == null) sInstance = new ChromeBrowserConnection(application);
-        }
-        return sInstance;
-    }
-
-    @Override
-    public long finishSetup(IBrowserConnectionCallback callback) {
-        if (callback == null) return RESULT_ERROR;
-        final int uid = Binder.getCallingUid();
-        synchronized (mLock) {
-            if (mUidToCallback.get(uid) != null) return RESULT_ERROR;
-            try {
-                callback.asBinder().linkToDeath(new IBinder.DeathRecipient() {
-                    @Override
-                    public void binderDied() {
-                        synchronized (mLock) {
-                            cleanupAlreadyLocked(uid);
-                        }
-                    }
-                }, 0);
-            } catch (RemoteException e) {
-                // The return code doesn't matter, because this executes when
-                // the caller has died.
-                return RESULT_ERROR;
-            }
-            mUidToCallback.put(uid, callback);
-        }
-        return RESULT_OK;
-    }
-
-    @Override
-    public long warmup(long flags) {
-        // Here and in mayLaunchUrl(), don't do expensive work for background applications.
-        if (!isUidForeground(Binder.getCallingUid())) return RESULT_ERROR;
-        if (!mWarmupHasBeenCalled.compareAndSet(false, true)) return RESULT_OK;
-        // The call is non-blocking and this must execute on the UI thread, post a task.
-        ThreadUtils.postOnUiThread(new Runnable() {
-            @Override
-            @SuppressFBWarnings("DM_EXIT")
-            public void run() {
-                try {
-                    // TODO(lizeb): Warm up more of the browser.
-                    ChromiumApplication app = (ChromiumApplication) mApplication;
-                    app.startBrowserProcessesAndLoadLibrariesSync(
-                            app.getApplicationContext(), true);
-                    final Context context = app.getApplicationContext();
-                    new AsyncTask<Void, Void, Void>() {
-                        @Override
-                        protected Void doInBackground(Void... params) {
-                            ChildProcessLauncher.warmUp(context);
-                            return null;
-                        }
-                    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
-                } catch (ProcessInitException e) {
-                    Log.e(TAG, "ProcessInitException while starting the browser process.");
-                    // Cannot do anything without the native library, and cannot show a
-                    // dialog to the user.
-                    System.exit(-1);
-                }
-            }
-        });
-        return RESULT_OK;
-    }
-
-    @Override
-    @SuppressLint("TrulyRandom") // TODO(lizeb): Figure out whether using SecureRandom is OK.
-    public long newSession() {
-        synchronized (mLock) {
-            long sessionId;
-            SecureRandom randomSource = new SecureRandom();
-            do {
-                sessionId = randomSource.nextLong();
-                // Because Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE.
-                if (sessionId == Long.MIN_VALUE) continue;
-                sessionId = Math.abs(sessionId);
-            } while (sessionId == 0 || mSessionParams.get(sessionId) != null);
-            mSessionParams.put(sessionId, new SessionParams(Binder.getCallingUid()));
-            return sessionId;
-        }
-    }
-
-    @Override
-    public long mayLaunchUrl(
-            long sessionId, final String url, Bundle extras, List<Bundle> otherLikelyBundles) {
-        int uid = Binder.getCallingUid();
-        // Don't do anything for unknown schemes. Not having a scheme is
-        // allowed, as we allow "www.example.com".
-        String scheme = Uri.parse(url).normalizeScheme().getScheme();
-        if (scheme != null && !scheme.equals("http") && !scheme.equals("https")) {
-            return RESULT_ERROR;
-        }
-        if (!isUidForeground(uid)) return RESULT_ERROR;
-        synchronized (mLock) {
-            SessionParams sessionParams = mSessionParams.get(sessionId);
-            if (sessionParams == null || sessionParams.mUid != uid) return RESULT_ERROR;
-        }
-        ThreadUtils.postOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                WarmupManager.getInstance().maybePrefetchDnsForUrlInBackground(
-                        mApplication.getApplicationContext(), url);
-            }
-        });
-        // TODO(lizeb): Prerendering.
-        return sessionId;
-    }
-
-    /**
-     * Transfers a prerendered WebContents if one exists.
-     *
-     * This resets the internal WebContents; a subsequent call to this method
-     * returns null.
-     *
-     * @param sessionId The session ID, returned by {@link newSession}.
-     * @param url The URL the WebContents is for.
-     * @param extras from the intent.
-     * @return The prerendered WebContents, or null.
-     */
-    WebContents takePrerenderedUrl(long sessionId, String url, Bundle extras) {
-        // TODO(lizeb): Pre-rendering.
-        return null;
-    }
-
-    /**
-     * Calls the onUserNavigation callback for a given sessionId.
-     *
-     * This is non-blocking.
-     *
-     * @param sessionId Session ID associated with the callback
-     * @param url URL the user has navigated to.
-     * @param bundle Reserved for future use.
-     * @return false if there is no client to deliver the callback to.
-     */
-    boolean deliverOnUserNavigationCallback(long sessionId, String url, Bundle extras) {
-        synchronized (mLock) {
-            SessionParams sessionParams = mSessionParams.get(sessionId);
-            if (sessionParams == null) return false;
-            IBrowserConnectionCallback cb = mUidToCallback.get(sessionParams.mUid);
-            if (cb == null) return false;
-            try {
-                cb.onUserNavigation(sessionId, url, extras);
-            } catch (RemoteException e) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Keeps the application linked with sessionId alive.
-     *
-     * The application is kept alive (that is, raised to at least the current
-     * process priority level) until {@link dontKeepAliveForSessionId()} is
-     * called.
-     *
-     * @param sessionId Session ID provided in the intent.
-     * @param intent Intent describing the service to bind to.
-     * @return true for success.
-     */
-    boolean keepAliveForSessionId(long sessionId, Intent intent) {
-        // When an application is bound to a service, its priority is raised to
-        // be at least equal to the application's one. This binds to a dummy
-        // service (no calls to this service are made).
-        if (intent == null || intent.getComponent() == null) return false;
-        SessionParams sessionParams;
-        synchronized (mLock) {
-            sessionParams = mSessionParams.get(sessionId);
-            if (sessionParams == null) return false;
-        }
-        String packageName = intent.getComponent().getPackageName();
-        PackageManager pm = mApplication.getApplicationContext().getPackageManager();
-        // Only binds to the application associated to this session ID.
-        int uid = sessionParams.mUid;
-        if (!Arrays.asList(pm.getPackagesForUid(uid)).contains(packageName)) return false;
-        Intent serviceIntent = new Intent().setComponent(intent.getComponent());
-        // This ServiceConnection doesn't handle disconnects. This is on
-        // purpose, as it occurs when the remote process has died. Since the
-        // only use of this connection is to keep the application alive,
-        // re-connecting would just re-create the process, but the application
-        // state has been lost at that point, the callbacks invalidated, etc.
-        ServiceConnection connection = new ServiceConnection() {
-            @Override
-            public void onServiceConnected(ComponentName name, IBinder service) {}
-            @Override
-            public void onServiceDisconnected(ComponentName name) {}
-        };
-        boolean ok;
-        try {
-            ok = mApplication.getApplicationContext().bindService(
-                    serviceIntent, connection, Context.BIND_AUTO_CREATE);
-        } catch (SecurityException e) {
-            return false;
-        }
-        if (ok) sessionParams.setServiceConnection(connection);
-        return ok;
-    }
-
-    /**
-     * Lets the lifetime of the process linked to a given sessionId be managed normally.
-     *
-     * Without a matching call to {@link keepAliveForSessionId}, this is a no-op.
-     *
-     * @param sessionId Session ID, as provided to {@link keepAliveForSessionId}.
-     */
-    void dontKeepAliveForSessionId(long sessionId) {
-        SessionParams sessionParams;
-        synchronized (mLock) {
-            sessionParams = mSessionParams.get(sessionId);
-        }
-        if (sessionParams == null || sessionParams.getServiceConnection() == null) return;
-        ServiceConnection serviceConnection = sessionParams.getServiceConnection();
-        sessionParams.setServiceConnection(null);
-        mApplication.getApplicationContext().unbindService(serviceConnection);
-    }
-
-    /**
-     * @return true iff the UID is associated with a process having a foreground importance.
-     */
-    private boolean isUidForeground(int uid) {
-        ActivityManager am =
-                (ActivityManager) mApplication.getSystemService(Context.ACTIVITY_SERVICE);
-        List<ActivityManager.RunningAppProcessInfo> running = am.getRunningAppProcesses();
-        for (ActivityManager.RunningAppProcessInfo rpi : running) {
-            boolean isForeground =
-                    rpi.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
-            if (rpi.uid == uid && isForeground) return true;
-        }
-        return false;
-    }
-
-    /**
-     * Called when a remote client has died.
-     */
-    private void cleanupAlreadyLocked(int uid) {
-        List<Long> keysToRemove = new ArrayList<Long>();
-        // TODO(lizeb): If iterating through all the session IDs is too costly,
-        // use two mappings.
-        for (int i = 0; i < mSessionParams.size(); i++) {
-            if (mSessionParams.valueAt(i).mUid == uid) keysToRemove.add(mSessionParams.keyAt(i));
-        }
-        for (Long sessionId : keysToRemove) {
-            mSessionParams.remove(sessionId);
-        }
-        mUidToCallback.remove(uid);
-    }
-}
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/HostedContentHandler.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/HostedContentHandler.java
deleted file mode 100644
index a2b6685e..0000000
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/HostedContentHandler.java
+++ /dev/null
@@ -1,24 +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.hosted;
-
-import org.chromium.content_public.browser.LoadUrlParams;
-
-/**
- * Interface to handle hosted mode calls whenever the session id matched.
- * TODO(yusufo): Add a way to handle mayLaunchUrl as well.
- */
-public interface HostedContentHandler {
-    /**
-     * Load a new url inside the {@link HostedContentHandler}.
-     * @param params The params to use while loading the url.
-     */
-    void loadUrl(LoadUrlParams params);
-
-    /**
-     * @return The session id this {@link HostedContentHandler} is associated with.
-     */
-    long getSessionId();
-}
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/IBrowserConnectionCallback.aidl b/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/IBrowserConnectionCallback.aidl
deleted file mode 100644
index d8b3d8e..0000000
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/IBrowserConnectionCallback.aidl
+++ /dev/null
@@ -1,21 +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.hosted;
-
-import android.os.Bundle;
-
-/**
- * Interface for the client-provided callback on user navigation.
- */
-interface IBrowserConnectionCallback {
-    /**
-     * To be called when the user triggers an external navigation.
-     *
-     * @param sessionId As returned by {@link IBrowserConnectionService#newSession}.
-     * @param url URL the user has navigated to.
-     * @param extras Reserved for future use.
-     */
-    void onUserNavigation(long sessionId, String url, in Bundle extras);
-}
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/RecentTabsPage.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/RecentTabsPage.java
index decca49..5275518 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/RecentTabsPage.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/RecentTabsPage.java
@@ -58,6 +58,11 @@
     private boolean mInForeground;
 
     /**
+     * Whether {@link #mView} is attached to the application window.
+     */
+    private boolean mIsAttachedToWindow;
+
+    /**
      * The time, whichever is most recent, that the page:
      * - Moved to the foreground
      * - Became visible
@@ -103,10 +108,9 @@
      * Updates whether the page is in the foreground based on whether the application is in the
      * foreground and whether {@link #mView} is attached to the application window. If the page is
      * no longer in the foreground, records the time that the page spent in the foreground to UMA.
-     * @param isAttachedToWindow whether {@link #mView} is attached to the application window.
      */
-    private void updateForegroundState(boolean isAttachedToWindow) {
-        boolean inForeground = isAttachedToWindow
+    private void updateForegroundState() {
+        boolean inForeground = mIsAttachedToWindow
                 && ApplicationStatus.getStateForActivity(mActivity) == ActivityState.RESUMED;
         if (mInForeground == inForeground) {
             return;
@@ -170,7 +174,7 @@
     public void onActivityStateChange(Activity activity, int state) {
         // Called when the user locks the screen or moves Chrome to the background via the task
         // switcher.
-        updateForegroundState(mView.isAttachedToWindow());
+        updateForegroundState();
     }
 
     // View.OnAttachStateChangeListener
@@ -178,16 +182,15 @@
     public void onViewAttachedToWindow(View view) {
         // Called when the user opens the RecentTabsPage or switches back to the RecentTabsPage from
         // another tab.
-        updateForegroundState(true);
+        mIsAttachedToWindow = true;
+        updateForegroundState();
     }
 
     @Override
     public void onViewDetachedFromWindow(View view) {
         // Called when the user navigates from the RecentTabsPage or switches to another tab.
-        // The value of {@link View#isAttachedToWindow()} changes after the
-        // {@link View.OnAttachStateChangeListener#onViewDetachedFromWindow()} listeners are
-        // notified.
-        updateForegroundState(false);
+        mIsAttachedToWindow = false;
+        updateForegroundState();
     }
 
     // ExpandableListView.OnChildClickedListener
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/omaha/OmahaUpdateInfobar.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/omaha/OmahaUpdateInfobar.java
index 46a5978..300e675 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/omaha/OmahaUpdateInfobar.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/omaha/OmahaUpdateInfobar.java
@@ -34,10 +34,10 @@
     private static final int ACTION_DISMISSED = 3;
     private static final int ACTION_MAX = 3;
 
-    private String mUrl;
-    private Context mActivityContext;
+    private final String mUrl;
+    private final Context mActivityContext;
     private boolean mActionTaken;
-    private long mShownTime;
+    private final long mShownTime;
 
     /**
      * Listens for the InfoBar being dismissed and checks whether it was caused by a user action
@@ -65,8 +65,8 @@
 
     public OmahaUpdateInfobar(Context activityContext, String message, String buttonMessage,
                 String url) {
-        super(0, new DismissListener(), R.drawable.infobar_warning, null, message, null,
-                buttonMessage, null);
+        super(new DismissListener(), R.drawable.infobar_warning, null, message, null, buttonMessage,
+                null);
         mActivityContext = activityContext;
         mUrl = url;
         mShownTime = SystemClock.uptimeMillis();
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index 32190450..ca8b5e6 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -790,10 +790,10 @@
         mContextualMenuBar.setCustomSelectionActionModeCallback(
                 new CustomSelectionActionModeCallback() {
                     @Override
-                    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
-                        super.onPrepareActionMode(mode, menu);
+                    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+                        boolean retVal = super.onCreateActionMode(mode, menu);
                         mode.getMenuInflater().inflate(R.menu.textselectionmenu, menu);
-                        return true;
+                        return retVal;
                     }
 
                     @Override
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/snackbar/LoFiBarPopupController.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/snackbar/LoFiBarPopupController.java
index bff657bd24..53f3b28 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/snackbar/LoFiBarPopupController.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/snackbar/LoFiBarPopupController.java
@@ -9,6 +9,7 @@
 import com.google.android.apps.chrome.R;
 
 import org.chromium.chrome.browser.Tab;
+import org.chromium.chrome.browser.preferences.bandwidth.DataReductionProxyUma;
 
 /**
  * Each time a tab loads with Lo-Fi this controller saves that tab id and title to the stack of
@@ -41,6 +42,8 @@
                 null, mContext.getString(R.string.data_reduction_lo_fi_snackbar_message),
                 mContext.getString(R.string.data_reduction_lo_fi_snackbar_action),
                 tab.getId(), this);
+        DataReductionProxyUma.dataReductionProxyLoFiUIAction(
+                DataReductionProxyUma.ACTION_LOAD_IMAGES_SNACKBAR_SHOWN);
     }
 
     /**
@@ -58,6 +61,8 @@
         mSnackbarManager.dismissSnackbar(false);
         mTab.stopLoading();
         mTab.reloadIgnoringCache();
+        DataReductionProxyUma.dataReductionProxyLoFiUIAction(
+                DataReductionProxyUma.ACTION_LOAD_IMAGES_SNACKBAR_CLICKED);
     }
 
     @Override
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/tab/ThumbnailTabHelper.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/tab/ThumbnailTabHelper.java
index e483b1f..7ef07215 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/tab/ThumbnailTabHelper.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/tab/ThumbnailTabHelper.java
@@ -111,7 +111,7 @@
         }
 
         @Override
-        public void onPageLoadStarted(Tab tab) {
+        public void onPageLoadStarted(Tab tab, String url) {
             cancelThumbnailCapture();
             mThumbnailCapturedForLoad = false;
         }
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
index f18ab31..80ca244 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
@@ -146,13 +146,7 @@
         }
     }
 
-    /**
-     * Creates a tab around the native web contents pointer.
-     * @param webContents The web contents to create a tab around.
-     * @param parentId    The id of the parent tab.
-     * @param type        The TabLaunchType describing how this tab was created.
-     * @return            The created tab.
-     */
+    @Override
     public ChromeTab createTabWithWebContents(WebContents webContents, int parentId,
             TabLaunchType type) {
         TabModel model = mTabModel;
@@ -178,24 +172,14 @@
     public Tab launchNTP() {
         try {
             TraceEvent.begin("ChromeTabCreator.launchNTP");
-            ChromeTab tab = launchUrl(UrlConstants.NTP_URL,
-                    TabModel.TabLaunchType.FROM_MENU_OR_OVERVIEW);
-            return tab;
+            return launchUrl(UrlConstants.NTP_URL, TabModel.TabLaunchType.FROM_MENU_OR_OVERVIEW);
         } finally {
             TraceEvent.end("ChromeTabCreator.launchNTP");
         }
     }
 
-    /**
-     * Creates a new tab and loads the specified URL in it. This is a convenience method for
-     * {@link #createNewTab} with the default {@link LoadUrlParams} and no parent tab.
-     *
-     * @param url the URL to open.
-     * @param type the type of action that triggered that launch. Determines how the tab is opened
-     *             (for example, in the foreground or background).
-     * @return the created tab.
-     */
-    public ChromeTab launchUrl(String url, TabModel.TabLaunchType type) {
+    @Override
+    public Tab launchUrl(String url, TabModel.TabLaunchType type) {
         return launchUrl(url, type, null, 0);
     }
 
@@ -210,7 +194,7 @@
      * @param intentTimestamp the time the intent was received.
      * @return the created tab.
      */
-    public ChromeTab launchUrl(String url, TabModel.TabLaunchType type, Intent intent,
+    public Tab launchUrl(String url, TabModel.TabLaunchType type, Intent intent,
             long intentTimestamp) {
         LoadUrlParams loadUrlParams = new LoadUrlParams(url);
         loadUrlParams.setIntentReceivedTimestamp(intentTimestamp);
@@ -231,7 +215,7 @@
      * @param intentTimestamp the time the intent was received.
      * @return the tab the URL was opened in, could be a new tab or a reused one.
      */
-    public ChromeTab launchUrlFromExternalApp(String url, String referer, String headers,
+    public Tab launchUrlFromExternalApp(String url, String referer, String headers,
             String appId, boolean forceNewTab, Intent intent, long intentTimestamp) {
         assert !mIncognito;
         boolean isLaunchedFromChrome = TextUtils.equals(appId, mActivity.getPackageName());
@@ -271,7 +255,7 @@
         }
 
         // No tab for that app, we'll have to create a new one.
-        ChromeTab tab = launchUrl(url, TabLaunchType.FROM_EXTERNAL_APP, intent, intentTimestamp);
+        Tab tab = launchUrl(url, TabLaunchType.FROM_EXTERNAL_APP, intent, intentTimestamp);
         tab.setAppAssociatedWith(appId);
         return tab;
     }
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
index c4cee23..75090cf 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorImpl.java
@@ -52,6 +52,9 @@
 
     private CloseAllTabsDelegate mCloseAllTabsDelegate;
 
+    private ChromeTabCreator mRegularTabCreator;
+    private ChromeTabCreator mIncognitoTabCreator;
+
     private static class TabModelImplCreator implements OffTheRecordTabModelDelegate {
         private final ChromeActivity mActivity;
         private final TabModelSelectorUma mUma;
@@ -124,11 +127,11 @@
         mTabSaver = new TabPersistentStore(this, selectorIndex, mActivity, mActivity,
                 persistentStoreObserver);
         mOrderController = new TabModelOrderController(this);
-        ChromeTabCreator regularTabCreator = new ChromeTabCreator(mActivity, windowAndroid,
-                mOrderController, mTabSaver, false);
-        ChromeTabCreator incognitoTabCreator = new ChromeTabCreator(mActivity, windowAndroid,
-                mOrderController, mTabSaver, true);
-        mActivity.setTabCreators(regularTabCreator, incognitoTabCreator);
+        mRegularTabCreator = new ChromeTabCreator(
+                mActivity, windowAndroid, mOrderController, mTabSaver, false);
+        mIncognitoTabCreator = new ChromeTabCreator(
+                mActivity, windowAndroid, mOrderController, mTabSaver, true);
+        mActivity.setTabCreators(mRegularTabCreator, mIncognitoTabCreator);
     }
 
     @Override
@@ -182,8 +185,8 @@
         TabModel incognitoModel = new OffTheRecordTabModel(new TabModelImplCreator(
                 mActivity, mUma, mOrderController, mTabContentManager, mTabSaver, this));
         initialize(isIncognitoSelected(), normalModel, incognitoModel);
-        mActivity.getTabCreator(false).setTabModel(normalModel, mTabContentManager);
-        mActivity.getTabCreator(true).setTabModel(incognitoModel, mTabContentManager);
+        mRegularTabCreator.setTabModel(normalModel, mTabContentManager);
+        mIncognitoTabCreator.setTabModel(incognitoModel, mTabContentManager);
 
         mTabSaver.setTabContentManager(tabContentProvider);
 
@@ -214,10 +217,10 @@
             }
 
             @Override
-            public void onPageLoadStarted(Tab tab) {
-                String url = tab.getUrl();
-                if (NativePageFactory.isNativePageUrl(url, tab.isIncognito())) {
-                    mTabContentManager.invalidateTabThumbnail(tab.getId(), url);
+            public void onPageLoadStarted(Tab tab, String url) {
+                String previousUrl = tab.getUrl();
+                if (NativePageFactory.isNativePageUrl(previousUrl, tab.isIncognito())) {
+                    mTabContentManager.invalidateTabThumbnail(tab.getId(), previousUrl);
                 } else {
                     mTabContentManager.removeTabThumbnail(tab.getId());
                 }
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/HostedToolbar.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
similarity index 97%
rename from chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/HostedToolbar.java
rename to chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
index 3789897..7f66fcf 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/HostedToolbar.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
@@ -52,9 +52,9 @@
 import org.chromium.ui.base.WindowAndroid;
 
 /**
- * The Toolbar layout to be used for hosted mode. This is used for both phone and tablet UIs.
+ * The Toolbar layout to be used for a custom tab. This is used for both phone and tablet UIs.
  */
-public class HostedToolbar extends ToolbarLayout implements LocationBar {
+public class CustomTabToolbar extends ToolbarLayout implements LocationBar {
     private View mUrlInfoContainer;
     private UrlBar mUrlBar;
     private TextView mTitleBar;
@@ -62,14 +62,14 @@
     private ImageButton mCustomActionButton;
     private int mSecurityIconType;
     private boolean mUseDarkColors;
-    private TintedImageButton mBackButton;
+    private TintedImageButton mReturnButton;
     private Animator mSecurityButtonShowAnimator;
     private boolean mBackgroundColorSet;
 
     /**
      * Constructor for getting this class inflated from an xml layout file.
      */
-    public HostedToolbar(Context context, AttributeSet attrs) {
+    public CustomTabToolbar(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
@@ -86,7 +86,7 @@
         mSecurityButton = (ImageButton) findViewById(R.id.security_button);
         mSecurityIconType = ConnectionSecurityHelperSecurityLevel.NONE;
         mCustomActionButton = (ImageButton) findViewById(R.id.action_button);
-        mBackButton = (TintedImageButton) findViewById(R.id.back_button);
+        mReturnButton = (TintedImageButton) findViewById(R.id.back_button);
         mSecurityButtonShowAnimator = ObjectAnimator.ofFloat(mSecurityButton, ALPHA, 1);
         mSecurityButtonShowAnimator
                 .setDuration(ToolbarPhone.URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
@@ -115,8 +115,8 @@
     }
 
     @Override
-    public void setHostedBackClickHandler(OnClickListener listener) {
-        mBackButton.setOnClickListener(listener);
+    public void setCustomTabReturnClickHandler(OnClickListener listener) {
+        mReturnButton.setOnClickListener(listener);
     }
 
     @Override
@@ -239,7 +239,7 @@
         ColorStateList colorStateList = resources.getColorStateList(mUseDarkColors
                 ? R.color.dark_mode_tint : R.color.light_mode_tint);
         mMenuButton.setTint(colorStateList);
-        mBackButton.setTint(colorStateList);
+        mReturnButton.setTint(colorStateList);
         mUrlBar.setUseDarkTextColors(mUseDarkColors);
 
         int titleTextColor = mUseDarkColors ? resources.getColor(R.color.url_emphasis_default_text)
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/Toolbar.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/Toolbar.java
index 1af6fa9e..699ce9c 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/Toolbar.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/Toolbar.java
@@ -62,10 +62,10 @@
     void setBookmarkClickHandler(OnClickListener listener);
 
     /**
-     * Sets the OnClickListener to notify when the back button is pressed in hosted mode.
+     * Sets the OnClickListener to notify when the back button is pressed in a custom tab.
      * @param listener The callback that will be notified when the back button is pressed.
      */
-    void setHostedBackClickHandler(OnClickListener listener);
+    void setCustomTabReturnClickHandler(OnClickListener listener);
 
     /**
      * Calculates the {@link Rect} that represents the content area of the location bar.  This
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarHelper.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarHelper.java
index 5cca213..d042382f 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarHelper.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarHelper.java
@@ -149,7 +149,7 @@
             OnClickListener tabSwitcherClickHandler,
             OnClickListener newTabClickHandler,
             OnClickListener bookmarkClickHandler,
-            OnClickListener hostedBackClickHandler) {
+            OnClickListener customTabsBackClickHandler) {
 
 
         TabModelSelector selector = mActivity.getTabModelSelector();
@@ -176,7 +176,7 @@
         mToolbar.setOnTabSwitcherClickHandler(tabSwitcherClickHandler);
         mToolbar.setOnNewTabClickHandler(newTabClickHandler);
         mToolbar.setBookmarkClickHandler(bookmarkClickHandler);
-        mToolbar.setHostedBackClickHandler(hostedBackClickHandler);
+        mToolbar.setCustomTabReturnClickHandler(customTabsBackClickHandler);
         mInitialized = true;
     }
 
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
index 0b0d389..b15333f 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
@@ -248,7 +248,7 @@
     public void setBookmarkClickHandler(OnClickListener listener) { }
 
     @Override
-    public void setHostedBackClickHandler(OnClickListener listener) { }
+    public void setCustomTabReturnClickHandler(OnClickListener listener) { }
 
     /**
      * Gives inheriting classes the chance to update the visibility of the
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 6df7ded6..7cb6e7a 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -225,7 +225,7 @@
             }
 
             @Override
-            public void onPageLoadStarted(Tab tab) {
+            public void onPageLoadStarted(Tab tab, String url) {
                 updateButtonStatus();
                 updateTabLoadingState(true, true);
             }
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index 55a0124e..adb8aab17 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -1080,12 +1080,18 @@
         // called.  The alpha is being used prior to getting to draw(...), so updating the value
         // after this point was having no affect.
         if (mTextureCaptureMode) assert getAlpha() == 1f;
-        if (!mTextureCaptureMode && mClipRect != null) {
+
+        // mClipRect can change in the draw call, so cache this value to ensure the canvas is
+        // restored correctly.
+        boolean shouldClip = !mTextureCaptureMode && mClipRect != null;
+        if (shouldClip) {
             canvas.save();
             canvas.clipRect(mClipRect);
         }
         super.draw(canvas);
-        if (!mTextureCaptureMode && mClipRect != null) canvas.restore();
+        if (shouldClip) {
+            canvas.restore();
+        }
     }
 
     @Override
@@ -1620,6 +1626,8 @@
 
     @Override
     protected void onPrimaryColorChanged() {
+        if (!getToolbarDataProvider().isUsingBrandColor()) return;
+
         super.onPrimaryColorChanged();
         if (mBrandColorTransitionActive) mBrandColorTransitionAnimation.cancel();
         if (!isVisualStateValidForBrandColorTransition(mVisualState)) {
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/emptybackground/EmptyBackgroundViewTablet.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/emptybackground/EmptyBackgroundViewTablet.java
index b2ed0f43..bdabb0b 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/emptybackground/EmptyBackgroundViewTablet.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/emptybackground/EmptyBackgroundViewTablet.java
@@ -19,7 +19,7 @@
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.browser.appmenu.AppMenuButtonHelper;
 import org.chromium.chrome.browser.appmenu.AppMenuHandler;
-import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager.TabCreator;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.widget.incognitotoggle.IncognitoToggleButtonTablet;
 import org.chromium.ui.UiUtils;
@@ -32,7 +32,7 @@
     private static final int ANIMATE_DURATION_MS = 200;
 
     private TabModelSelector mTabModelSelector;
-    private ChromeTabCreator mTabCreator;
+    private TabCreator mTabCreator;
 
     private Animator mCurrentTransitionAnimation;
 
@@ -80,10 +80,10 @@
     }
 
     /**
-     * Sets the {@link ChromeTabCreator} that will be used to open the New Tab Page.
-     * @param tabCreator A {@link ChromeTabCreator} to open the New Tab Page.
+     * Sets the {@link TabCreator} that will be used to open the New Tab Page.
+     * @param tabCreator A {@link TabCreator} to open the New Tab Page.
      */
-    public void setTabCreator(ChromeTabCreator tabCreator) {
+    public void setTabCreator(TabCreator tabCreator) {
         mTabCreator = tabCreator;
     }
 
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/emptybackground/EmptyBackgroundViewWrapper.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/emptybackground/EmptyBackgroundViewWrapper.java
index 1241501..79b102d 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/emptybackground/EmptyBackgroundViewWrapper.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/emptybackground/EmptyBackgroundViewWrapper.java
@@ -14,9 +14,9 @@
 import org.chromium.chrome.browser.Tab;
 import org.chromium.chrome.browser.appmenu.AppMenuHandler;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
-import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager.TabCreator;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModelObserver;
@@ -31,7 +31,7 @@
 public class EmptyBackgroundViewWrapper {
     private final Activity mActivity;
     private final TabModelSelector mTabModelSelector;
-    private final ChromeTabCreator mTabCreator;
+    private final TabCreator mTabCreator;
     private final TabModelObserver mTabModelObserver;
     private final TabModelSelectorObserver mTabModelSelectorObserver;
     private final OverviewModeBehavior mOverviewModeBehavior;
@@ -43,15 +43,14 @@
      * Creates a {@link EmptyBackgroundViewWrapper} instance that will lazily inflate.
      * @param selector             A {@link TabModelSelector} that will be used to query system
      *                             state.
-     * @param tabCreator           A {@link ChromeTabCreator} that will be used to open the New Tab
-     *                             Page.
+     * @param tabCreator           A {@link TabCreator} that will be used to open the New Tab Page.
      * @param activity             An {@link Activity} that represents a parent of the
      *                             {@link android.view.ViewStub}.
      * @param menuHandler          A {@link AppMenuHandler} to handle menu touch events.
      * @param overviewModeBehavior A {@link OverviewModeBehavior} instance to detect when the app
      *                             is in overview mode.
      */
-    public EmptyBackgroundViewWrapper(TabModelSelector selector, ChromeTabCreator tabCreator,
+    public EmptyBackgroundViewWrapper(TabModelSelector selector, TabCreator tabCreator,
             Activity activity, AppMenuHandler menuHandler,
             OverviewModeBehavior overviewModeBehavior) {
         mActivity = activity;
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
index 576b8e7..068fb1b 100644
--- a/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
@@ -129,7 +129,7 @@
 
         mTabObserver = new EmptyTabObserver() {
             @Override
-            public void onPageLoadStarted(Tab tab) {
+            public void onPageLoadStarted(Tab tab, String url) {
                 deactivate();
             }
 
diff --git a/chrome/android/javatests/AndroidManifest.xml b/chrome/android/javatests/AndroidManifest.xml
index 4355f76f..3b69261 100644
--- a/chrome/android/javatests/AndroidManifest.xml
+++ b/chrome/android/javatests/AndroidManifest.xml
@@ -30,9 +30,9 @@
         <activity android:name="org.chromium.test.broker.OnDeviceInstrumentationBroker"
             android:exported="true"/>
 
-        <receiver android:name="org.chromium.chrome.browser.hosted.HostedActivityTest$DummyBroadcastReceiver">
+        <receiver android:name="org.chromium.chrome.browser.customtabs.CustomTabsActivityTest$DummyBroadcastReceiver">
             <intent-filter>
-                <action android:name="org.chromium.chrome.browser.hosted.TEST_PENDING_INTENT_SENT" >
+                <action android:name="org.chromium.chrome.browser.customtabs.TEST_PENDING_INTENT_SENT" >
                 </action>
             </intent-filter>
         </receiver>
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java
index 9ceb1636..1d529a97 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/BindingManagerIntegrationTest.java
@@ -12,7 +12,7 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
-import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager.TabCreator;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
@@ -117,7 +117,7 @@
             @Override
             public void run() {
                 // Foreground tab.
-                ChromeTabCreator tabCreator = getActivity().getCurrentTabCreator();
+                TabCreator tabCreator = getActivity().getCurrentTabCreator();
                 tabs[0] = tabCreator.createNewTab(
                         new LoadUrlParams(TestHttpServerClient.getUrl(FILE_PATH)),
                                 TabLaunchType.FROM_KEYBOARD, null);
@@ -189,7 +189,7 @@
             @Override
             public void run() {
                 // Foreground tab.
-                ChromeTabCreator tabCreator = getActivity().getCurrentTabCreator();
+                TabCreator tabCreator = getActivity().getCurrentTabCreator();
                 tabs[0] = tabCreator.createNewTab(
                         new LoadUrlParams(TestHttpServerClient.getUrl(FILE_PATH)),
                                 TabLaunchType.FROM_KEYBOARD, null);
@@ -301,7 +301,7 @@
                 new Callable<Tab>() {
                     @Override
                     public Tab call() throws Exception {
-                        ChromeTabCreator tabCreator = getActivity().getCurrentTabCreator();
+                        TabCreator tabCreator = getActivity().getCurrentTabCreator();
                         return tabCreator.createNewTab(
                                 new LoadUrlParams(TestHttpServerClient.getUrl(FILE_PATH)),
                                         TabLaunchType.FROM_KEYBOARD, null);
@@ -373,7 +373,7 @@
                 new Callable<Tab>() {
                     @Override
                     public Tab call() {
-                        ChromeTabCreator tabCreator = getActivity().getCurrentTabCreator();
+                        TabCreator tabCreator = getActivity().getCurrentTabCreator();
                         return tabCreator.createNewTab(
                                 new LoadUrlParams(TestHttpServerClient.getUrl(FILE_PATH)),
                                         TabLaunchType.FROM_KEYBOARD, null);
@@ -406,7 +406,7 @@
                 new Callable<Tab>() {
                     @Override
                     public Tab call() {
-                        ChromeTabCreator tabCreator = getActivity().getCurrentTabCreator();
+                        TabCreator tabCreator = getActivity().getCurrentTabCreator();
                         Tab tab = tabCreator.createNewTab(
                                 new LoadUrlParams(TestHttpServerClient.getUrl(FILE_PATH)),
                                         TabLaunchType.FROM_LONGPRESS_BACKGROUND, null);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
index ee77b9e..b544c3b5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
@@ -134,6 +134,34 @@
     }
 
     /**
+     * Test Opening a link and verify that TabObserver#onPageLoadStarted gives the old and new URL.
+     * Bug: crbug.com/171037
+     * @MediumTest
+     * @Feature({"Navigation"})
+     */
+    @FlakyTest
+    public void testTabObserverOnPageLoadStarted() throws InterruptedException, TimeoutException {
+        final String url1 = TestHttpServerClient.getUrl("chrome/test/data/android/google.html");
+        final String url2 = TestHttpServerClient.getUrl("chrome/test/data/android/about.html");
+
+        typeInOmniboxAndNavigate(url1);
+        assertEquals(url1, getActivity().getActivityTab().getUrl());
+        TabObserver onPageLoadStartedObserver = new EmptyTabObserver() {
+            @Override
+            public void onPageLoadStarted(Tab tab, String url) {
+                tab.removeObserver(this);
+                assertEquals(tab.getUrl(), url1);
+                assertEquals(url, url2);
+            }
+        };
+        Tab tab = getActivity().getActivityTab();
+        tab.addObserver(onPageLoadStartedObserver);
+        DOMUtils.clickNode(this, tab.getContentViewCore(), "aboutLink");
+        ChromeTabUtils.waitForTabPageLoaded(tab, url2);
+        assertEquals("Desired Link not open", url2, getActivity().getActivityTab().getUrl());
+    }
+
+    /**
      * Test re-direct functionality for a web-page.
      * @throws Exception
      */
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 ec11bca..2e1e181b 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
@@ -734,10 +734,12 @@
 
     /**
      * Tests tap to expand, after an initial tap to activate the peeking card.
+     *
+     * @SmallTest
+     * @Feature({"ContextualSearch"})
      */
-    @SmallTest
-    @Feature({"ContextualSearch"})
     @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+    @FlakyTest
     public void testTapExpand() throws InterruptedException, TimeoutException {
         assertNoSearchesLoaded();
         clickWordNode("states");
@@ -1603,10 +1605,11 @@
 
     /**
      * Tests the promo open counter.
+     * @SmallTest
+     * @Feature({"ContextualSearch"})
      */
-    @SmallTest
-    @Feature({"ContextualSearch"})
     @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+    @FlakyTest
     public void testPromoOpenCountForUndecided() throws InterruptedException, TimeoutException {
         mPolicy.overrideDecidedStateForTesting(false);
 
@@ -1645,9 +1648,13 @@
     // --------------------------------------------------------------------------------------------
     // Tap count - number of taps between opens.
     // --------------------------------------------------------------------------------------------
-    @SmallTest
-    @Feature({"ContextualSearch"})
+    /**
+     * Tests the counter for the number of taps between opens.
+     * @SmallTest
+     * @Feature({"ContextualSearch"})
+     */
     @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE})
+    @FlakyTest
     public void testTapCount() throws InterruptedException, TimeoutException {
         assertEquals(0, mPolicy.getTapCount());
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/hosted/HostedActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
similarity index 85%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/hosted/HostedActivityTest.java
rename to chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index 7e70440..77798c1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/hosted/HostedActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -2,7 +2,7 @@
 // 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.hosted;
+package org.chromium.chrome.browser.customtabs;
 
 import android.app.Activity;
 import android.app.Instrumentation;
@@ -38,9 +38,9 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
- * Instrumentation tests for {@link HostedActivity}.
+ * Instrumentation tests for {@link CustomTabActivity}.
  */
-public class HostedActivityTest extends ChromeActivityTestCaseBase<HostedActivity> {
+public class CustomTabActivityTest extends ChromeActivityTestCaseBase<CustomTabActivity> {
 
     /**
      * An empty {@link BroadcastReceiver} that exists only to make the PendingIntent to carry an
@@ -60,15 +60,15 @@
     }
 
     private static final String
-            TEST_ACTION = "org.chromium.chrome.browser.hosted.TEST_PENDING_INTENT_SENT";
+            TEST_ACTION = "org.chromium.chrome.browser.customtabs.TEST_PENDING_INTENT_SENT";
     private static final String TEST_PAGE = TestHttpServerClient.getUrl(
             "chrome/test/data/android/google.html");
     private static final String TEST_MENU_TITLE = "testMenuTitle";
 
-    private HostedActivity mActivity;
+    private CustomTabActivity mActivity;
 
-    public HostedActivityTest() {
-        super(HostedActivity.class);
+    public CustomTabActivityTest() {
+        super(CustomTabActivity.class);
     }
 
     @Override
@@ -78,17 +78,18 @@
     @Override
     protected void startActivityCompletely(Intent intent) {
         Instrumentation.ActivityMonitor monitor = getInstrumentation().addMonitor(
-                HostedActivity.class.getName(), null, false);
+                CustomTabActivity.class.getName(), null, false);
         Activity activity = getInstrumentation().startActivitySync(intent);
         assertNotNull("Main activity did not start", activity);
-        HostedActivity hostedActivity = (HostedActivity) monitor.waitForActivityWithTimeout(
+        CustomTabActivity customTabActivity =
+                (CustomTabActivity) monitor.waitForActivityWithTimeout(
                 ACTIVITY_START_TIMEOUT_MS);
-        assertNotNull("HostedActivity did not start", hostedActivity);
-        setActivity(hostedActivity);
-        mActivity = hostedActivity;
+        assertNotNull("CustomTabActivity did not start", customTabActivity);
+        setActivity(customTabActivity);
+        mActivity = customTabActivity;
     }
 
-    private void startHostedActivityWithIntent(Intent intent) throws InterruptedException {
+    private void startCustomTabActivityWithIntent(Intent intent) throws InterruptedException {
         startActivityCompletely(intent);
         assertTrue("Tab never selected/initialized.",
                 CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
@@ -113,14 +114,14 @@
 
     /**
      * Creates the simplest intent that is sufficient to let {@link ChromeLauncherActivity} launch
-     * the {@link HostedActivity}.
+     * the {@link CustomTabActivity}.
      */
-    private Intent createMinimalHostedIntent() {
+    private Intent createMinimalCustomTabIntent() {
         Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(TEST_PAGE));
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         intent.setComponent(new ComponentName(getInstrumentation().getTargetContext(),
                 ChromeLauncherActivity.class));
-        intent.putExtra(HostedIntentDataProvider.EXTRA_HOSTED_SESSION_ID, true);
+        intent.putExtra(CustomTabIntentDataProvider.EXTRA_CUSTOM_TABS_SESSION_ID, true);
         return intent;
     }
 
@@ -136,11 +137,11 @@
         PendingIntent pi = PendingIntent.getBroadcast(getInstrumentation().getTargetContext(), 0,
                 menuIntent, 0);
         Bundle bundle = new Bundle();
-        bundle.putString(HostedIntentDataProvider.KEY_HOSTED_MENU_TITLE, TEST_MENU_TITLE);
-        bundle.putParcelable(HostedIntentDataProvider.KEY_HOSTED_PENDING_INTENT, pi);
+        bundle.putString(CustomTabIntentDataProvider.KEY_CUSTOM_TABS_MENU_TITLE, TEST_MENU_TITLE);
+        bundle.putParcelable(CustomTabIntentDataProvider.KEY_CUSTOM_TABS_PENDING_INTENT, pi);
         ArrayList<Bundle> menuItems = new ArrayList<Bundle>();
         menuItems.add(bundle);
-        intent.putParcelableArrayListExtra(HostedIntentDataProvider.EXTRA_HOSTED_MENU_ITEMS,
+        intent.putParcelableArrayListExtra(CustomTabIntentDataProvider.EXTRA_CUSTOM_TABS_MENU_ITEMS,
                 menuItems);
         return pi;
     }
@@ -163,7 +164,7 @@
 
     @SmallTest
     public void testContextMenuEntriesForImage() throws InterruptedException, TimeoutException {
-        startHostedActivityWithIntent(createMinimalHostedIntent());
+        startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
 
         final int expectedMenuSize = 4;
         Menu menu = ContextMenuUtils.openContextMenu(this, getActivity().getActivityTab(), "logo");
@@ -176,7 +177,7 @@
 
     @SmallTest
     public void testContextMenuEntriesForLink() throws InterruptedException, TimeoutException {
-        startHostedActivityWithIntent(createMinimalHostedIntent());
+        startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
 
         final int expectedMenuSize = 3;
         Menu menu = ContextMenuUtils.openContextMenu(this, getActivity().getActivityTab(),
@@ -188,10 +189,10 @@
     }
 
     @SmallTest
-    public void testHostedAppMenu() throws InterruptedException {
-        Intent intent = createMinimalHostedIntent();
+    public void testCustomTabAppMenu() throws InterruptedException {
+        Intent intent = createMinimalCustomTabIntent();
         addMenuEntryToIntent(intent);
-        startHostedActivityWithIntent(intent);
+        startCustomTabActivityWithIntent(intent);
 
         openAppMenuAndAssertMenuShown();
         final int expectedMenuSize = 4;
@@ -207,9 +208,9 @@
 
     @SmallTest
     public void testCustomMenuEntry() throws InterruptedException {
-        Intent intent = createMinimalHostedIntent();
+        Intent intent = createMinimalCustomTabIntent();
         final PendingIntent pi = addMenuEntryToIntent(intent);
-        startHostedActivityWithIntent(intent);
+        startCustomTabActivityWithIntent(intent);
 
         final OnFinishedForTest onFinished = new OnFinishedForTest(pi);
         mActivity.getIntentDataProvider().setMenuSelectionOnFinishedForTesting(onFinished);
@@ -235,7 +236,7 @@
 
     @SmallTest
     public void testOpenInChrome() throws InterruptedException {
-        startHostedActivityWithIntent(createMinimalHostedIntent());
+        startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
 
         boolean isDocumentMode = FeatureUtilities.isDocumentMode(
                 getInstrumentation().getTargetContext());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java
index d9db0443..2c9741f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeTest.java
@@ -883,7 +883,7 @@
 
                 newTab.addObserver(new EmptyTabObserver() {
                     @Override
-                    public void onPageLoadStarted(Tab tab) {
+                    public void onPageLoadStarted(Tab tab, String url) {
                         newTab.removeObserver(this);
                         tabLoadStartedCallback.notifyCalled();
                     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java
index 447196e..1a006a1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java
@@ -7,6 +7,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import org.chromium.base.ApplicationState;
 import org.chromium.base.ApplicationStatus;
@@ -32,6 +33,7 @@
         mContext = getInstrumentation().getTargetContext();
     }
 
+    @SmallTest
     public void testLaunchWithUrlNoScheme() throws Exception {
         Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("www.google.com"));
         intent.setClassName(mContext.getPackageName(), ChromeLauncherActivity.class.getName());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java
index f7894b0..22312e1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java
@@ -143,9 +143,11 @@
 
     /**
      * Test for interstitial page loads resetting brand color.
+     * http://crbug.com/497866
+     * @SmallTest
+     * @Feature({"Omnibox"})
      */
-    @SmallTest
-    @Feature({"Omnibox"})
+    @FlakyTest
     public void testBrandColorInterstitial() throws InterruptedException {
         final String brandColorUrl = getUrlWithBrandColor(BRAND_COLOR_1);
         startMainActivityWithURL(brandColorUrl);
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/NavigationPopupTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/NavigationPopupTest.java
index 7c15b61..1c37788 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/NavigationPopupTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/NavigationPopupTest.java
@@ -183,6 +183,24 @@
         public boolean removeEntryAtIndex(int index) {
             return false;
         }
+
+        @Override
+        public boolean canCopyStateOver() {
+            return false;
+        }
+
+        @Override
+        public boolean canPruneAllButLastCommitted() {
+            return false;
+        }
+
+        @Override
+        public void copyStateFrom(NavigationController source) {
+        }
+
+        @Override
+        public void copyStateFromAndPrune(NavigationController source, boolean replaceEntry) {
+        }
     }
 
     @MediumTest
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollectorTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollectorTest.java
index ec5ccdc..f5860c1 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollectorTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/feedback/ConnectivityCheckerCollectorTest.java
@@ -5,12 +5,17 @@
 package org.chromium.chrome.browser.feedback;
 
 import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.browser.feedback.ConnectivityCheckerCollector.FeedbackData;
+import org.chromium.chrome.browser.feedback.ConnectivityCheckerCollector.Result;
+import org.chromium.chrome.browser.feedback.ConnectivityCheckerCollector.Type;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 
+import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
@@ -25,8 +30,7 @@
 
     @MediumTest
     public void testNormalCaseShouldWork() throws Exception {
-        final AtomicReference<Future<Map<ConnectivityCheckerCollector.Type,
-                ConnectivityCheckerCollector.Result>>> resultFuture = new AtomicReference<>();
+        final AtomicReference<Future<FeedbackData>> resultFuture = new AtomicReference<>();
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
@@ -45,21 +49,20 @@
             }
         }, TIMEOUT_MS, RESULT_CHECK_INTERVAL_MS);
         assertTrue("Should be finished by now.", gotResult);
-        Map<ConnectivityCheckerCollector.Type, ConnectivityCheckerCollector.Result> result =
-                getResult(resultFuture);
+        FeedbackData feedback = getResult(resultFuture);
+        Map<Type, Result> result = feedback.getConnections();
         assertEquals("Should have 4 results.", 4, result.size());
-        for (Map.Entry<ConnectivityCheckerCollector.Type, ConnectivityCheckerCollector.Result> re :
-                result.entrySet()) {
+        for (Map.Entry<Type, Result> re : result.entrySet()) {
             switch (re.getKey()) {
                 case CHROME_HTTP:
                 case SYSTEM_HTTP:
-                    assertEquals("Wrong result for " + re.getKey(),
-                            ConnectivityCheckerCollector.Result.CONNECTED, re.getValue());
+                    assertEquals(
+                            "Wrong result for " + re.getKey(), Result.CONNECTED, re.getValue());
                     break;
                 case CHROME_HTTPS:
                 case SYSTEM_HTTPS:
-                    assertEquals("Wrong result for " + re.getKey(),
-                            ConnectivityCheckerCollector.Result.NOT_CONNECTED, re.getValue());
+                    assertEquals(
+                            "Wrong result for " + re.getKey(), Result.NOT_CONNECTED, re.getValue());
                     break;
                 default:
                     fail("Failed to recognize type " + re.getKey());
@@ -69,8 +72,7 @@
 
     @MediumTest
     public void testTwoTimeoutsShouldFillInTheRest() throws Exception {
-        final AtomicReference<Future<Map<ConnectivityCheckerCollector.Type,
-                ConnectivityCheckerCollector.Result>>> resultFuture = new AtomicReference<>();
+        final AtomicReference<Future<FeedbackData>> resultFuture = new AtomicReference<>();
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
@@ -89,22 +91,20 @@
             }
         }, TIMEOUT_MS / 5, RESULT_CHECK_INTERVAL_MS);
         assertFalse("Should not be finished by now.", gotResult);
-        Map<ConnectivityCheckerCollector.Type, ConnectivityCheckerCollector.Result> result =
-                getResult(resultFuture);
+        FeedbackData feedback = getResult(resultFuture);
+        Map<Type, Result> result = feedback.getConnections();
 
         assertEquals("Should have 4 results.", 4, result.size());
-        for (Map.Entry<ConnectivityCheckerCollector.Type, ConnectivityCheckerCollector.Result> re :
-                result.entrySet()) {
+        for (Map.Entry<Type, Result> re : result.entrySet()) {
             switch (re.getKey()) {
                 case CHROME_HTTP:
                 case SYSTEM_HTTP:
-                    assertEquals("Wrong result for " + re.getKey(),
-                            ConnectivityCheckerCollector.Result.CONNECTED, re.getValue());
+                    assertEquals(
+                            "Wrong result for " + re.getKey(), Result.CONNECTED, re.getValue());
                     break;
                 case CHROME_HTTPS:
                 case SYSTEM_HTTPS:
-                    assertEquals("Wrong result for " + re.getKey(),
-                            ConnectivityCheckerCollector.Result.UNKNOWN, re.getValue());
+                    assertEquals("Wrong result for " + re.getKey(), Result.UNKNOWN, re.getValue());
                     break;
                 default:
                     fail("Failed to recognize type " + re.getKey());
@@ -112,11 +112,31 @@
         }
     }
 
-    private static Map<ConnectivityCheckerCollector.Type, ConnectivityCheckerCollector.Result>
-            getResult(final AtomicReference<Future<Map<ConnectivityCheckerCollector.Type,
-            ConnectivityCheckerCollector.Result>>> resultFuture) {
-        final AtomicReference<Map<ConnectivityCheckerCollector.Type,
-                ConnectivityCheckerCollector.Result>> result = new AtomicReference<>();
+    @SmallTest
+    public void testFeedbackDataConversion() {
+        Map<Type, Result> connectionMap = new HashMap<>();
+        connectionMap.put(Type.CHROME_HTTP, Result.NOT_CONNECTED);
+        connectionMap.put(Type.CHROME_HTTPS, Result.CONNECTED);
+        connectionMap.put(Type.SYSTEM_HTTP, Result.UNKNOWN);
+        connectionMap.put(Type.SYSTEM_HTTPS, Result.CONNECTED);
+
+        FeedbackData feedback = new FeedbackData(connectionMap);
+        Map<String, String> map = feedback.toMap();
+
+        assertEquals("Should have 4 entries.", 4, map.size());
+        assertTrue(map.containsKey("CHROME_HTTP"));
+        assertEquals("NOT_CONNECTED", map.get("CHROME_HTTP"));
+        assertTrue(map.containsKey("CHROME_HTTPS"));
+        assertEquals("CONNECTED", map.get("CHROME_HTTPS"));
+        assertTrue(map.containsKey("SYSTEM_HTTP"));
+        assertEquals("UNKNOWN", map.get("SYSTEM_HTTP"));
+        assertTrue(map.containsKey("SYSTEM_HTTPS"));
+        assertEquals("CONNECTED", map.get("SYSTEM_HTTPS"));
+    }
+
+    private static FeedbackData getResult(
+            final AtomicReference<Future<FeedbackData>> resultFuture) {
+        final AtomicReference<FeedbackData> result = new AtomicReference<>();
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTest.java
index c44b620e..683faa4 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/search_engines/TemplateUrlServiceTest.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.search_engines;
 
+import android.net.Uri;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import org.chromium.base.ThreadUtils;
@@ -15,6 +16,8 @@
 import org.chromium.content.browser.test.util.CriteriaHelper;
 
 import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
@@ -24,6 +27,18 @@
  */
 public class TemplateUrlServiceTest extends ChromeShellTestBase {
 
+    private static final String QUERY_PARAMETER = "q";
+    private static final String QUERY_VALUE = "cat";
+
+    private static final String ALTERNATIVE_PARAMETER = "ctxsl_alternate_term";
+    private static final String ALTERNATIVE_VALUE = "lion";
+
+    private static final String VERSION_PARAMETER = "ctxs";
+    private static final String VERSION_VALUE = "2";
+
+    private static final String PREFETCH_PARAMETER = "pf";
+    private static final String PREFETCH_VALUE = "c";
+
     @Override
     public void setUp() throws Exception {
         super.setUp();
@@ -32,6 +47,48 @@
     }
 
     @SmallTest
+    @Feature({"ContextualSearch"})
+    public void testUrlForContextualSearchQueryValid()
+            throws InterruptedException, ExecutionException {
+        waitForTemplateUrlServiceToLoad();
+
+        final AtomicBoolean loadedResult = new AtomicBoolean();
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                loadedResult.set(TemplateUrlService.getInstance().isLoaded());
+            }
+        });
+        assertTrue(loadedResult.get());
+
+        validateQuery(QUERY_VALUE, ALTERNATIVE_VALUE, true);
+        validateQuery(QUERY_VALUE, ALTERNATIVE_VALUE, false);
+        validateQuery(QUERY_VALUE, null, true);
+        validateQuery(QUERY_VALUE, null, false);
+    }
+
+    private void validateQuery(final String query, final String alternative, final boolean prefetch)
+            throws ExecutionException {
+        String result = ThreadUtils.runOnUiThreadBlocking(new Callable<String>() {
+            @Override
+            public String call() throws Exception {
+                return TemplateUrlService.getInstance()
+                        .getUrlForContextualSearchQuery(query, alternative, prefetch);
+            }
+        });
+        assertNotNull(result);
+        Uri uri = Uri.parse(result);
+        assertEquals(query, uri.getQueryParameter(QUERY_PARAMETER));
+        assertEquals(alternative, uri.getQueryParameter(ALTERNATIVE_PARAMETER));
+        assertEquals(VERSION_VALUE, uri.getQueryParameter(VERSION_PARAMETER));
+        if (prefetch) {
+            assertEquals(PREFETCH_VALUE, uri.getQueryParameter(PREFETCH_PARAMETER));
+        } else {
+            assertNull(uri.getQueryParameter(PREFETCH_PARAMETER));
+        }
+    }
+
+    @SmallTest
     @Feature({"SearchEngines"})
     public void testLoadUrlService() throws InterruptedException {
         final AtomicBoolean loadedResult = new AtomicBoolean();
@@ -61,7 +118,7 @@
         final TemplateUrlService templateUrlService = waitForTemplateUrlServiceToLoad();
         final AtomicInteger searchEngineIndex = new AtomicInteger();
 
-        // Ensure known state of default search index before running teest.
+        // Ensure known state of default search index before running test.
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
diff --git a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java
index 4c44092..c0f3261 100644
--- a/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java
+++ b/chrome/android/javatests_shell/src/org/chromium/chrome/browser/tabmodel/TabPersistentStoreTest.java
@@ -12,10 +12,13 @@
 import org.chromium.chrome.browser.Tab;
 import org.chromium.chrome.browser.TabState;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager.TabCreator;
+import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabPersistentStore.TabPersistentStoreObserver;
 import org.chromium.chrome.shell.ChromeShellTestBase;
 import org.chromium.chrome.test.util.browser.tabmodel.MockTabModelSelector;
 import org.chromium.content.browser.test.util.CallbackHelper;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.WebContents;
 
 import java.util.ArrayList;
 
@@ -46,6 +49,12 @@
         public int idOfFirstCreatedTab = Tab.INVALID_TAB_ID;
 
         @Override
+        public Tab createNewTab(
+                LoadUrlParams loadUrlParams, TabModel.TabLaunchType type, Tab parent) {
+            return null;
+        }
+
+        @Override
         public void createFrozenTab(TabState state, int id, int index) {
             if (created.size() == 0) idOfFirstCreatedTab = id;
             created.put(id, state);
@@ -53,9 +62,20 @@
         }
 
         @Override
+        public Tab createTabWithWebContents(
+                WebContents webContents, int parentId, TabLaunchType type) {
+            return null;
+        }
+
+        @Override
         public Tab launchNTP() {
             return null;
         }
+
+        @Override
+        public Tab launchUrl(String url, TabModel.TabLaunchType type) {
+            return null;
+        }
     }
 
     private static class MockTabCreatorManager implements TabCreatorManager {
diff --git a/chrome/android/shell/res/drawable/progress_bar.xml b/chrome/android/shell/res/drawable/shell_progress_bar.xml
similarity index 100%
rename from chrome/android/shell/res/drawable/progress_bar.xml
rename to chrome/android/shell/res/drawable/shell_progress_bar.xml
diff --git a/chrome/android/shell/res/layout/chrome_shell_activity.xml b/chrome/android/shell/res/layout/chrome_shell_activity.xml
index 5edf9c0..81186512 100644
--- a/chrome/android/shell/res/layout/chrome_shell_activity.xml
+++ b/chrome/android/shell/res/layout/chrome_shell_activity.xml
@@ -63,7 +63,7 @@
         <org.chromium.chrome.browser.widget.ToolbarProgressBar
             android:id="@+id/progress"
             style="@android:style/Widget.Holo.Light.ProgressBar.Horizontal"
-            android:progressDrawable="@drawable/progress_bar"
+            android:progressDrawable="@drawable/shell_progress_bar"
             android:layout_width="match_parent"
             android:layout_height="2dp"
             android:progress="0" />
diff --git a/chrome/android/sync_shell/OWNERS b/chrome/android/sync_shell/OWNERS
index 3f15c2d..4f35a2f3 100644
--- a/chrome/android/sync_shell/OWNERS
+++ b/chrome/android/sync_shell/OWNERS
@@ -1,3 +1,4 @@
 nyquist@chromium.org
+pvalenzuela@chromium.org
 yfriedman@chromium.org
 zea@chromium.org
diff --git a/chrome/android/sync_shell/javatests/DEPS b/chrome/android/sync_shell/javatests/DEPS
index 036906f..915be87 100644
--- a/chrome/android/sync_shell/javatests/DEPS
+++ b/chrome/android/sync_shell/javatests/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+components/bookmarks",
   "+content/public/android/java",
   "+sync/android/java/src/org/chromium/sync",
   "+sync/test/android/javatests/src/org/chromium/sync/test/util",
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java
index c3cea45..90e8875 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java
@@ -7,13 +7,21 @@
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Pair;
 
+import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.BookmarksBridge;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
+import org.chromium.components.bookmarks.BookmarkId;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.sync.internal_api.pub.base.ModelType;
+import org.json.JSONException;
 import org.json.JSONObject;
 
+import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Test suite for the bookmarks sync data type.
@@ -23,63 +31,199 @@
 
     private static final String BOOKMARKS_TYPE_STRING = "Bookmarks";
 
-    /**
-     * This method performs all steps to test that the client successfully downloads a bookmark from
-     * the server. If successful, a single bookmark will exist on the fake Sync server and on the
-     * client. This state can then be used to test deletion or modification of the bookmark.
-     *
-     * @return the downloaded bookmark's server ID
-     */
-    private String runDownloadBookmarkTestScenario() throws Exception {
-        setupTestAccountAndSignInToSync(CLIENT_ID);
-        assertEquals("No bookmarks should exist on the client by default.",
-                0, SyncTestUtil.getLocalData(mContext, BOOKMARKS_TYPE_STRING).size());
+    private static final String URL = "http://chromium.org/";
+    private static final String TITLE = "Chromium";
+    private static final String MODIFIED_TITLE = "Chromium2";
 
-        String title = "Title";
-        String url = "http://chromium.org/";
-        mFakeServerHelper.injectBookmarkEntity(
-                title, url, mFakeServerHelper.getBookmarkBarFolderId());
+    private BookmarksBridge mBookmarksBridge;
 
-        SyncTestUtil.triggerSyncAndWaitForCompletion(mContext);
+    // A container to store bookmark information for data verification.
+    private static class Bookmark {
+        public final String id;
+        public final String title;
+        public final String url;
 
-        List<Pair<String, JSONObject>> bookmarks = SyncTestUtil.getLocalData(
-                mContext, BOOKMARKS_TYPE_STRING);
-        assertEquals("Only the injected bookmark should exist on the client.",
-                1, bookmarks.size());
-        Pair<String, JSONObject> bookmark = bookmarks.get(0);
-        JSONObject bookmarkJson = bookmark.second;
-        assertEquals("The wrong title was found for the bookmark.", title,
-                bookmarkJson.getString("title"));
-        assertEquals("The wrong URL was found for the bookmark.",
-                url, bookmarkJson.getString("url"));
-
-        return bookmark.first;
+        private Bookmark(String id, String title, String url) {
+            this.id = id;
+            this.title = title;
+            this.url = url;
+        }
     }
 
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mBookmarksBridge = new BookmarksBridge(Profile.getLastUsedProfile());
+                // The BookmarksBridge needs to know how to handle partner bookmarks.
+                // Without this call to fake that knowledge for testing, it crashes.
+                mBookmarksBridge.loadEmptyPartnerBookmarkShimForTesting();
+            }
+        });
+        setupTestAccountAndSignInToSync(CLIENT_ID);
+        // Make sure initial state is clean.
+        assertClientBookmarkCount(0);
+        assertServerBookmarkCountWithName(0, TITLE);
+        assertServerBookmarkCountWithName(0, MODIFIED_TITLE);
+    }
+
+    // Test syncing a new bookmark from server to client.
     @LargeTest
     @Feature({"Sync"})
     public void testDownloadBookmark() throws Exception {
-        runDownloadBookmarkTestScenario();
+        addServerBookmarkAndSync(TITLE, URL);
+        List<Bookmark> bookmarks = getClientBookmarks();
+        assertEquals("Only the injected bookmark should exist on the client.",
+                1, bookmarks.size());
+        Bookmark bookmark = bookmarks.get(0);
+        assertEquals("The wrong title was found for the bookmark.", TITLE, bookmark.title);
+        assertEquals("The wrong URL was found for the bookmark.", URL, bookmark.url);
     }
 
+    // Test syncing a bookmark tombstone from server to client.
     @LargeTest
     @Feature({"Sync"})
-    public void testDownloadDeletedBookmark() throws Exception {
-        String id = runDownloadBookmarkTestScenario();
-        mFakeServerHelper.deleteEntity(id);
-        SyncTestUtil.triggerSyncAndWaitForCompletion(mContext);
+    public void testDownloadBookmarkTombstone() throws Exception {
+        // Add the entity to test deleting.
+        addServerBookmarkAndSync(TITLE, URL);
+        waitForServerBookmarkCountWithName(1, TITLE);
+        waitForClientBookmarkCount(1);
 
-        boolean bookmarkDeleted = CriteriaHelper.pollForCriteria(new Criteria() {
+        // Delete on server, sync, and verify deleted locally.
+        Bookmark bookmark = getClientBookmarks().get(0);
+        mFakeServerHelper.deleteEntity(bookmark.id);
+        waitForServerBookmarkCountWithName(0, TITLE);
+        SyncTestUtil.triggerSyncAndWaitForCompletion(mContext);
+        waitForClientBookmarkCount(0);
+    }
+
+    // Test syncing a new bookmark from client to server.
+    @LargeTest
+    @Feature({"Sync"})
+    public void testUploadBookmark() throws Exception {
+        addClientBookmark(TITLE, URL);
+        waitForClientBookmarkCount(1);
+        waitForServerBookmarkCountWithName(1, TITLE);
+    }
+
+    // Test syncing a bookmark modification from client to server.
+    @LargeTest
+    @Feature({"Sync"})
+    public void testUploadBookmarkModification() throws Exception {
+        // Add the entity to test modifying.
+        BookmarkId bookmarkId = addClientBookmark(TITLE, URL);
+        waitForClientBookmarkCount(1);
+        waitForServerBookmarkCountWithName(1, TITLE);
+
+        setClientBookmarkTitle(bookmarkId, MODIFIED_TITLE);
+        waitForServerBookmarkCountWithName(1, MODIFIED_TITLE);
+        assertServerBookmarkCountWithName(0, TITLE);
+    }
+
+    // Test syncing a bookmark tombstone from client to server.
+    @LargeTest
+    @Feature({"Sync"})
+    public void testUploadBookmarkTombstone() throws Exception {
+        // Add the entity to test deleting.
+        BookmarkId bookmarkId = addClientBookmark(TITLE, URL);
+        waitForClientBookmarkCount(1);
+        waitForServerBookmarkCountWithName(1, TITLE);
+
+        deleteClientBookmark(bookmarkId);
+        waitForClientBookmarkCount(0);
+        waitForServerBookmarkCountWithName(0, TITLE);
+        assertServerBookmarkCountWithName(0, MODIFIED_TITLE);
+    }
+
+    private BookmarkId addClientBookmark(final String title, final String url) {
+        final AtomicReference<BookmarkId> id = new AtomicReference<BookmarkId>();
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                BookmarkId parentId = mBookmarksBridge.getMobileFolderId();
+                id.set(mBookmarksBridge.addBookmark(parentId, 0, title, url));
+            }
+        });
+        assertNotNull("Failed to create bookmark.", id.get());
+        return id.get();
+    }
+
+    private void addServerBookmarkAndSync(String title, String url) throws InterruptedException {
+        mFakeServerHelper.injectBookmarkEntity(
+                title, url, mFakeServerHelper.getBookmarkBarFolderId());
+        SyncTestUtil.triggerSyncAndWaitForCompletion(mContext);
+    }
+
+    private void deleteClientBookmark(final BookmarkId id) {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mBookmarksBridge.deleteBookmark(id);
+            }
+        });
+    }
+
+    private void setClientBookmarkTitle(final BookmarkId id, final String title) {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mBookmarksBridge.setBookmarkTitle(id, title);
+            }
+        });
+    }
+
+    private List<Bookmark> getClientBookmarks() throws JSONException {
+        List<Pair<String, JSONObject>> rawBookmarks = SyncTestUtil.getLocalData(
+                mContext, BOOKMARKS_TYPE_STRING);
+        List<Bookmark> bookmarks = new ArrayList<Bookmark>(rawBookmarks.size());
+        for (Pair<String, JSONObject> rawBookmark : rawBookmarks) {
+            String id = rawBookmark.first;
+            JSONObject json = rawBookmark.second;
+            bookmarks.add(new Bookmark(id, json.getString("title"), json.getString("url")));
+        }
+        return bookmarks;
+    }
+
+    private void assertClientBookmarkCount(int count) throws JSONException {
+        assertEquals("There should be " + count + " local bookmarks.",
+                count, SyncTestUtil.getLocalData(mContext, BOOKMARKS_TYPE_STRING).size());
+    }
+
+    private void assertServerBookmarkCountWithName(int count, String name) {
+        assertTrue("There should be " + count + " remote bookmarks with name " + name + ".",
+                mFakeServerHelper.verifyEntityCountByTypeAndName(
+                            count, ModelType.BOOKMARK, name));
+    }
+
+    private void waitForClientBookmarkCount(final int n) throws InterruptedException {
+        boolean success = CriteriaHelper.pollForCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
                 try {
-                    return SyncTestUtil.getLocalData(mContext, BOOKMARKS_TYPE_STRING).isEmpty();
+                    return SyncTestUtil.getLocalData(mContext, BOOKMARKS_TYPE_STRING).size() == n;
                 } catch (Exception e) {
                     throw new RuntimeException(e);
                 }
             }
         }, SyncTestUtil.UI_TIMEOUT_MS, SyncTestUtil.CHECK_INTERVAL_MS);
+        assertTrue("There should be " + n + " local bookmarks.", success);
+    }
 
-        assertTrue("The lone bookmark should have been deleted.", bookmarkDeleted);
+    private void waitForServerBookmarkCountWithName(final int count, final String name)
+            throws InterruptedException {
+        boolean success = CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                try {
+                    return mFakeServerHelper.verifyEntityCountByTypeAndName(
+                            count, ModelType.BOOKMARK, name);
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }, SyncTestUtil.UI_TIMEOUT_MS, SyncTestUtil.CHECK_INTERVAL_MS);
+        assertTrue("Expected " + count + " remote bookmarks with name " + name + ".", success);
     }
 }
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
index 591d4a5..ce71b77f 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/SyncTest.java
@@ -8,11 +8,9 @@
 import android.app.Activity;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
-import android.util.Pair;
 
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.shell.ChromeShellActivity;
 import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
@@ -20,18 +18,10 @@
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.JavaScriptUtils;
-import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.sync.AndroidSyncSettings;
-import org.chromium.sync.internal_api.pub.base.ModelType;
-import org.chromium.sync.protocol.EntitySpecifics;
-import org.chromium.sync.protocol.SyncEnums;
-import org.chromium.sync.protocol.TypedUrlSpecifics;
 import org.chromium.sync.signin.AccountManagerHelper;
 import org.chromium.sync.signin.ChromeSigninController;
-import org.chromium.ui.base.PageTransition;
-import org.json.JSONObject;
 
-import java.util.List;
 import java.util.concurrent.TimeoutException;
 
 /**
@@ -180,65 +170,6 @@
         SyncTestUtil.verifySignedInWithAccount(mContext, account);
     }
 
-    @LargeTest
-    @Feature({"Sync"})
-    public void testUploadTypedUrl() throws Exception {
-        setupTestAccountAndSignInToSync(CLIENT_ID);
-
-        // TestHttpServerClient is preferred here but it can't be used. The test server
-        // serves pages on localhost and Chrome doesn't sync localhost URLs as typed URLs.
-        // This type of URL requires no external data connection or resources.
-        final String urlToLoad = "data:text,testTypedUrl";
-        assertTrue("A typed URL entity for " + urlToLoad + " already exists on the fake server.",
-                mFakeServerHelper.verifyEntityCountByTypeAndName(0, ModelType.TYPED_URL,
-                        urlToLoad));
-
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                LoadUrlParams params = new LoadUrlParams(urlToLoad, PageTransition.TYPED);
-                getActivity().getActiveTab().loadUrl(params);
-            }
-        });
-
-        boolean synced = CriteriaHelper.pollForCriteria(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return mFakeServerHelper.verifyEntityCountByTypeAndName(1, ModelType.TYPED_URL,
-                        urlToLoad);
-            }
-        }, SyncTestUtil.UI_TIMEOUT_MS, SyncTestUtil.CHECK_INTERVAL_MS);
-
-        assertTrue("The typed URL entity for " + urlToLoad + " was not found on the fake server.",
-                synced);
-    }
-
-    @LargeTest
-    @Feature({"Sync"})
-    public void testDownloadTypedUrl() throws Exception {
-        setupTestAccountAndSignInToSync(CLIENT_ID);
-        assertEquals("No typed URLs should exist on the client by default.",
-                0, SyncTestUtil.getLocalData(mContext, "Typed URLs").size());
-
-        String url = "data:text,testDownloadTypedUrl";
-        EntitySpecifics specifics = new EntitySpecifics();
-        specifics.typedUrl = new TypedUrlSpecifics();
-        specifics.typedUrl.url = url;
-        specifics.typedUrl.title = url;
-        specifics.typedUrl.visits = new long[]{1L};
-        specifics.typedUrl.visitTransitions = new int[]{SyncEnums.TYPED};
-        mFakeServerHelper.injectUniqueClientEntity(url /* name */, specifics);
-
-        SyncTestUtil.triggerSyncAndWaitForCompletion(mContext);
-
-        List<Pair<String, JSONObject>> typedUrls = SyncTestUtil.getLocalData(
-                mContext, "Typed URLs");
-        assertEquals("Only the injected typed URL should exist on the client.",
-                1, typedUrls.size());
-        JSONObject typedUrl = typedUrls.get(0).second;
-        assertEquals("The wrong URL was found for the typed URL.", url, typedUrl.getString("url"));
-    }
-
     private static ContentViewCore getContentViewCore(ChromeShellActivity activity) {
         return activity.getActiveContentViewCore();
     }
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java
new file mode 100644
index 0000000..11a04ab
--- /dev/null
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java
@@ -0,0 +1,173 @@
+// 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.sync;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Pair;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.sync.internal_api.pub.base.ModelType;
+import org.chromium.sync.protocol.EntitySpecifics;
+import org.chromium.sync.protocol.SyncEnums;
+import org.chromium.sync.protocol.TypedUrlSpecifics;
+import org.chromium.ui.base.PageTransition;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test suite for the typed URLs sync data type.
+ */
+public class TypedUrlsTest extends SyncTestBase {
+    private static final String TAG = "TypedUrlsTest";
+
+    private static final String TYPED_URLS_TYPE = "Typed URLs";
+
+    // TestHttpServerClient is preferred here but it can't be used. The test server
+    // serves pages on localhost and Chrome doesn't sync localhost URLs as typed URLs.
+    // This type of URL requires no external data connection or resources.
+    private static final String URL = "data:text,testTypedUrl";
+
+    // A container to store typed URL information for data verification.
+    private static class TypedUrl {
+        public final String id;
+        public final String url;
+
+        public TypedUrl(String id, String url) {
+            this.id = id;
+            this.url = url;
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        setupTestAccountAndSignInToSync(CLIENT_ID);
+        // Make sure the initial state is clean.
+        assertClientTypedUrlCount(0);
+        assertServerTypedUrlCountWithName(0, URL);
+    }
+
+    // Test syncing a typed URL from client to server.
+    @LargeTest
+    @Feature({"Sync"})
+    public void testUploadTypedUrl() throws Exception {
+        loadUrlByTyping(URL);
+        waitForClientTypedUrlCount(1);
+        waitForServerTypedUrlCountWithName(1, URL);
+    }
+
+    // Test syncing a typed URL from server to client.
+    @LargeTest
+    @Feature({"Sync"})
+    public void testDownloadTypedUrl() throws Exception {
+        addServerTypedUrl(URL);
+        SyncTestUtil.triggerSyncAndWaitForCompletion(mContext);
+
+        // Verify data synced to client.
+        List<TypedUrl> typedUrls = getClientTypedUrls();
+        assertEquals("Only the injected typed URL should exist on the client.",
+                1, typedUrls.size());
+        TypedUrl typedUrl = typedUrls.get(0);
+        assertEquals("The wrong URL was found for the typed URL.", URL, typedUrl.url);
+    }
+
+    // Test syncing a typed URL deletion from server to client.
+    @LargeTest
+    @Feature({"Sync"})
+    public void testDownloadDeletedTypedUrl() throws Exception {
+        // Add the entity to test deleting.
+        addServerTypedUrl(URL);
+        SyncTestUtil.triggerSyncAndWaitForCompletion(mContext);
+        assertServerTypedUrlCountWithName(1, URL);
+        assertClientTypedUrlCount(1);
+
+        // Delete on server, sync, and verify deleted locally.
+        TypedUrl typedUrl = getClientTypedUrls().get(0);
+        mFakeServerHelper.deleteEntity(typedUrl.id);
+        waitForServerTypedUrlCountWithName(0, URL);
+        SyncTestUtil.triggerSyncAndWaitForCompletion(mContext);
+        waitForClientTypedUrlCount(0);
+    }
+
+    private void loadUrlByTyping(final String url) {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                LoadUrlParams params = new LoadUrlParams(url, PageTransition.TYPED);
+                getActivity().getActiveTab().loadUrl(params);
+            }
+        });
+    }
+
+    private void addServerTypedUrl(String url) throws InterruptedException {
+        EntitySpecifics specifics = new EntitySpecifics();
+        specifics.typedUrl = new TypedUrlSpecifics();
+        specifics.typedUrl.url = url;
+        specifics.typedUrl.title = url;
+        specifics.typedUrl.visits = new long[]{1L};
+        specifics.typedUrl.visitTransitions = new int[]{SyncEnums.TYPED};
+        mFakeServerHelper.injectUniqueClientEntity(url /* name */, specifics);
+    }
+
+    private List<TypedUrl> getClientTypedUrls() throws JSONException {
+        List<Pair<String, JSONObject>> rawTypedUrls = SyncTestUtil.getLocalData(
+                mContext, TYPED_URLS_TYPE);
+        List<TypedUrl> typedUrls = new ArrayList<TypedUrl>(rawTypedUrls.size());
+        for (Pair<String, JSONObject> rawTypedUrl : rawTypedUrls) {
+            String id =  rawTypedUrl.first;
+            typedUrls.add(new TypedUrl(id, rawTypedUrl.second.getString("url")));
+        }
+        return typedUrls;
+    }
+
+    private void assertClientTypedUrlCount(int count) throws JSONException {
+        assertEquals("There should be " + count + " local typed URL entities.",
+                count, SyncTestUtil.getLocalData(mContext, TYPED_URLS_TYPE).size());
+    }
+
+    private void assertServerTypedUrlCountWithName(int count, String name) {
+        assertTrue("Expected " + count + " server typed URLs with name " + name + ".",
+                mFakeServerHelper.verifyEntityCountByTypeAndName(
+                        count, ModelType.TYPED_URL, name));
+    }
+
+    private void waitForClientTypedUrlCount(final int count) throws InterruptedException {
+        boolean success = CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                try {
+                    return SyncTestUtil.getLocalData(mContext, TYPED_URLS_TYPE).size() == count;
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }, SyncTestUtil.UI_TIMEOUT_MS, SyncTestUtil.CHECK_INTERVAL_MS);
+        assertTrue("Expected " + count + " local typed URL entities.", success);
+    }
+
+    private void waitForServerTypedUrlCountWithName(final int count, final String name)
+            throws InterruptedException {
+        boolean success = CriteriaHelper.pollForCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                try {
+                    return mFakeServerHelper.verifyEntityCountByTypeAndName(
+                            count, ModelType.TYPED_URL, name);
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }, SyncTestUtil.UI_TIMEOUT_MS, SyncTestUtil.CHECK_INTERVAL_MS);
+        assertTrue("Expected " + count + " server typed URLs with name " + name + ".", success);
+    }
+}
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index a4abc08..d582e1e 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1244,6 +1244,12 @@
   <message name="IDS_FLAGS_WAKE_ON_PACKETS_DESCRIPTION" desc="Description for the flag to enable wake on packets.">
     Enables waking the device based on the receipt of some network packets.
   </message>
+  <message name="IDS_FLAGS_FULLSCREEN_APP_LIST_NAME" desc="Description for the flag to enable experimental fullscreen app list.">
+    Enables the fullscreen app-list in touch-view mode.
+  </message>
+  <message name="IDS_FLAGS_FULLSCREEN_APP_LIST_DESCRIPTION" desc="Description for the flag to enable experimental fullscreen app list.">
+    The app-list will appear as fullscreen mode when it's in touch view mode. This flag does nothing outside of the mode.
+  </message>
   <message name="IDS_OFFERS_CONSENT_INFOBAR_LABEL_LEARN_MORE" desc="Text of the Learn More link in the echo dialog.">
     Learn More
   </message>
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 4ecc419..68553fb4 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -211,6 +211,9 @@
   </translations>
   <release seq="1" allow_pseudo="false">
     <messages fallback_to_english="true">
+      <!-- Settings specific strings -->
+      <part file="settings_chromium_strings.grdp" />
+
       <message name="IDS_PROFILES_DISCONNECT_MANAGED_PROFILE_TEXT" desc="Message explaining to the user what will happen if they disconnect the managed profile.">
         Disconnecting <ph name="USERNAME">$1<ex>someone@example.com</ex></ph> will clear your history, bookmarks, settings, and other Chromium data stored on this device. Data stored in your Google Account will not be cleared and can be managed on <ph name="GOOGLE_DASHBOARD_LINK">&lt;a target="_blank" href="$2"&gt;</ph>Google Dashboard<ph name="END_GOOGLE_DASHBOARD_LINK">&lt;/a&gt;</ph>.
       </message>
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index f31abb76..8571c75 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -2556,6 +2556,12 @@
       <message name="IDS_BLOCKED_COOKIES_NO_ACTION" desc="Radio button choice to continue blocking a site from setting cookies, displayed in bubble when a page tries to set cookies.">
         Continue blocking cookies
       </message>
+      <message name="IDS_ALLOWED_COOKIES_NO_ACTION" desc="Radio button choice to keep allowing a site to set the cookies, displayed in bubble when a page tries to set cookies.">
+        Continue allowing cookies
+      </message>
+      <message name="IDS_ALLOWED_COOKIES_BLOCK" desc="Radio button choice to block a site to set the cookies, displayed in bubble when a page tries to set cookies.">
+        Always block cookies on <ph name="HOST">$1<ex>mail.google.com</ex></ph>
+      </message>
       <message name="IDS_BLOCKED_IMAGES_NO_ACTION" desc="Radio button choice to continue blocking a site from showing images, displayed in bubble when a page tries to display images.">
         Continue blocking images
       </message>
@@ -7248,7 +7254,7 @@
         Continue allowing unsandboxed plugins
       </message>
       <message name="IDS_ALLOWED_PPAPI_BROKER_BLOCK" desc="Radio button to block the Pepper broker">
-        Never allow unsandboxed plugins on <ph name="HOST">$1<ex>example.com</ex></ph>
+        Always block unsandboxed plugins on <ph name="HOST">$1<ex>example.com</ex></ph>
       </message>
       <message name="IDS_PPAPI_BROKER_BUBBLE_MANAGE_LINK" desc="Link title to manage Pepper broker settings">
         Manage unsandboxed plugin blocking...
@@ -7284,6 +7290,17 @@
         </message>
       </if>
 
+      <!-- chromeos bookmark app add to shelf strings -->
+      <message name="IDS_ADD_TO_SHELF_INFOBAR_TITLE" desc="Label displayed in an infobar asking users to add to the site to their shelf">
+        Add this site to your shelf to use it any time.
+      </message>
+      <message name="IDS_ADD_TO_SHELF_INFOBAR_ADD_BUTTON" desc="Text displayed on the button to allow users to add to the site to their shelf">
+        Add
+      </message>
+      <message name="IDS_ADD_TO_SHELF_INFOBAR_NEVER_BUTTON" desc="Text displayed on the button to prevent the add to shelf infobar from ever being displayed for this site">
+        Never for this site
+      </message>
+
       <!-- about:system strings -->
       <if expr="not is_android">
         <message name="IDS_ABOUT_SYS_TITLE" desc="about:system page title">
@@ -14278,11 +14295,11 @@
       </message>
 
       <if expr="chromeos">
-        <message name="IDS_FLAGS_DISABLE_SMART_VIRTUAL_KEYBOARD_NAME" desc="Name of about:flags option to turn off smart deployment of the virtual keyboard.">
-          Disable Smart Virtual Keyboard
+        <message name="IDS_FLAGS_SMART_VIRTUAL_KEYBOARD_NAME" desc="Name of about:flags option to toggle smart deployment of the virtual keyboard.">
+          Smart Deployment of the Virtual Keyboard
         </message>
-        <message name="IDS_FLAGS_DISABLE_SMART_VIRTUAL_KEYBOARD_DESCRIPTION" desc="Description of about:flags option to turn off smart deployment of the virtual keyboard">
-          Disable smart deployment of the virtual keyboard.
+        <message name="IDS_FLAGS_SMART_VIRTUAL_KEYBOARD_DESCRIPTION" desc="Description of about:flags option to turn off smart deployment of the virtual keyboard">
+          Enable/Disable smart deployment of the virtual keyboard.
         </message>
 
         <message name="IDS_FLAGS_ENABLE_VIRTUAL_KEYBOARD_NAME" desc="Name of about:flags option to turn on the virtual keyboard">
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index ca17dec..2fe3701 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -134,6 +134,9 @@
   </translations>
   <release seq="1" allow_pseudo="false">
     <messages fallback_to_english="true">
+      <!-- Settings specific strings -->
+      <part file="settings_google_chrome_strings.grdp" />
+
       <message name="IDS_PROFILES_DISCONNECT_MANAGED_PROFILE_TEXT" desc="Message explaining to the user what will happen if they disconnect the managed profile.">
         Disconnecting <ph name="USERNAME">$1<ex>someone@example.com</ex></ph> will clear your history, bookmarks, settings, and other Chrome data stored on this device. Data stored in your Google Account will not be cleared and can be managed on <ph name="GOOGLE_DASHBOARD_LINK">&lt;a target="_blank" href="$2"&gt;</ph>Google Dashboard<ph name="END_GOOGLE_DASHBOARD_LINK">&lt;/a&gt;</ph>.
       </message>
diff --git a/chrome/app/resources/chromium_strings_kn.xtb b/chrome/app/resources/chromium_strings_kn.xtb
index 8b197fd..3de92cf 100644
--- a/chrome/app/resources/chromium_strings_kn.xtb
+++ b/chrome/app/resources/chromium_strings_kn.xtb
@@ -143,7 +143,7 @@
 <translation id="1745962126679160932">Chromium ನಿಮ್ಮ ಮಾಹಿತಿಯನ್ನು ಸುಭದ್ರವಾಗಿ ಸಂಗ್ರಹಿಸಿಕೊಳ್ಳುತ್ತದೆ ಇದರಿಂದಾಗಿ ನೀವು ಅದನ್ನು ಮತ್ತೆ ಟೈಪ್ ಮಾಡಬೇಕಾಗಿಲ್ಲ, ಆದರೂ ನೀವು ಭವಿಷ್ಯದ ಪಾವತಿಗಳಿಗಾಗಿ ಈಗಲೂ ಕಾರ್ಡ್‌ನ ಭದ್ರತೆ ಕೋಡ್ ಆನ್ನು ಪರಿಶೀಲಿಸಬೇಕಾಗುತ್ತದೆ.</translation>
 <translation id="275588974610408078">Chromium ನಲ್ಲಿ ಕ್ರ್ಯಾಶ್ ವರದಿ ಮಾಡುವಿಕೆ ಲಭ್ಯವಿಲ್ಲ.</translation>
 <translation id="5909170354645388250">Chromium ನಲ್ಲಿ ಬಳಸಿಲ್ಲ. ಸಿಂಕ್‌ನಲ್ಲಿ ಸಂಪನ್ಮೂಲ ನಕ್ಷೆಗಳನ್ನು ಇರಿಸಲು Placeholder. ಇದು ಒಂದು ವಾದದವನ್ನು ಅಪೇಕ್ಷಿಸುತ್ತದೆ: $1.</translation>
-<translation id="1144202035120576837"><ph name="SITE"/> ಸಾಮಾನ್ಯವಾಗಿ ನಿಮ್ಮ ಮಾಹಿತಿಯನ್ನು ಸುರಕ್ಷಿತವಾಗಿಡಲು ಎನ್‌ಕ್ರಿಪ್ಶನ್ ಅನ್ನು ಬಳಸುತ್ತದೆ. ಈ ಬಾರಿ Chromium <ph name="SITE"/> ಗೆ ಸಂಪರ್ಕಿಸಲು ಪ್ರಯತ್ನಿಸಿದಾಗ, ವೆಬ್‌ಸೈಟ್ ಸಾಮಾನ್ಯವಲ್ಲದ ಮತ್ತು ತಪ್ಪಾದ ರುಜುವಾತುಗಳನ್ನು ಕಳುಹಿಸಿದೆ. ಆಕ್ರಮಣಕಾರರು <ph name="SITE"/> ಅಂತೆ ನಟಿಸುತ್ತಿದ್ದಾರೆ, ಅಥವಾ ವೈ-ಫೈ ಸೈನ್ ಇನ್ ಪರದೆಯು ಸಂಪರ್ಕದಲ್ಲಿ ಅಡಚಣೆಯನ್ನು ಉಂಟುಮಾಡಿದೆ. ನಿಮ್ಮ ಮಾಹಿತಿಯು ಈಗಲೂ ಸಹ ಸುರಕ್ಷಿತವಾಗಿದೆ ಏಕೆಂದರೆ ಯಾವುದೇ ಡೇಟಾವನ್ನು ಬದಲಾಯಿಸುವುದಕ್ಕೂ ಮೊದಲೇ Chromium ಸಂಪರ್ಕವನ್ನು ನಿಲ್ಲಿಸಿದೆ.</translation>
+<translation id="1144202035120576837"><ph name="SITE"/> ಸಾಮಾನ್ಯವಾಗಿ ನಿಮ್ಮ ಮಾಹಿತಿಯನ್ನು ಸುರಕ್ಷಿತವಾಗಿಡಲು ಎನ್‌ಕ್ರಿಪ್ಶನ್ ಅನ್ನು ಬಳಸುತ್ತದೆ. ಈ ಬಾರಿ Chromium <ph name="SITE"/> ಗೆ ಸಂಪರ್ಕಿಸಲು ಪ್ರಯತ್ನಿಸಿದಾಗ, ವೆಬ್‌ಸೈಟ್ ಸಾಮಾನ್ಯವಲ್ಲದ ಮತ್ತು ತಪ್ಪಾದ ರುಜುವಾತುಗಳನ್ನು ಕಳುಹಿಸಿದೆ. ಆಕ್ರಮಣಕಾರರು <ph name="SITE"/> ಅಂತೆ ನಟಿಸುತ್ತಿದ್ದಾರೆ, ಅಥವಾ Wi-Fi ಸೈನ್ ಇನ್ ಪರದೆಯು ಸಂಪರ್ಕದಲ್ಲಿ ಅಡಚಣೆಯನ್ನು ಉಂಟುಮಾಡಿದೆ. ನಿಮ್ಮ ಮಾಹಿತಿಯು ಈಗಲೂ ಸಹ ಸುರಕ್ಷಿತವಾಗಿದೆ ಏಕೆಂದರೆ ಯಾವುದೇ ಡೇಟಾವನ್ನು ಬದಲಾಯಿಸುವುದಕ್ಕೂ ಮೊದಲೇ Chromium ಸಂಪರ್ಕವನ್ನು ನಿಲ್ಲಿಸಿದೆ.</translation>
 <translation id="2316129865977710310">ಬೇಡ, ಧನ್ಯವಾದಗಳು</translation>
 <translation id="7937630085815544518"><ph name="USER_EMAIL_ADDRESS"/> ನಂತೆ Chromium ಅನ್ನು ನೀವು ಸೈನ್ ಇನ್ ಮಾಡಿರುವಿರಿ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಸೈನ್ ಇನ್ ಮಾಡಲು ಅದೇ ಖಾತೆಯನ್ನು ಬಳಸಿ.</translation>
 <translation id="2685838254101182273">Chromium ನವೀಕರಿಸುವುದನ್ನು ನಿಲ್ಲಿಸಿದೆ ಹಾಗೂ ನಿಮ್ಮ ಆಪರೇಟಿಂಗ್ ಸಿಸ್ಟಮ್‌ನ ಈ  ಆವೃತ್ತಿಯನ್ನು ಇನ್ನು ಮುಂದೆ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ.</translation>
diff --git a/chrome/app/resources/generated_resources_am.xtb b/chrome/app/resources/generated_resources_am.xtb
index 492ee25..1d15097e 100644
--- a/chrome/app/resources/generated_resources_am.xtb
+++ b/chrome/app/resources/generated_resources_am.xtb
@@ -457,7 +457,6 @@
 <translation id="4950138595962845479">አማራጮች...</translation>
 <translation id="4653235815000740718">የስርዓተ ክወና ዳግም ማግኛ ማህደረ መረጃ በመፍጠር ላይ ሳለ አንድ ችግር ነበር። ስራ ላይ የዋለ የማከማቻ መሣሪያ ሊገኝ አልቻለም።</translation>
 <translation id="1407489512183974736">እስከ መሃከል የተከረከመ</translation>
-<translation id="1870557287802238488">በገጽ ውስጥ ዳሰሳዎች ላይ የይለፍ ቃል መጠየቂያ ማሳየትን ያንቁ።</translation>
 <translation id="2688196195245426394">መሣሪያውን በዚህ አገልጋይ ላይ በመመዝገብ ላይ ሳለ ስህተት፦ <ph name="CLIENT_ERROR"/>።</translation>
 <translation id="1528372117901087631">የበይነመረብ ግንኙነት</translation>
 <translation id="1788636309517085411">ነባሪን ይጠቀሙ</translation>
@@ -3236,7 +3235,6 @@
 <translation id="6983783921975806247">የተመዘገበ OID</translation>
 <translation id="394984172568887996">ከIE የመጣ</translation>
 <translation id="5311260548612583999">የግል ቁልፍ ፋይል (ግድ ያይደል)፦</translation>
-<translation id="2831904287943562142">በገጽ ውስጥ ዳሰሳዎች ላይ የይለፍ ቃል መጠየቂያ ማሳየትን ያንቁ። ይህ በተጨማሪ ገጾች ላይ የይለፍ ቃሎችን ማስቀመጥን ይፈቅዳል ነገር ግን አንዳንድ ጊዜ ያልተሳካ በመለያ የመግባት ሙከራዎች በሚደረጉበት ጊዜ መጠየቂያውን ሊያስጀምረው ይችላል።</translation>
 <translation id="8256319818471787266">Sparky</translation>
 <translation id="7568790562536448087">በማዘመን ላይ</translation>
 <translation id="3910699493603749297">የክመር ቁልፍ ሰሌዳ</translation>
diff --git a/chrome/app/resources/generated_resources_ar.xtb b/chrome/app/resources/generated_resources_ar.xtb
index 41fb829..573048d 100644
--- a/chrome/app/resources/generated_resources_ar.xtb
+++ b/chrome/app/resources/generated_resources_ar.xtb
@@ -453,7 +453,6 @@
 <translation id="4950138595962845479">خيارات...</translation>
 <translation id="4653235815000740718">حدثت مشكلة أثناء إنشاء وسائط استعادة نظام التشغيل. حيث تعذر العثور على جهاز التخزين المستخدم.</translation>
 <translation id="1407489512183974736">اقتصاص الوسط</translation>
-<translation id="1870557287802238488">تمكين عرض المطالبة بكلمة المرور على التنقلات في الصفحة.</translation>
 <translation id="2688196195245426394">حدث خطأ عند تسجيل الجهاز مع الخادم: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">اتصال الإنترنت</translation>
 <translation id="1788636309517085411">استخدام الموقع الافتراضي</translation>
@@ -3187,7 +3186,6 @@
 <translation id="6983783921975806247">‏معرّف الكائنات (OID) المسجل</translation>
 <translation id="394984172568887996">‏تمّ الاستيراد من IE</translation>
 <translation id="5311260548612583999">ملف مفتاح خاص (اختياري):</translation>
-<translation id="2831904287943562142">تمكن من عرض المطالبة بكلمة المرور على التنقلات في الصفحة. وهذا يسمح بحفظ كلمات المرور في صفحات أكثر، لكن في بعض الأحيان قد يشغل المطالبة في محاولات تسجيل دخول غير ناجحة.</translation>
 <translation id="8256319818471787266">اللامع</translation>
 <translation id="7568790562536448087">تحديث</translation>
 <translation id="3910699493603749297">لوحة مفاتيح اللغة الخميرية</translation>
diff --git a/chrome/app/resources/generated_resources_bg.xtb b/chrome/app/resources/generated_resources_bg.xtb
index f4692f9..e0b1304 100644
--- a/chrome/app/resources/generated_resources_bg.xtb
+++ b/chrome/app/resources/generated_resources_bg.xtb
@@ -447,7 +447,6 @@
 <translation id="4950138595962845479">Опции...</translation>
 <translation id="4653235815000740718">Възникна проблем при създаването на носителя за възстановяване на операционната система. Използваното устройство за съхранение не бе намерено.</translation>
 <translation id="1407489512183974736">Центриране с подрязване</translation>
-<translation id="1870557287802238488">Активиране на показването на подкана за парола при придвижване в страници.</translation>
 <translation id="2688196195245426394">Грешка при регистрирането на устройството в сървъра: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Връзка с интернет</translation>
 <translation id="1788636309517085411">Използване на стандартното</translation>
@@ -3193,7 +3192,6 @@
 <translation id="6983783921975806247">Регистриран ИДО</translation>
 <translation id="394984172568887996">Импортирани от Internet Explorer</translation>
 <translation id="5311260548612583999">Файл с личен ключ (по избор):</translation>
-<translation id="2831904287943562142">Активирайте показването на подканата за парола при придвижване в страници. Това позволява да се запазват пароли на повече страници, но понякога може да задейства подканата при неуспешни опити за вход.</translation>
 <translation id="8256319818471787266">Спарки</translation>
 <translation id="7568790562536448087">Актуализира се</translation>
 <translation id="3910699493603749297">Кхмерска клавиатура</translation>
diff --git a/chrome/app/resources/generated_resources_bn.xtb b/chrome/app/resources/generated_resources_bn.xtb
index be6ca87..336a8c6 100644
--- a/chrome/app/resources/generated_resources_bn.xtb
+++ b/chrome/app/resources/generated_resources_bn.xtb
@@ -453,7 +453,6 @@
 <translation id="4950138595962845479">বিকল্পসমূহ...</translation>
 <translation id="4653235815000740718">OS পুনরুদ্ধার মিডিয়াটি তৈরি করার সময় একটি ত্রুটি ছিল৷ ব্যবহৃত সঞ্চয় ডিভাইসটির খোঁজ পাওয়া যায়নি৷</translation>
 <translation id="1407489512183974736">কেন্দ্রে ক্রপ করা হয়েছে</translation>
-<translation id="1870557287802238488">পৃষ্ঠা-মধ্যস্থ নেভিগেশানগুলিতে পাসওয়ার্ড বিজ্ঞপ্তি দেখানো সক্ষম করুন৷</translation>
 <translation id="2688196195245426394">ডিভাইসটি সার্ভারে নথিভুক্ত করার সময়ে ত্রুটি: <ph name="CLIENT_ERROR"/>৷</translation>
 <translation id="1528372117901087631">ইন্টারনেট সংযোগ</translation>
 <translation id="1788636309517085411">ডিফল্ট ব্যবহার করুন</translation>
@@ -3220,7 +3219,6 @@
 <translation id="6983783921975806247">নিবন্ধীকৃত OID</translation>
 <translation id="394984172568887996">IE থেকে আমাদানি করা</translation>
 <translation id="5311260548612583999">ব্যক্তিগত কী ফাইল (ঐচ্ছিক):</translation>
-<translation id="2831904287943562142">পৃষ্ঠা-মধ্যস্থ নেভিগেশানগুলিতে পাসওয়ার্ড বিজ্ঞপ্তি দেখানো সক্ষম করুন৷ এটি একাধিক পৃষ্ঠায় পাসওয়ার্ডগুলি সংরক্ষণ করতে দেয়, কিন্তু কখনো কখনো অসফল লগইন প্রচেষ্টায় বিজ্ঞপ্তি ট্রিগার করতে পারে৷</translation>
 <translation id="8256319818471787266">স্পার্কি</translation>
 <translation id="7568790562536448087">আপডেট হচ্ছে</translation>
 <translation id="3910699493603749297">খেমের কীবোর্ড</translation>
diff --git a/chrome/app/resources/generated_resources_ca.xtb b/chrome/app/resources/generated_resources_ca.xtb
index 6f63c40d..702d314 100644
--- a/chrome/app/resources/generated_resources_ca.xtb
+++ b/chrome/app/resources/generated_resources_ca.xtb
@@ -446,7 +446,6 @@
 <translation id="4950138595962845479">Opcions...</translation>
 <translation id="4653235815000740718">S'ha produït un error durant la creació del mitjà de recuperació del sistema operatiu. No s'ha pogut trobar el dispositiu d'emmagatzematge utilitzat.</translation>
 <translation id="1407489512183974736">Retallat al centre</translation>
-<translation id="1870557287802238488">Permet mostrar la sol·licitud de la contrasenya a la navegació de les pàgines.</translation>
 <translation id="2688196195245426394">S'ha produït un error en registrar el dispositiu amb el servidor: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Connexió a Internet</translation>
 <translation id="1788636309517085411">Utilitza la predeterminada</translation>
@@ -1582,7 +1581,7 @@
 <translation id="8094917007353911263">És possible que la xarxa que esteu fent servir requereixi que visiteu <ph name="BEGIN_BOLD"/><ph name="LOGIN_URL"/><ph name="END_BOLD"/>.</translation>
 <translation id="7676077734785147678">IME de l'extensió</translation>
 <translation id="8326478304147373412">PKCS #7, cadena de certificats</translation>
-<translation id="3242765319725186192">Clau compartida prèviament:</translation>
+<translation id="3242765319725186192">Clau precompartida d'IPSec:</translation>
 <translation id="8249048954461686687">Carpeta OEM</translation>
 <translation id="54870580363317966">Trieu un avatar per a aquest usuari supervisat.</translation>
 <translation id="2189826151768452760">Activa Economitzador de dades en mode de baixa fidelitat</translation>
@@ -1603,7 +1602,7 @@
 <translation id="2134149231879627725">Deixeu que Google us ajudi a bloquejar el dispositiu, a ubicar-lo i a esborrar-ne les dades de manera remota.</translation>
 <translation id="1146204723345436916">Importa les adreces d'interès des d'un fitxer HTML...</translation>
 <translation id="2113921862428609753">Accés a la informació d'entitats</translation>
-<translation id="9190063653747922532">L2TP/IPsec + clau compartida prèviament</translation>
+<translation id="9190063653747922532">L2TP/IPsec + clau precompartida d'IPSec</translation>
 <translation id="5227536357203429560">Afegeix una xarxa privada...</translation>
 <translation id="732677191631732447">Cop&amp;ia l'URL de l'àudio</translation>
 <translation id="7224023051066864079">Màscara de subxarxa:</translation>
@@ -3188,7 +3187,6 @@
 <translation id="6983783921975806247">OID registrat</translation>
 <translation id="394984172568887996">Importat d'IE</translation>
 <translation id="5311260548612583999">Clau privada (opcional): </translation>
-<translation id="2831904287943562142">Permet mostrar la sol·licitud de la contrasenya a la navegació de les pàgines. Això permet desar contrasenyes en més pàgines, però és possible que, de vegades, s'activi la sol·licitud quan no es pugui iniciar la sessió correctament.</translation>
 <translation id="8256319818471787266">Gosset</translation>
 <translation id="7568790562536448087">Actualització</translation>
 <translation id="3910699493603749297">Teclat de khmer</translation>
@@ -3375,7 +3373,8 @@
 <translation id="4958202758642732872">Excepcions de pantalla completa</translation>
 <translation id="6990778048354947307">Tema fosc</translation>
 <translation id="8119631488458759651">elimina aquest lloc</translation>
-<translation id="5225324770654022472">Mostra la drecera d'Aplicacions</translation>
+<translation id="5225324770654022472">Mostra la drecera d'aplicacions 
+</translation>
 <translation id="1408803555324839240">No s'ha pogut crear l'usuari supervisat nou. Assegureu-vos que heu iniciat la sessió correctament i torneu-ho a provar.</translation>
 <translation id="6016551720757758985">Confirmació de Powerwash amb retorn a la versió anterior</translation>
 <translation id="4927753642311223124">No hi ha cap notificació, podeu continuar.</translation>
@@ -4343,7 +4342,7 @@
 <translation id="1101112020367325578">No permetis mai els connectors de fora de la zona de proves a <ph name="HOST"/></translation>
 <translation id="6483805311199035658">S'està obrint <ph name="FILE"/>...</translation>
 <translation id="5465122519792752163">Teclat nepalès (InScript)</translation>
-<translation id="940425055435005472">Cos de lletra:</translation>
+<translation id="940425055435005472">Mida de la lletra:</translation>
 <translation id="494286511941020793">Ajuda per configurar servidors intermediaris</translation>
 <translation id="2765217105034171413">Petit</translation>
 <translation id="3590559774363307859">S'ha desat la contrasenya. Hi podeu accedir, així com a totes les <ph name="SAVED_PASSWORDS_LINK"/>, des de qualsevol navegador.</translation>
@@ -4501,7 +4500,7 @@
 <translation id="4669109953235344059">TORNA-HO A PROVAR</translation>
 <translation id="3758760622021964394">Aquesta pàgina vol desactivar el cursor del ratolí.</translation>
 <translation id="4165986682804962316">Configuració del lloc</translation>
-<translation id="4106164762195622179">Les pàgines que es mostren a les pestanyes d'incògnit no s'emmagatzemaran a l'historial del navegador, al magatzem de galetes ni a l'historial de cerca després d'haver tancat <ph name="BEGIN_BOLD"/>totes<ph name="END_BOLD"/> les pestanyes d'incògnit. Els fitxers que baixeu i les adreces d'interès que creeu es sí que es mantindran.</translation>
+<translation id="4106164762195622179">Les pàgines que es mostren a les pestanyes d'incògnit no s'emmagatzemaran a l'historial del navegador, al magatzem de galetes ni a l'historial de cerca després d'haver tancat <ph name="BEGIN_BOLD"/>totes<ph name="END_BOLD"/> les pestanyes d'incògnit. Els fitxers que baixeu i les adreces d'interès que creeu sí que es mantindran. </translation>
 <translation id="1209796539517632982">Servidors de noms automàtics</translation>
 <translation id="8392451568018454956">Menú d'opcions per a <ph name="USER_EMAIL_ADDRESS"/></translation>
 <translation id="6452181791372256707">Rebutja</translation>
diff --git a/chrome/app/resources/generated_resources_cs.xtb b/chrome/app/resources/generated_resources_cs.xtb
index a0481c8..3550a5bac 100644
--- a/chrome/app/resources/generated_resources_cs.xtb
+++ b/chrome/app/resources/generated_resources_cs.xtb
@@ -451,7 +451,6 @@
 <translation id="4950138595962845479">Možnosti...</translation>
 <translation id="4653235815000740718">Při vytváření média pro obnovení operačního systému došlo k potížím. Vybrané úložné zařízení nebylo nalezeno.</translation>
 <translation id="1407489512183974736">Ořezat na střed</translation>
-<translation id="1870557287802238488">Aktivovat zobrazení výzvy k uložení hesla v navigacích na stránce</translation>
 <translation id="2688196195245426394">Při registraci zařízení na serveru došlo k chybě: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Připojení k internetu</translation>
 <translation id="1788636309517085411">Použít výchozí umístění</translation>
@@ -3189,7 +3188,6 @@
 <translation id="6983783921975806247">Registrovaný OID</translation>
 <translation id="394984172568887996">Importováno z aplikace IE</translation>
 <translation id="5311260548612583999">Soubor soukromého klíče (volitelné):</translation>
-<translation id="2831904287943562142">Aktivuje zobrazení výzvy k uložení hesla při navigaci na stránce. Umožňuje to uložení hesel na více stránkách, ale někdy to může vyvolat výzvu při neúspěšných pokusech o přihlášení.</translation>
 <translation id="8256319818471787266">Štěně</translation>
 <translation id="7568790562536448087">Aktualizace</translation>
 <translation id="3910699493603749297">Khmérská klávesnice</translation>
diff --git a/chrome/app/resources/generated_resources_da.xtb b/chrome/app/resources/generated_resources_da.xtb
index dcbccdd8..0f8dd77 100644
--- a/chrome/app/resources/generated_resources_da.xtb
+++ b/chrome/app/resources/generated_resources_da.xtb
@@ -456,7 +456,6 @@
 <translation id="4950138595962845479">Indstillinger...</translation>
 <translation id="4653235815000740718">Der opstod et problem under oprettelsen af genoprettelsesmediet til operativsystemet. Den brugte lagerenhed kunne ikke findes.</translation>
 <translation id="1407489512183974736">Centrér, beskær</translation>
-<translation id="1870557287802238488">Aktivér visning af meddelelsen Husk adgangskode ved sidenavigation.</translation>
 <translation id="2688196195245426394">Fejl ved registrering af enheden med serveren: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Internetforbindelse</translation>
 <translation id="1788636309517085411">Brug standard</translation>
@@ -3204,7 +3203,6 @@
 <translation id="6983783921975806247">Registreret OID</translation>
 <translation id="394984172568887996">Importeret fra IE</translation>
 <translation id="5311260548612583999">Privat nøglefil (valgfri):</translation>
-<translation id="2831904287943562142">Aktivér visning af meddelelsen Husk adgangskode ved sidenavigation. Dette giver dig mulighed for at gemme adgangskoder på flere sider, men kan nogle gange udløse meddelelsen ved mislykkede loginforsøg.</translation>
 <translation id="8256319818471787266">Fido</translation>
 <translation id="7568790562536448087">Opdatering</translation>
 <translation id="3910699493603749297">Khmerisk tastatur</translation>
diff --git a/chrome/app/resources/generated_resources_de.xtb b/chrome/app/resources/generated_resources_de.xtb
index 4cdc17d..1a95a3a 100644
--- a/chrome/app/resources/generated_resources_de.xtb
+++ b/chrome/app/resources/generated_resources_de.xtb
@@ -455,7 +455,6 @@
 <translation id="4950138595962845479">Optionen...</translation>
 <translation id="4653235815000740718">Beim Erstellen des Datenträgers für die OS-Wiederherstellung ist ein Problem aufgetreten. Das verwendete Speichergerät konnte nicht gefunden werden.</translation>
 <translation id="1407489512183974736">Zugeschnitten zentrieren</translation>
-<translation id="1870557287802238488">Einblenden der Passwort-Eingabeaufforderung in der seiteninternen Navigation aktivieren</translation>
 <translation id="2688196195245426394">Fehler bei der Registrierung des Geräts auf dem Server: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Internetverbindung</translation>
 <translation id="1788636309517085411">Standardeinstellung verwenden</translation>
@@ -3184,7 +3183,6 @@
 <translation id="6983783921975806247">Registrierte OID</translation>
 <translation id="394984172568887996">Aus Internet Explorer importiert</translation>
 <translation id="5311260548612583999">Private Schlüsseldatei (optional):</translation>
-<translation id="2831904287943562142">Aktiviert das Einblenden der Passwort-Eingabeaufforderung in der seiteninternen Navigation. So können Passwörter auf mehr Seiten gespeichert werden. Manchmal kann die Eingabeaufforderung jedoch bei Anmeldefehlern eingeblendet werden.</translation>
 <translation id="8256319818471787266">Bello</translation>
 <translation id="7568790562536448087">Aktualisierung läuft</translation>
 <translation id="3910699493603749297">Khmer-Tastatur</translation>
diff --git a/chrome/app/resources/generated_resources_el.xtb b/chrome/app/resources/generated_resources_el.xtb
index bb3f3eb..3c2105fa 100644
--- a/chrome/app/resources/generated_resources_el.xtb
+++ b/chrome/app/resources/generated_resources_el.xtb
@@ -25,7 +25,7 @@
 <translation id="1058418043520174283"><ph name="INDEX"/> από <ph name="COUNT"/></translation>
 <translation id="7717536746040464035">Ενεργοποίηση περιβάλλοντος δοκιμών λειτουργίας απόδοσης seccomp-bpf</translation>
 <translation id="1128109161498068552">Να μην επιτρέπεται σε κανέναν ιστότοπο να χρησιμοποιεί αποκλειστικά μηνύματα συστήματος για την πρόσβαση σε συσκευές MIDI</translation>
-<translation id="8009669262342650481">Επιτρέπει το Bluetooth ιστού, το οποία ενδέχεται να επιτρέψει στους ιστότοπους να συνδέονται και να ελέγχουν τις κοντινές συσκευές Bluetooth, μεταξύ των οποίων πληκτρολόγια, κάμερες, μικρόφωνα, κ.λπ.</translation>
+<translation id="8009669262342650481">Επιτρέπει στο Bluetooth ιστού, το οποίο ενδέχεται να επιτρέψει στους ιστότοπους να συνδέονται και να ελέγχουν τις κοντινές συσκευές Bluetooth, μεταξύ των οποίων πληκτρολόγια, κάμερες, μικρόφωνα, κ.λπ.</translation>
 <translation id="2368075211218459617">Ενεργοποίηση Αναζήτησης με βάση τα συμφραζόμενα.</translation>
 <translation id="8417199120207155527">Με την ενεργοποίηση αυτής της επιλογής, δεν θα επιτρέπεται η πρόσβαση εφαρμογών ιστού στο API WebRTC.</translation>
 <translation id="778579833039460630">Δεν έχουν ληφθεί δεδομένα</translation>
@@ -457,7 +457,6 @@
 <translation id="4950138595962845479">Επιλογές...</translation>
 <translation id="4653235815000740718">Παρουσιάστηκε πρόβλημα κατά τη δημιουργία του μέσου ανάκτησης λειτουργικού συστήματος. Δεν ήταν δυνατός ο εντοπισμός της συσκευής αποθήκευσης που χρησιμοποιήθηκε.</translation>
 <translation id="1407489512183974736">Περικοπή στο κέντρο</translation>
-<translation id="1870557287802238488">Ενεργοποίηση ερώτησης εμφάνισης κωδικού πρόσβασης στην πλοήγηση στις σελίδες.</translation>
 <translation id="2688196195245426394">Σφάλμα εγγραφής της συσκευής στο διακομιστή: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Σύνδεση στο διαδίκτυο</translation>
 <translation id="1788636309517085411">Χρήση προεπιλογής</translation>
@@ -3219,7 +3218,6 @@
 <translation id="6983783921975806247">Εγγεγραμμένο OID</translation>
 <translation id="394984172568887996">Εισαγωγή από το IE</translation>
 <translation id="5311260548612583999">Αρχείο ιδ. κλειδιού (προαιρετικό): </translation>
-<translation id="2831904287943562142">Ενεργοποίηση ερώτησης εμφάνισης κωδικού πρόσβασης στην πλοήγηση στις σελίδες. Αυτό επιτρέπει την αποθήκευση κωδικών πρόσβασης σε περισσότερες σελίδες, αλλά ενδέχεται ορισμένες φορές να εμφανίζει την ερώτηση στις ανεπιτυχείς προσπάθειες σύνδεσης.</translation>
 <translation id="8256319818471787266">Ζωηρός</translation>
 <translation id="7568790562536448087">Ενημέρωση</translation>
 <translation id="3910699493603749297">Πληκτρολόγιο Κμερ</translation>
diff --git a/chrome/app/resources/generated_resources_en-GB.xtb b/chrome/app/resources/generated_resources_en-GB.xtb
index 9591af9d..e3be474 100644
--- a/chrome/app/resources/generated_resources_en-GB.xtb
+++ b/chrome/app/resources/generated_resources_en-GB.xtb
@@ -455,7 +455,6 @@
 <translation id="4950138595962845479">Options...</translation>
 <translation id="4653235815000740718">There was a problem while creating OS recovery media. Used storage device could not be found.</translation>
 <translation id="1407489512183974736">Centre Cropped</translation>
-<translation id="1870557287802238488">Enable showing of password prompt on in-page navigations.</translation>
 <translation id="2688196195245426394">Error when registering the device with the server: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Internet connection</translation>
 <translation id="1788636309517085411">Use default</translation>
@@ -3211,7 +3210,6 @@
 <translation id="6983783921975806247">Registered OID</translation>
 <translation id="394984172568887996">Imported From IE</translation>
 <translation id="5311260548612583999">Private key file (optional):</translation>
-<translation id="2831904287943562142">Enable showing of the password prompt on in-page navigation. This allows for saving passwords on more pages but might sometimes trigger the prompt on unsuccessful log-in attempts.</translation>
 <translation id="8256319818471787266">Sparky</translation>
 <translation id="7568790562536448087">Updating</translation>
 <translation id="3910699493603749297">Khmer keyboard</translation>
diff --git a/chrome/app/resources/generated_resources_es-419.xtb b/chrome/app/resources/generated_resources_es-419.xtb
index 2ea218b2..c7aa746 100644
--- a/chrome/app/resources/generated_resources_es-419.xtb
+++ b/chrome/app/resources/generated_resources_es-419.xtb
@@ -448,7 +448,6 @@
 <translation id="4950138595962845479">Opciones...</translation>
 <translation id="4653235815000740718">Se produjo un error durante la creación de la recuperación de datos del SO. No se pudo encontrar el dispositivo de almacenamiento utilizado.</translation>
 <translation id="1407489512183974736">Centrar imagen recortada</translation>
-<translation id="1870557287802238488">Habilitar la aparición de la solicitud de contraseña cuando hay desplazamiento en una página</translation>
 <translation id="2688196195245426394">Se produjo un error al registrar el dispositivo en el servidor: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Conexión a Internet</translation>
 <translation id="1788636309517085411">Usar predeterminado</translation>
@@ -883,7 +882,7 @@
 <translation id="3872166400289564527">Almacenamiento externo</translation>
 <translation id="1442912890475371290">Se bloqueó un intento de <ph name="BEGIN_LINK"/>acceso a una página en <ph name="DOMAIN"/><ph name="END_LINK"/>.</translation>
 <translation id="5912378097832178659">&amp;Editar motores de búsqueda...</translation>
-<translation id="8013526960933383914">Habilita el modo de escritorio unificado</translation>
+<translation id="8013526960933383914">Habilitar el modo de escritorio unificado</translation>
 <translation id="6732586201820838268">No se pudo establecer una conexión con el teléfono. Asegúrate de que tienes un teléfono Android compatible, y que esté encendido y al alcance de tu mano. &lt;a&gt;Más información&lt;/a&gt;</translation>
 <translation id="3749289110408117711">Nombre del archivo</translation>
 <translation id="3893630138897523026">ChromeVox (comentarios por voz)</translation>
@@ -1859,7 +1858,7 @@
 <translation id="2509739495444557741">No hay complementos instalados.</translation>
 <translation id="7075513071073410194">PKCS N. º 1 MD5 con encriptación RSA</translation>
 <translation id="7767646430896201896">Opciones:</translation>
-<translation id="1114335938027186412">La computadora contiene un dispositivo de seguridad del módulo de plataforma segura (TPM) que se usa para implementar varias funciones clave de seguridad en el Sistema operativo Chrome. Para obtener más información, visita el Centro de ayuda de Chromebook: https://support.google.com/chromebook/?p=tpm.</translation>
+<translation id="1114335938027186412">La computadora contiene un dispositivo de seguridad del Módulo de plataforma segura (TPM) que se usa para implementar varias funciones clave de seguridad en el Sistema operativo Chrome. Para obtener más información, visita el Centro de ayuda de Chromebook: https://support.google.com/chromebook/?p=tpm.</translation>
 <translation id="714034171374937760">Chromebase</translation>
 <translation id="7124398136655728606">Con Esc se elimina todo el búfer de edición previa</translation>
 <translation id="3344786168130157628">Nombre de punto de acceso:</translation>
@@ -3199,7 +3198,6 @@
 <translation id="6983783921975806247">OID registrado</translation>
 <translation id="394984172568887996">Importado de Internet Explorer</translation>
 <translation id="5311260548612583999">Archivo de clave privada (opcional):</translation>
-<translation id="2831904287943562142">Habilita la aparición de la solicitud de contraseña cuando hay desplazamiento en una página. Esta acción permite que se guarden las contraseñas en más páginas, pero también es posible que active la solicitud en intentos de acceso fallidos.</translation>
 <translation id="8256319818471787266">Bobby</translation>
 <translation id="7568790562536448087">Actualizando</translation>
 <translation id="3910699493603749297">Teclado khmer</translation>
@@ -4826,7 +4824,7 @@
 <translation id="6626108645084335023">Esperando el sondeo del DNS</translation>
 <translation id="1903219944620007795">Para la entrada de texto, selecciona un idioma y visualiza los métodos de entrada disponibles.</translation>
 <translation id="1850508293116537636">Girar &amp;a la derecha</translation>
-<translation id="7291266260406617455">Habilita la opción de exigir que se guarden las contraseñas.</translation>
+<translation id="7291266260406617455">Habilitar la opción de exigir que se guarden las contraseñas</translation>
 <translation id="7209475358897642338">¿Cuál es tu idioma?</translation>
 <translation id="140520891692800925"><ph name="PROFILE_DISPLAY_NAME"/> (supervisado)</translation>
 <translation id="9149866541089851383">Edición...</translation>
@@ -5842,7 +5840,7 @@
 <translation id="5832830184511718549">Utiliza un subproceso secundario para realizar la composición de páginas web. Esto permite un desplazamiento sin problemas, incluso cuando el subproceso principal no responda.</translation>
 <translation id="7943385054491506837">Inglés (Estados Unidos; Colemak)</translation>
 <translation id="8203365863660628138">Confirmar instalación</translation>
-<translation id="1635033183663317347">Instalado por tu custodia</translation>
+<translation id="1635033183663317347">Instalado por tu tutor</translation>
 <translation id="5457858494714903578">No puedes instalar una extensión no confiable con el ID &quot;<ph name="IMPORT_ID"/>&quot;.</translation>
 <translation id="7025325401470358758">Siguiente panel</translation>
 <translation id="3397561538744706497">9 x 16</translation>
diff --git a/chrome/app/resources/generated_resources_es.xtb b/chrome/app/resources/generated_resources_es.xtb
index 5f3272b..6d10a64 100644
--- a/chrome/app/resources/generated_resources_es.xtb
+++ b/chrome/app/resources/generated_resources_es.xtb
@@ -458,7 +458,6 @@
 <translation id="4950138595962845479">Opciones...</translation>
 <translation id="4653235815000740718">Se ha producido un error durante la creación del medio de recuperación del sistema operativo. No se ha podido encontrar el dispositivo de almacenamiento utilizado.</translation>
 <translation id="1407489512183974736">Centrar imagen recortada</translation>
-<translation id="1870557287802238488">Habilitar solicitud de contraseña en la navegación dentro de páginas.</translation>
 <translation id="2688196195245426394">Error al registrar el dispositivo en el servidor (<ph name="CLIENT_ERROR"/>)</translation>
 <translation id="1528372117901087631">Conexión a Internet</translation>
 <translation id="1788636309517085411">Utilizar valores predeterminados</translation>
@@ -3196,7 +3195,6 @@
 <translation id="6983783921975806247">OID registrado</translation>
 <translation id="394984172568887996">Importado de Internet Explorer</translation>
 <translation id="5311260548612583999">Clave privada (opcional):</translation>
-<translation id="2831904287943562142">Habilitar solicitud de contraseña en la navegación dentro de páginas. Esta opción permite guardar contraseñas en más páginas pero, en algunos casos, puede hacer que se muestre la solicitud al realizar intentos fallidos de inicio de sesión.</translation>
 <translation id="8256319818471787266">Perrito</translation>
 <translation id="7568790562536448087">Actualización</translation>
 <translation id="3910699493603749297">Teclado khmer</translation>
diff --git a/chrome/app/resources/generated_resources_et.xtb b/chrome/app/resources/generated_resources_et.xtb
index e4f2924..46909c0 100644
--- a/chrome/app/resources/generated_resources_et.xtb
+++ b/chrome/app/resources/generated_resources_et.xtb
@@ -456,7 +456,6 @@
 <translation id="4950138595962845479">Valikud...</translation>
 <translation id="4653235815000740718">OS-i taastekandja loomisel ilmnes tõrge. Kasutatud salvestusseadet ei leitud.</translation>
 <translation id="1407489512183974736">Keskel, kärbitud</translation>
-<translation id="1870557287802238488">Lehesisesel navigeerimisel parooliviiba kuvamise lubamine.</translation>
 <translation id="2688196195245426394">Seadme serveris registreerimisel ilmnes viga: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Interneti-ühendus</translation>
 <translation id="1788636309517085411">Vaikimisi kasutamine</translation>
@@ -3207,7 +3206,6 @@
 <translation id="6983783921975806247">Registreeritud OID</translation>
 <translation id="394984172568887996">Imporditud IE'st</translation>
 <translation id="5311260548612583999">Privaatvõtme fail (valik.):</translation>
-<translation id="2831904287943562142">Lubab lehesisesel navigeerimisel parooliviiba kuvamise. See võimaldab salvestada paroole erinevatel lehtedel, aga võib mõnikord käivitada viiba ebaõnnestunud sisselogimiskatse korral.</translation>
 <translation id="8256319818471787266">Muri</translation>
 <translation id="7568790562536448087">Värskendamine</translation>
 <translation id="3910699493603749297">Khmeeri klaviatuur</translation>
diff --git a/chrome/app/resources/generated_resources_fa.xtb b/chrome/app/resources/generated_resources_fa.xtb
index f67fda7..69eeadf 100644
--- a/chrome/app/resources/generated_resources_fa.xtb
+++ b/chrome/app/resources/generated_resources_fa.xtb
@@ -449,7 +449,6 @@
 <translation id="4950138595962845479">گزینه‌ها...</translation>
 <translation id="4653235815000740718">در ایجاد رسانه بازیابی سیستم عامل مشکلی روی داد. دستگاه ذخیره‌سازی مورد استفاده یافت نشد.</translation>
 <translation id="1407489512183974736">برش خورده در مرکز</translation>
-<translation id="1870557287802238488">نمایش درخواست گذرواژه را در پیمایش‌های درون صفحه فعال کنید.</translation>
 <translation id="2688196195245426394">خطا هنگام ثبت دستگاه با سرور: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">اتصال اینترنت</translation>
 <translation id="1788636309517085411">استفاده از پیش‌فرض</translation>
@@ -3199,7 +3198,6 @@
 <translation id="6983783921975806247">‏OID ثبت شده</translation>
 <translation id="394984172568887996">‏وارد شده از IE</translation>
 <translation id="5311260548612583999">فایل کلید خصوصی (اختیاری):</translation>
-<translation id="2831904287943562142">نمایش درخواست گذرواژه را هنگام پیمایش‌های درون صفحه‌ای فعال کنید. با این کار ذخیره گذرواژه‌ها در صفحات بیشتری امکان‌پذیر می‌شود اما شاید گاهی درخواست را هنگام تلاش‌های ناموفق برای ورود به سیستم، فعال کند.</translation>
 <translation id="8256319818471787266">سرزنده</translation>
 <translation id="7568790562536448087">در حال به‌روزرسانی</translation>
 <translation id="3910699493603749297">صفحه‌کلید خمری</translation>
diff --git a/chrome/app/resources/generated_resources_fi.xtb b/chrome/app/resources/generated_resources_fi.xtb
index e69a3cf4..d513c12 100644
--- a/chrome/app/resources/generated_resources_fi.xtb
+++ b/chrome/app/resources/generated_resources_fi.xtb
@@ -447,7 +447,6 @@
 <translation id="4950138595962845479">Asetukset...</translation>
 <translation id="4653235815000740718">Virhe käyttöjärjestelmän palautustietovälineen luomisessa. Tallennuslaitetta ei löydy.</translation>
 <translation id="1407489512183974736">Rajaa keskelle</translation>
-<translation id="1870557287802238488">Ota salasanakehoitus käyttöön sivulla navigoinnissa.</translation>
 <translation id="2688196195245426394">Virhe rekisteröitäessä laitetta palvelimelle: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Internetyhteys</translation>
 <translation id="1788636309517085411">Käytä oletusta</translation>
@@ -3180,7 +3179,6 @@
 <translation id="6983783921975806247">Rekisteröity OID</translation>
 <translation id="394984172568887996">Tuotu IE:stä</translation>
 <translation id="5311260548612583999">Yksityinen avaintiedosto (valinnainen):</translation>
-<translation id="2831904287943562142">Ota salasanakehote käyttöön sivulla navigoinnissa. Sen avulla salasanoja voi tallentaa useammille sivuille, mutta se saattaa joskus aiheuttaa ilmoituksen epäonnistuneesta kirjautumisyrityksestä.</translation>
 <translation id="8256319818471787266">Musti</translation>
 <translation id="7568790562536448087">Päivitetään</translation>
 <translation id="3910699493603749297">Khmerinkielinen näppäimistö</translation>
diff --git a/chrome/app/resources/generated_resources_fil.xtb b/chrome/app/resources/generated_resources_fil.xtb
index 09359d4..10e2738 100644
--- a/chrome/app/resources/generated_resources_fil.xtb
+++ b/chrome/app/resources/generated_resources_fil.xtb
@@ -455,7 +455,6 @@
 <translation id="4950138595962845479">Mga Pagpipilian...</translation>
 <translation id="4653235815000740718">Nagkaproblema habang nililikha ang OS recovery media. Hindi matagpuan ang ginamit na storage device.</translation>
 <translation id="1407489512183974736">Gitnang Naka-crop</translation>
-<translation id="1870557287802238488">I-enable ang pagpapakita ng prompt ng password sa mga navigation na nasa page.</translation>
 <translation id="2688196195245426394">Error kapag inirerehistro ang device sa server: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Koneksyon sa Internet</translation>
 <translation id="1788636309517085411">Gamitin ang default</translation>
@@ -3220,7 +3219,6 @@
 <translation id="6983783921975806247">Nakarehistrong OID</translation>
 <translation id="394984172568887996">Nag-import mula sa IE</translation>
 <translation id="5311260548612583999">Private key file (opsyonal): </translation>
-<translation id="2831904287943562142">I-enable ang pagpapakita ng prompt ng password sa mga navigation na nasa page. Nagbibigay-daan ito sa iyo para sa pagse-save ng mga password sa higit pang mga page ngunit minsan ay maaaring i-trigger ang prompt sa mga hindi matagumpay na pagsubok na mag-login.</translation>
 <translation id="8256319818471787266">Bantay</translation>
 <translation id="7568790562536448087">Ina-update</translation>
 <translation id="3910699493603749297">Khmer keyboard</translation>
diff --git a/chrome/app/resources/generated_resources_fr.xtb b/chrome/app/resources/generated_resources_fr.xtb
index 3947c53..f099030 100644
--- a/chrome/app/resources/generated_resources_fr.xtb
+++ b/chrome/app/resources/generated_resources_fr.xtb
@@ -451,7 +451,6 @@
 <translation id="4950138595962845479">Options...</translation>
 <translation id="4653235815000740718">Un problème est survenu lors de la création du support de récupération du système d'exploitation. Le périphérique de stockage utilisé est introuvable.</translation>
 <translation id="1407489512183974736">Recadrer et centrer</translation>
-<translation id="1870557287802238488">Activer l'affichage de l'invite d'enregistrement du mot de passe lors de la navigation sur les pages</translation>
 <translation id="2688196195245426394">Erreur survenue lors de l'enregistrement de l'appareil avec le serveur : <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Connexion Internet</translation>
 <translation id="1788636309517085411">Utiliser les valeurs par défaut</translation>
@@ -3221,7 +3220,6 @@
 <translation id="6983783921975806247">OID enregistré</translation>
 <translation id="394984172568887996">Importés depuis IE</translation>
 <translation id="5311260548612583999">Fichier de clé privée (facultatif) :</translation>
-<translation id="2831904287943562142">Activer l'affichage de l'invite d'enregistrement du mot de passe lors de la navigation sur les pages. Cette option permet d'enregistrer les mots de passe sur plus de pages, mais elle peut parfois déclencher l'invite lors de l'échec d'une tentative de connexion.</translation>
 <translation id="8256319818471787266">Médor</translation>
 <translation id="7568790562536448087">Mise à jour en cours</translation>
 <translation id="3910699493603749297">Clavier khmer</translation>
diff --git a/chrome/app/resources/generated_resources_gu.xtb b/chrome/app/resources/generated_resources_gu.xtb
index 1c04622..eed6625 100644
--- a/chrome/app/resources/generated_resources_gu.xtb
+++ b/chrome/app/resources/generated_resources_gu.xtb
@@ -459,7 +459,6 @@
 <translation id="4950138595962845479">વિકલ્પો...</translation>
 <translation id="4653235815000740718">OS પુનર્પ્રાપ્તિ મીડિયા બનાવતી વખતે એક સમસ્યા આવી હતી. વપરાયેલ સ્ટોરેજ ઉપકરણ મળી શક્યું નથી. </translation>
 <translation id="1407489512183974736">મધ્યમાં કાપેલું</translation>
-<translation id="1870557287802238488">પૃષ્ઠમાં નેવિગેશન્સ પર પાસવર્ડ સંકેત દર્શાવવાનું સક્ષમ કરો.</translation>
 <translation id="2688196195245426394">સર્વર સાથે ઉપકરણની નોંધણી કરતી વખતે ભૂલ: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">ઇન્ટરનેટ કનેક્શન</translation>
 <translation id="1788636309517085411">ડિફૉલ્ટનો ઉપયોગ કરો</translation>
@@ -3222,7 +3221,6 @@
 <translation id="6983783921975806247">નોંધાયેલ OID</translation>
 <translation id="394984172568887996">IE થી આયાત કરેલ</translation>
 <translation id="5311260548612583999">ખાનગી કી ફાઇલ (વૈકલ્પિક):</translation>
-<translation id="2831904287943562142">પૃષ્ઠમાં નેવિગેશન્સ પર પાસવર્ડ સંકેત દર્શાવવાનું સક્ષમ કરો. આ વધુ પૃષ્ઠો પર પાસવર્ડ્સ સાચવવાની મંજૂરી આપે છે પરંતુ કેટલીકવાર અસફળ લોગિન પ્રયત્નો પર સંકેત ટ્રિગર થઈ શકે છે.</translation>
 <translation id="8256319818471787266">સ્પાર્કી</translation>
 <translation id="7568790562536448087">અપડેટ થઈ રહ્યું છે</translation>
 <translation id="3910699493603749297">ખ્મેર કીબોર્ડ</translation>
diff --git a/chrome/app/resources/generated_resources_hi.xtb b/chrome/app/resources/generated_resources_hi.xtb
index 7fafdac..c25ce72 100644
--- a/chrome/app/resources/generated_resources_hi.xtb
+++ b/chrome/app/resources/generated_resources_hi.xtb
@@ -453,7 +453,6 @@
 <translation id="4950138595962845479">विकल्प...</translation>
 <translation id="4653235815000740718">OS पुनर्प्राप्‍ति मीडिया बनाते समय समस्‍या आई थी. उपयोग किया गया मेमोरी डिवाइस नहीं मिला.</translation>
 <translation id="1407489512183974736">मध्य में काटा गया</translation>
-<translation id="1870557287802238488">इन-पेज मागदर्शक पर पासवर्ड संकेत दिखाना सक्षम करें.</translation>
 <translation id="2688196195245426394">डिवाइस को सर्वर के साथ पंजीकृत करते समय त्रुटि: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">इंटरनेट कनेक्शन</translation>
 <translation id="1788636309517085411">डिफ़ॉल्ट का उपयोग करें</translation>
@@ -3233,7 +3232,6 @@
 <translation id="6983783921975806247">पंजीकृत OID</translation>
 <translation id="394984172568887996">IE से आयात किया गया</translation>
 <translation id="5311260548612583999">निजी कुंजी फ़ाइल (वैकल्पिक):</translation>
-<translation id="2831904287943562142">इन-पेज मार्गदर्शक पर पासवर्ड संकेत दिखाया जाना सक्षम करता है. इससे और अधिक पृष्‍ठों पर पासवर्ड सहेजा जा सकता है लेकिन कभी-कभी असफल प्रवेश प्रयासों पर भी संकेत ट्रिगर हो सकता है.</translation>
 <translation id="8256319818471787266">स्‍पार्की</translation>
 <translation id="7568790562536448087">अपडेट कर रहा है</translation>
 <translation id="3910699493603749297">खमेर कीबोर्ड</translation>
diff --git a/chrome/app/resources/generated_resources_hr.xtb b/chrome/app/resources/generated_resources_hr.xtb
index 2abf308..c252f62 100644
--- a/chrome/app/resources/generated_resources_hr.xtb
+++ b/chrome/app/resources/generated_resources_hr.xtb
@@ -447,7 +447,6 @@
 <translation id="4950138595962845479">Opcije...</translation>
 <translation id="4653235815000740718">Došlo je do problema prilikom izrade medija za oporavak sustava. Nije bilo moguće pronaći upotrijebljeni uređaj za pohranu.</translation>
 <translation id="1407489512183974736">Centriraj obrezano</translation>
-<translation id="1870557287802238488">Omogući prikazivanje upita za unos zaporke na navigaciji po stranici.</translation>
 <translation id="2688196195245426394">Pogreška pri registraciji uređaja na poslužitelju: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Internetska veza</translation>
 <translation id="1788636309517085411">Upotrijebi zadano</translation>
@@ -3188,7 +3187,6 @@
 <translation id="6983783921975806247">Registrirani OID</translation>
 <translation id="394984172568887996">Uvezeno iz IE</translation>
 <translation id="5311260548612583999">Datoteka s os.klj. (neobav.)</translation>
-<translation id="2831904287943562142">Omogućuje prikazivanje upita za unos zaporke na navigaciji po stranici. To omogućuje spremanje zaporki na više stranica, ali ponekad može pokrenuti upit za neuspješne pokušaje prijave.</translation>
 <translation id="8256319818471787266">Bobi</translation>
 <translation id="7568790562536448087">Ažuriranje stavke</translation>
 <translation id="3910699493603749297">kmerska tipkovnica</translation>
diff --git a/chrome/app/resources/generated_resources_hu.xtb b/chrome/app/resources/generated_resources_hu.xtb
index 01c0fe0..7d01519 100644
--- a/chrome/app/resources/generated_resources_hu.xtb
+++ b/chrome/app/resources/generated_resources_hu.xtb
@@ -448,7 +448,6 @@
 <translation id="4950138595962845479">Beállítások...</translation>
 <translation id="4653235815000740718">Probléma lépett fel az OS-helyreállító adathordozó elkészítése során. A felhasználni kívánt tárolóeszköz nem található.</translation>
 <translation id="1407489512183974736">Középre, levágva</translation>
-<translation id="1870557287802238488">Jelszó mentésével kapcsolatos üzenetek megjelenítésének engedélyezése az oldalon belüli navigációban.</translation>
 <translation id="2688196195245426394">Hiba az eszköz szerveren való regisztrálásakor: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Internetkapcsolat</translation>
 <translation id="1788636309517085411">Alapbeállítás használata</translation>
@@ -3196,7 +3195,6 @@
 <translation id="6983783921975806247">Regisztrált OID</translation>
 <translation id="394984172568887996">Az IE alkalmazásból importálva</translation>
 <translation id="5311260548612583999">Privátkulcs-fájl (nem kötelező):</translation>
-<translation id="2831904287943562142">Jelszó mentésével kapcsolatos üzenetek megjelenítésének engedélyezése az oldalon belüli navigációknál. Ezzel több oldalon nyílik lehetőség a jelszavak mentésére, de esetenként a sikertelen bejelentkezési kísérleteknél is megjelennek a jelszó mentésével kapcsolatos üzenetek.</translation>
 <translation id="8256319818471787266">Bundi</translation>
 <translation id="7568790562536448087"> frissítése</translation>
 <translation id="3910699493603749297">Khmer billentyűzet</translation>
diff --git a/chrome/app/resources/generated_resources_id.xtb b/chrome/app/resources/generated_resources_id.xtb
index 62d5443d..775043f 100644
--- a/chrome/app/resources/generated_resources_id.xtb
+++ b/chrome/app/resources/generated_resources_id.xtb
@@ -448,7 +448,6 @@
 <translation id="4950138595962845479">Opsi...</translation>
 <translation id="4653235815000740718">Ada masalah saat membuat media pemulihan OS. Perangkat penyimpanan yang dipakai tidak dapat ditemukan.</translation>
 <translation id="1407489512183974736">Dipangkas di Tengah</translation>
-<translation id="1870557287802238488">Munculkan permintaan sandi pada navigasi laman.</translation>
 <translation id="2688196195245426394">Terjadi kesalahan saat mendaftarkan perangkat dengan server: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Sambungan internet</translation>
 <translation id="1788636309517085411">Gunakan default</translation>
@@ -3198,7 +3197,6 @@
 <translation id="6983783921975806247">OID terdaftar</translation>
 <translation id="394984172568887996">Diimpor dari IE</translation>
 <translation id="5311260548612583999">Kunci pribadi (opsional):</translation>
-<translation id="2831904287943562142">Memungkinkan dimunculkannya permintaan sandi di navigasi laman. Tindakan ini memungkinkan penyimpanan sandi di laman lain namun terkadang dapat memicu permintaan pada upaya masuk yang tidak berhasil.</translation>
 <translation id="8256319818471787266">Bleki</translation>
 <translation id="7568790562536448087">Memperbarui</translation>
 <translation id="3910699493603749297">Keyboard Khmer</translation>
diff --git a/chrome/app/resources/generated_resources_it.xtb b/chrome/app/resources/generated_resources_it.xtb
index b157cb74c..af97282 100644
--- a/chrome/app/resources/generated_resources_it.xtb
+++ b/chrome/app/resources/generated_resources_it.xtb
@@ -447,7 +447,6 @@
 <translation id="4950138595962845479">Opzioni...</translation>
 <translation id="4653235815000740718">Si è verificato un problema durante la creazione del supporto di ripristino del sistema operativo. Il dispositivo di archiviazione utilizzato non è stato trovato.</translation>
 <translation id="1407489512183974736">Ritagliato al centro</translation>
-<translation id="1870557287802238488">Abilita visualizzazione richiesta di password su navigazioni nelle pagine.</translation>
 <translation id="2688196195245426394">Errore durante la registrazione del dispositivo con il server. <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Connessione Internet</translation>
 <translation id="1788636309517085411">Usa posizione predefinita</translation>
@@ -3175,7 +3174,6 @@
 <translation id="6983783921975806247">OID registrato</translation>
 <translation id="394984172568887996">Importati da IE</translation>
 <translation id="5311260548612583999">File chiave privata (facoltativo):</translation>
-<translation id="2831904287943562142">Abilita la visualizzazione della richiesta di password su navigazioni nelle pagine. Questo flag consente di salvare le password su più pagine, ma a volte può visualizzare la finestra di richiesta in caso di tentativi di accesso non riusciti.</translation>
 <translation id="8256319818471787266">Fido</translation>
 <translation id="7568790562536448087">Aggiornamento</translation>
 <translation id="3910699493603749297">Tastiera Khmer</translation>
diff --git a/chrome/app/resources/generated_resources_iw.xtb b/chrome/app/resources/generated_resources_iw.xtb
index 5ffd1ed..7f60271 100644
--- a/chrome/app/resources/generated_resources_iw.xtb
+++ b/chrome/app/resources/generated_resources_iw.xtb
@@ -450,7 +450,6 @@
 <translation id="4950138595962845479">אפשרויות...</translation>
 <translation id="4653235815000740718">אירעה בעיה במהלך היצירה של מדיית השחזור של מערכת ההפעלה. מכשיר האחסון שבו נעשה שימוש לא נמצא.</translation>
 <translation id="1407489512183974736">חתוך במרכז</translation>
-<translation id="1870557287802238488">הפעל הצגה של בקשה להזנת סיסמה תוך כדי ניווט בתוך הדף.</translation>
 <translation id="2688196195245426394">אירעה שגיאה בעת רישום המכשיר בשרת: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">חיבור לאינטרנט</translation>
 <translation id="1788636309517085411">השתמש בברירת המחדל</translation>
@@ -3184,7 +3183,6 @@
 <translation id="6983783921975806247">‏OID רשום</translation>
 <translation id="394984172568887996">‏מיובא מ-IE</translation>
 <translation id="5311260548612583999">קובץ מפתח פרטי (אופציונלי):</translation>
-<translation id="2831904287943562142">הפעל הצגה של בקשה להזנת סיסמה תוך כדי ניווט בתוך הדף. מצב זה מאפשר שמירה של סיסמאות בדפים רבים יותר, אך לעתים הבקשה תופיע לאחר ניסיונות התחברות שנכשלו.</translation>
 <translation id="8256319818471787266">נבחן</translation>
 <translation id="7568790562536448087">מעדכן</translation>
 <translation id="3910699493603749297">מקלדת חמר</translation>
diff --git a/chrome/app/resources/generated_resources_ja.xtb b/chrome/app/resources/generated_resources_ja.xtb
index 722bd016..0695ccb3 100644
--- a/chrome/app/resources/generated_resources_ja.xtb
+++ b/chrome/app/resources/generated_resources_ja.xtb
@@ -449,7 +449,6 @@
 <translation id="4950138595962845479">オプション...</translation>
 <translation id="4653235815000740718">OS リカバリ メディアの作成中に問題が発生しました。使用するストレージ デバイスが見つかりません。</translation>
 <translation id="1407489512183974736">中央トリミング</translation>
-<translation id="1870557287802238488">ページ内のメニューでパスワード メッセージの表示を指定できるようにする</translation>
 <translation id="2688196195245426394">デバイスをサーバーに登録するときにエラーが発生しました: <ph name="CLIENT_ERROR"/>。</translation>
 <translation id="1528372117901087631">インターネット接続</translation>
 <translation id="1788636309517085411">デフォルトを使用</translation>
@@ -3212,7 +3211,6 @@
 <translation id="6983783921975806247">登録されている OID</translation>
 <translation id="394984172568887996">IE ブックマーク</translation>
 <translation id="5311260548612583999">秘密鍵ファイル(省略可能):</translation>
-<translation id="2831904287943562142">ページ内のメニューでパスワード メッセージの表示を指定できるようにします。この機能を使用するとより多くのページでパスワードを保存できますが、ログインがうまくいかなかったときにもメッセージが表示されることがあります。</translation>
 <translation id="8256319818471787266">スパーキー</translation>
 <translation id="7568790562536448087">更新中:</translation>
 <translation id="3910699493603749297">クメール語キーボード</translation>
diff --git a/chrome/app/resources/generated_resources_kn.xtb b/chrome/app/resources/generated_resources_kn.xtb
index a008ac3d..a9b284e9 100644
--- a/chrome/app/resources/generated_resources_kn.xtb
+++ b/chrome/app/resources/generated_resources_kn.xtb
@@ -102,7 +102,7 @@
 <translation id="6156863943908443225">ಲಿಪಿ ಸಂಗ್ರಹ</translation>
 <translation id="6139269067241684224">MTP ಬರವಣಿಗೆ ಬೆಂಬಲವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ</translation>
 <translation id="4274187853770964845">ಸಿಂಕ್ ದೋಷ: ದಯವಿಟ್ಟು ನಿಲ್ಲಿಸಿ ಮತ್ತು ಸಿಂಕ್ ಅನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿ.</translation>
-<translation id="4209562316857013835">ಸಾಧನಗಳಾದ್ಯಂತ ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳ ಸಿಂಕ್ರೊನೈಸೇಶನ್ ಸಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ. ಸಕ್ರಿಯಗೊಳಿಸಿದಾಗ, ವೈಫೈ ರುಜುವಾತು ಡೇಟಾಟೈಪ್ ಅನ್ನು Chrome ಸಿಂಕ್ ಜೊತೆಗೆ ನೋಂದಾಯಿಸಲಾಗುತ್ತದೆ, ಮತ್ತು ಬಳಕೆದಾರರ ಪ್ರಾಶಸ್ತ್ಯಗಳಿಗೆ ಬದ್ಧವಾಗಿ ಸಿಂಕ್ರೊನೈಸ್ ಮಾಡಲಾಗುತ್ತದೆ. (ಇದನ್ನು ಸಹ ವೀಕ್ಷಿಸಿ, chrome://settings/syncSetup.)</translation>
+<translation id="4209562316857013835">ಸಾಧನಗಳಾದ್ಯಂತ Wi-Fi ನೆಟ್‌ವರ್ಕ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳ ಸಿಂಕ್ರೊನೈಸೇಶನ್ ಸಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ. ಸಕ್ರಿಯಗೊಳಿಸಿದಾಗ, ವೈಫೈ ರುಜುವಾತು ಡೇಟಾಟೈಪ್ ಅನ್ನು Chrome ಸಿಂಕ್ ಜೊತೆಗೆ ನೋಂದಾಯಿಸಲಾಗುತ್ತದೆ, ಮತ್ತು ಬಳಕೆದಾರರ ಪ್ರಾಶಸ್ತ್ಯಗಳಿಗೆ ಬದ್ಧವಾಗಿ ಸಿಂಕ್ರೊನೈಸ್ ಮಾಡಲಾಗುತ್ತದೆ. (ಇದನ್ನು ಸಹ ವೀಕ್ಷಿಸಿ, chrome://settings/syncSetup.)</translation>
 <translation id="5029568752722684782">ನಕಲು ತೆರವುಗೊಳಿಸು</translation>
 <translation id="656293578423618167">ಫೈಲ್ ಹಾದಿ ಅಥವಾ ಹೆಸರು ತುಂಬಾ ಉದ್ದವಾಗಿದೆ. ದಯವಿಟ್ಟು ಕಿರಿದಾದ ಹೆಸರಿನೊಂದಿಗೆ ಅಥವಾ ಮತ್ತೊಂದು ಸ್ಥಾನದಲ್ಲಿ ಉಳಿಸಿ. </translation>
 <translation id="3484869148456018791">ಹೊಸ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಪಡೆಯಿರಿ</translation>
@@ -407,7 +407,7 @@
 <translation id="2436707352762155834">ಕನಿಷ್ಠ</translation>
 <translation id="5556206011531515970">ನಿಮ್ಮ ಡೀಫಾಲ್ಟ್ ಬ್ರೌಸರ್ ಆಯ್ಕೆ ಮಾಡಲು ಮುಂದೆ ಕ್ಲಿಕ್ ಮಾಡಿ.</translation>
 <translation id="3382073616108123819">ಓಹ್‌‌!  ಈ ಸಾಧನಕ್ಕಾಗಿ ಸಾಧನ ಗುರುತಿಸುವಿಕೆಗಳನ್ನು ನಿರ್ಧರಿಸುವಲ್ಲಿ ಸಿಸ್ಟಂ ವಿಫಲಗೊಂಡಿದೆ.</translation>
-<translation id="782886543891417279">ನೀವು ಬಳಸುತ್ತಿರುವ ವೈ-ಫೈ (<ph name="WIFI_NAME"/>) ಅದರ ಲಾಗಿನ್ ಪುಟಕ್ಕೆ ನೀವು ಭೇಟಿ ನೀಡುವ ಅಗತ್ಯವಿದೆ.</translation>
+<translation id="782886543891417279">ನೀವು ಬಳಸುತ್ತಿರುವ Wi-Fi (<ph name="WIFI_NAME"/>) ಅದರ ಲಾಗಿನ್ ಪುಟಕ್ಕೆ ನೀವು ಭೇಟಿ ನೀಡುವ ಅಗತ್ಯವಿದೆ.</translation>
 <translation id="9041603713188951722">ವಿಂಡೋದಲ್ಲಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ತೋರಿಸು</translation>
 <translation id="5419294236999569767">ಸಿಸ್ಟಂ ಸಮಯ</translation>
 <translation id="8338952601723052325">ಡೆವಲಪರ್ ವೆಬ್‌ಸೈಟ್</translation>
@@ -447,7 +447,6 @@
 <translation id="4950138595962845479">ಆಯ್ಕೆಗಳು...</translation>
 <translation id="4653235815000740718">OS ಪುನರ್‌ಪ್ರಾಪ್ತಿ ಮಾಧ್ಯಮವನ್ನು ರಚಿಸುವಲ್ಲಿ ಒಂದು ಸಮಸ್ಯೆ ಇದೆ. ಬಳಸಿದ ಸಂಗ್ರಹ ಸಾಧನವನ್ನು ಕಂಡುಹಿಡಿಯಲಾಗುವುದಿಲ್ಲ.</translation>
 <translation id="1407489512183974736">ಮಧ್ಯಕ್ಕೆ ಕತ್ತರಿಸಲಾಗಿರುವುದು</translation>
-<translation id="1870557287802238488">ಪುಟದಲ್ಲಿ ನ್ಯಾವಿಗೇಷನ್‌ಗಳಿಗೆ ಪಾಸ್‌ವರ್ಡ್ ಪ್ರಾಂಪ್ಟ್ ತೋರಿಸುವುದನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ.</translation>
 <translation id="2688196195245426394">ಸರ್ವರ್‌ನೊಂದಿಗೆ ಸಾಧನವನ್ನು ನೋಂದಾಯಿಸುವಾಗ ದೋಷ: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">ಇಂಟರ್ನೆಟ್‌ ಸಂಪರ್ಕ</translation>
 <translation id="1788636309517085411">ಡೀಫಾಲ್ಟ್ ಬಳಸಿ</translation>
@@ -591,7 +590,7 @@
 <translation id="4865571580044923428">ವಿನಾಯಿತಿಗಳನ್ನು ನಿರ್ವಹಿಸು...</translation>
 <translation id="2526619973349913024">ನವೀಕರಣಕ್ಕಾಗಿ ಪರಿಶೀಲಿಸು</translation>
 <translation id="3716615839203649375">ಅನುಮತಿಸು</translation>
-<translation id="8298115750975731693">ನೀವು ಬಳಸುತ್ತಿರುವ ವೈ-ಫೈ (<ph name="WIFI_NAME"/>) ಗೆ ನೀವು <ph name="BEGIN_BOLD"/><ph name="LOGIN_URL"/><ph name="END_BOLD"/> ಅನ್ನು ಭೇಟಿ ನೀಡುವ ಅಗತ್ಯವಿದೆ.</translation>
+<translation id="8298115750975731693">ನೀವು ಬಳಸುತ್ತಿರುವ Wi-Fi (<ph name="WIFI_NAME"/>) ಗೆ ನೀವು <ph name="BEGIN_BOLD"/><ph name="LOGIN_URL"/><ph name="END_BOLD"/> ಅನ್ನು ಭೇಟಿ ನೀಡುವ ಅಗತ್ಯವಿದೆ.</translation>
 <translation id="8884532952272649884">ವೆಬ್‌ಪುಟವನ್ನು ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ ಏಕೆಂದರೆ ನಿಮ್ಮ ಸಾಧನವು ಜಡ ಅಥವಾ
           ಸುಪ್ತ ಮೋಡ್‌ಗೆ ತಲುಪಿದೆ. ಇದು ಸಂಭವಿಸಿದಾಗ, ನೆಟ್‌ವರ್ಕ್‌ ಸಂಪರ್ಕಗಳು 
           ಮುಚ್ಚುತ್ತವೆ ಮತ್ತು ಹೊಸ ನೆಟ್‌ವರ್ಕ್ ವಿನಂತಿಗಳು ವಿಫಲವಾಗುತ್ತವೆ. ಪುಟವನ್ನು 
@@ -1425,7 +1424,7 @@
 <translation id="6812349420832218321">ಮೂಲದಂತೆ <ph name="PRODUCT_NAME"/> ಅನ್ನು ಚಾಲನೆಮಾಡಲಾಗುವುದಿಲ್ಲ.</translation>
 <translation id="8442065444327205563">ನಿಮ್ಮ ಡಾಕ್ಯುಮೆಂಟ್ ವೀಕ್ಷಿಸಲು ಸಿದ್ಧವಿದೆ.</translation>
 <translation id="236141728043665931">ಯಾವಾಗಲೂ ಮೈಕ್ರೋಫೋನ್ ಪ್ರವೇಶವನ್ನು ನಿರ್ಬಂಧಿಸಿ</translation>
-<translation id="1122242684574577509">ದೃಢೀಕರಣ ವಿಫಲವಾಗಿದೆ. ನೀವು ಬಳಸುತ್ತಿರುವ (<ph name="NETWORK_ID"/>) ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ನ ಲಾಗಿನ್ ಪುಟಕ್ಕೆ ಭೇಟಿ ನೀಡಲು ಕ್ಲಿಕ್ ಮಾಡಿ.</translation>
+<translation id="1122242684574577509">ದೃಢೀಕರಣ ವಿಫಲವಾಗಿದೆ. ನೀವು ಬಳಸುತ್ತಿರುವ (<ph name="NETWORK_ID"/>) Wi-Fi ನೆಟ್‌ವರ್ಕ್‌ನ ಲಾಗಿನ್ ಪುಟಕ್ಕೆ ಭೇಟಿ ನೀಡಲು ಕ್ಲಿಕ್ ಮಾಡಿ.</translation>
 <translation id="82239625576146587">ಹೊಸ ಕೊರಿಯನ್ IME ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ.</translation>
 <translation id="2307462900900812319">ನೆಟ್‌ವರ್ಕ್ ಕಾನ್ಫಿಗರ್ ಮಾಡು</translation>
 <translation id="5393125431335030955">ಈ ಪ್ಲಗ್ಇನ್ ಡೆಸ್ಕ್‌ಟಾಪ್‌ನಲ್ಲಿ ಮಾತ್ರ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ.</translation>
@@ -2354,7 +2353,7 @@
 <translation id="5932901536148835538">Chromebit</translation>
 <translation id="1406500794671479665">ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ...</translation>
 <translation id="7193047015510747410">ಸ್ವಯಂತುಂಬುವಿಕೆ ಸಿಂಕ್ ರುಜುವಾತು</translation>
-<translation id="7257173066616499747">ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು</translation>
+<translation id="7257173066616499747">Wi-Fi ನೆಟ್‌ವರ್ಕ್‌ಗಳು</translation>
 <translation id="2726841397172503890">ವಾಸ್ತವದ ಕೀಬೋರ್ಡ್‌ ಬೆಂಬಲಕ್ಕಾಗಿ ಸ್ವೈಪ್ ಆಯ್ಕೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ. ವಾಸ್ತವದ ಕೀಬೋರ್ಡ್ ಸಕ್ರಿಯಗೊಳಿಸದ ಹೊರತು, ಇದು ಏನನ್ನೂ ಮಾಡುವುದಿಲ್ಲ.</translation>
 <translation id="6199801702437275229">ಅಂತರ ಮಾಹಿತಿಗಾಗಿ ನಿರೀಕ್ಷಿಸಲಾಗುತ್ತಿದೆ...</translation>
 <translation id="2767649238005085901">ಫಾರ್ವಡ್ ಮಾಡಲು enter, ಇತಿಹಾಸವನ್ನು ವೀಕ್ಷಿಸಲು ಕಾಂಟೆಕ್ಸ್ಟ್ ಮೆನು ಕೀ ಒತ್ತಿರಿ</translation>
@@ -3202,7 +3201,6 @@
 <translation id="6983783921975806247">ನೋಂದಾಯಿತ OID</translation>
 <translation id="394984172568887996">IE ಯಿಂದ ಆಮದುಗೊಂಡಿದೆ</translation>
 <translation id="5311260548612583999">ಖಾಸಗಿ ಕೀಲಿ ಫೈಲ್ (ಐಚ್ಛಿಕ):</translation>
-<translation id="2831904287943562142">ಪುಟದಲ್ಲಿ ನ್ಯಾವಿಗೇಷನ್‌ಗಳಿಗೆ ಪಾಸ್‌ವರ್ಡ್ ಪ್ರಾಂಪ್ಟ್ ತೋರಿಸುವುದನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ. ಇದು ಹಲವಾರು ಪುಟಗಳಲ್ಲಿ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ಉಳಿಸಲು ಅನುಮತಿಸುತ್ತದೆ ಆದರೆ ವಿಫಲ ಲಾಗಿನ್ ಪ್ರಯತ್ನಗಳಿಗೆ ಕೆಲವೊಮ್ಮೆ ಪ್ರಾಂಪ್ಟ್ ಅನ್ನು ಟ್ರಿಗ್ಗರ್ ಮಾಡುತ್ತದೆ.</translation>
 <translation id="8256319818471787266">ಸ್ಪಾರ್ಕಿ</translation>
 <translation id="7568790562536448087">ನವೀಕರಿಸಲಾಗುತ್ತಿದೆ</translation>
 <translation id="3910699493603749297">ಖಮೇರ್ ಕೀಬೋರ್ಡ್</translation>
@@ -3571,7 +3569,7 @@
 <translation id="4240511609794012987">ಹಂಚಿದ ಸ್ಮರಣೆ</translation>
 <translation id="7491962110804786152">ಟ್ಯಾಬ್</translation>
 <translation id="4756388243121344051">&amp;ಇತಿಹಾಸ</translation>
-<translation id="7614030880636783720">ವೈ-ಫೈ ಮತ್ತು ಮೊಬೈಲ್ ಡೇಟಾ ಲಭ್ಯವಿಲ್ಲ. ಸಾಧನವು ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕ ಸಾಧಿಸಿದಾಗ ಪುಟವನ್ನು ಲೋಡ್ ಮಾಡಬಹುದು.</translation>
+<translation id="7614030880636783720">Wi-Fi ಮತ್ತು ಮೊಬೈಲ್ ಡೇಟಾ ಲಭ್ಯವಿಲ್ಲ. ಸಾಧನವು ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕ ಸಾಧಿಸಿದಾಗ ಪುಟವನ್ನು ಲೋಡ್ ಮಾಡಬಹುದು.</translation>
 <translation id="1146673768181266552">ಕ್ರ್ಯಾಷ್ ID <ph name="CRASH_ID"/> (<ph name="CRASH_LOCAL_ID"/>)</translation>
 <translation id="3544347428588533940">Smart Lock ಬಹುತೇಕ ಸಿದ್ಧವಾಗಿದೆ</translation>
 <translation id="8044899503464538266">ನಿಧಾನ</translation>
@@ -3836,7 +3834,7 @@
 <translation id="2478176599153288112">&quot;<ph name="EXTENSION"/>&quot; ಗಾಗಿ ಮಾಧ್ಯಮ-ಫೈಲ್ ಒಪ್ಪಿಗೆಗಳು</translation>
 <translation id="3473479545200714844">ಪರದೆ ವರ್ಧಕ</translation>
 <translation id="6759193508432371551">ಫ್ಯಾಕ್ಟರಿ ಮರುಹೊಂದಿಸು</translation>
-<translation id="5557991081552967863">ನಿದ್ರೆ ಸಮಯದಲ್ಲಿ ವೈ-ಫೈ ಆನ್ ಇರಿಸಿ</translation>
+<translation id="5557991081552967863">ನಿದ್ರೆ ಸಮಯದಲ್ಲಿ Wi-Fi ಆನ್ ಇರಿಸಿ</translation>
 <translation id="6439776357918534023">ಯಾವಾಗಲೂ ರನ್ ಮಾಡಿ</translation>
 <translation id="3627588569887975815">ಲಿಂಕ್‌ ಅನ್ನು ಅಜ್ಞಾ&amp;ತ ವಿಂಡೋದಲ್ಲಿ ತೆರೆಯಿರಿ</translation>
 <translation id="5851868085455377790">ನೀಡುವವರು</translation>
@@ -3880,12 +3878,12 @@
 <translation id="7732882898097938546">ಹೊಸ ಅಪ್ಲಿಕೇಶನ್ ಲಾಂಚರ್ ಮಿಕ್ಸರ್ ಅಲ್ಗಾರಿದಮ್ ಸಕ್ರಿಯಗೊಳಿಸಿ.</translation>
 <translation id="8353683614194668312">ಇದು ಸಾಧ್ಯ:</translation>
 <translation id="1047956942837015229"><ph name="COUNT"/> ಐಟಂಗಳನ್ನು ಅಳಿಸಲಾಗುತ್ತಿದೆ...</translation>
-<translation id="2059334576206320859">ವೈ-ಫೈ ರುಜುವಾತು ಸಿಂಕ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ.</translation>
+<translation id="2059334576206320859">Wi-Fi ರುಜುವಾತು ಸಿಂಕ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ.</translation>
 <translation id="7361039089383199231">$1 ಬೈಟ್‌ಗಳು</translation>
 <translation id="191688485499383649">&quot;<ph name="DEVICE_NAME"/>&quot; ಗೆ ಸಂಪರ್ಕಪಡಿಸಲು ಪ್ರಯತ್ನಿಸುತ್ತಿರುವಾಗ ಒಂದು ಅಜ್ಞಾತ ದೋಷ ಸಂಭವಿಸಿದೆ.</translation>
 <translation id="6874681241562738119">ಸೈನ್‌-ಇನ್‌ ದೋಷ</translation>
 <translation id="5135533361271311778">ಬುಕ್‌ಮಾರ್ಕ್ ಐಟಂ ಅನ್ನು ರಚಿಸಲು ಆಗುವುದಿಲ್ಲ.</translation>
-<translation id="2828650939514476812">ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕಪಡಿಸಿ</translation>
+<translation id="2828650939514476812">Wi-Fi ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕಪಡಿಸಿ</translation>
 <translation id="4477219268485577442">ಬಲ್ಗೇರಿಯನ್ ಫೊನೆಟಿಕ್</translation>
 <translation id="5271247532544265821">ಸರಳವಾದ ಟಾಗಲ್/ಸಾಂಪ್ರದಾಯಿಕ ಚೈನೀಸ್ ಮೋಡ್</translation>
 <translation id="2052610617971448509">ನೀವು ಸಮರ್ಪಕವಾಗಿ sandbox ಅನ್ನು ಪ್ರವೇಶಿಸಿಲ್ಲ!</translation>
@@ -4063,7 +4061,7 @@
 <translation id="2740393541869613458">ಮೇಲ್ವಿಚಾರಣೆಯ ಬಳಕೆದಾರರು ಭೇಟಿ ನೀಡಿರುವ ವೆಬ್‌ಸೈಟ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ, ಮತ್ತು</translation>
 <translation id="6264347891387618177">ಲಿಪ್ಯಂತರಣ (selam → ሰላም)</translation>
 <translation id="1114091355035739006">ಮಧ್ಯಸ್ಥರನ್ನು ಬಳಸಿ, ಕಾರ್ಯನಿರ್ವಹಣಾ ಡೇಟಾದಲ್ಲಿ ಬಾಹ್ಯ ಪರಿಣಾಮವನ್ನು ತಗ್ಗಿಸುತ್ತದೆ</translation>
-<translation id="1584990664401018068">ನೀವು ಬಳಸುತ್ತಿರುವ ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್ (<ph name="NETWORK_ID"/>) ಗೆ ಪ್ರಮಾಣೀಕರಣದ ಅಗತ್ಯವಿರಬಹುದು.</translation>
+<translation id="1584990664401018068">ನೀವು ಬಳಸುತ್ತಿರುವ Wi-Fi ನೆಟ್‌ವರ್ಕ್ (<ph name="NETWORK_ID"/>) ಗೆ ಪ್ರಮಾಣೀಕರಣದ ಅಗತ್ಯವಿರಬಹುದು.</translation>
 <translation id="8919034266226953085">PWG ರಾಸ್ಟರ್ ಪರಿವರ್ತಕ</translation>
 <translation id="3330616135759834145">ಬಹು ವಿಭಿನ್ನ ವಿಷಯ ಗಾತ್ರದ ಶಿರೋನಾಮೆಗಳನ್ನು ಸ್ವೀಕರಿಸಲಾಗಿದೆ. HTTP ಪ್ರತಿಕ್ರಿಯೆ ವಿಭಜಿಸುವ ಆಕ್ರಮಣಗಳ ವಿರುದ್ಧ ರಕ್ಷಿಸಲು ಇದನ್ನು ಅನುಮತಿಸಲಾಗಿಲ್ಲ.</translation>
 <translation id="6089481419520884864">ಪುಟವನ್ನು ಶೋಧಿಸು</translation>
@@ -5206,7 +5204,7 @@
 <translation id="3943582379552582368">&amp;ಹಿಂದೆ</translation>
 <translation id="1519264250979466059">ಬಿಲ್ಡ್ ಡೇಟಾ</translation>
 <translation id="7607002721634913082">ವಿರಾಮದಲ್ಲಿದೆ</translation>
-<translation id="7928710562641958568">ಸಾಧನ ಎಜೆಕ್ಟ್ ಮಾಡಿ</translation>
+<translation id="7928710562641958568">ಸಾಧನ ತೆಗೆದುಹಾಕು</translation>
 <translation id="8729518820755801792">Chrome ನಲ್ಲಿ ಈ URL ತೆರೆಯಲಾಗುವುದಿಲ್ಲ.</translation>
 <translation id="480990236307250886">ಮುಖ ಪುಟ ತೆರೆಯಿರಿ</translation>
 <translation id="6380143666419481200">ಸಮ್ಮತಿಸಿ ಮತ್ತು ಮುಂದುವರಿಯಿರಿ</translation>
@@ -5393,7 +5391,7 @@
 <translation id="568428328938709143">ಖಾತೆ ತೆಗೆದುಹಾಕಲಾಗಿದೆ</translation>
 <translation id="5830720307094128296">&amp;ಇದರಂತೆ ಪುಟವನ್ನು ಉಳಿಸಿ...</translation>
 <translation id="2448312741937722512">ಪ್ರಕಾರ</translation>
-<translation id="3564334271939054422">ನೀವು ಬಳಸುತ್ತಿರುವ ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್ (<ph name="NETWORK_ID"/>) ನ ಲಾಗಿನ್ ಪುಟಕ್ಕೆ ನೀವು ಭೇಟಿ ನೀಡಬೇಕಾದ ಅಗತ್ಯವಿರಬಹುದು.</translation>
+<translation id="3564334271939054422">ನೀವು ಬಳಸುತ್ತಿರುವ Wi-Fi ನೆಟ್‌ವರ್ಕ್ (<ph name="NETWORK_ID"/>) ನ ಲಾಗಿನ್ ಪುಟಕ್ಕೆ ನೀವು ಭೇಟಿ ನೀಡಬೇಕಾದ ಅಗತ್ಯವಿರಬಹುದು.</translation>
 <translation id="2568958845983666692">ಕಿಲೋಬೈಟ್‌ಗಳು</translation>
 <translation id="5209320130288484488">ಯಾವ ಸಾಧನಗಳೂ ಕಂಡುಬಂದಿಲ್ಲ</translation>
 <translation id="473221644739519769">Google ಮೇಘ ಮುದ್ರಣಕ್ಕೆ ನಿಮ್ಮ ಮುದ್ರಕಗಳನ್ನು ಸೇರಿಸುವುದರಿಂದ  
diff --git a/chrome/app/resources/generated_resources_ko.xtb b/chrome/app/resources/generated_resources_ko.xtb
index ec6090b8..0dec3094 100644
--- a/chrome/app/resources/generated_resources_ko.xtb
+++ b/chrome/app/resources/generated_resources_ko.xtb
@@ -456,7 +456,6 @@
 <translation id="4950138595962845479">옵션...</translation>
 <translation id="4653235815000740718">OS 복구 미디어를 만드는 중에 문제가 발생했습니다. 사용된 저장장치를 찾을 수 없습니다.</translation>
 <translation id="1407489512183974736">가운데 부분 자르기</translation>
-<translation id="1870557287802238488">인페이지 탐색에서 비밀번호 입력 요청 메시지 표시 사용</translation>
 <translation id="2688196195245426394">기기를 서버에 등록하는 중에 오류 발생: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">인터넷 연결</translation>
 <translation id="1788636309517085411">기본값 사용</translation>
@@ -3215,7 +3214,6 @@
 <translation id="6983783921975806247">등록된 OID</translation>
 <translation id="394984172568887996">IE에서 가져온 북마크</translation>
 <translation id="5311260548612583999">비공개 키 파일(선택사항):</translation>
-<translation id="2831904287943562142">인페이지 탐색에서 비밀번호 입력 요청 메시지 표시를 사용합니다. 이렇게 하면 더 많은 페이지에 비밀번호를 저장할 수 있지만 로그인에 실패한 경우에도 요청 메시지가 표시될 수 있습니다.</translation>
 <translation id="8256319818471787266">멍멍이</translation>
 <translation id="7568790562536448087">업데이트</translation>
 <translation id="3910699493603749297">크메르어 키보드</translation>
diff --git a/chrome/app/resources/generated_resources_lt.xtb b/chrome/app/resources/generated_resources_lt.xtb
index 23d2500..e676ff49 100644
--- a/chrome/app/resources/generated_resources_lt.xtb
+++ b/chrome/app/resources/generated_resources_lt.xtb
@@ -454,7 +454,6 @@
 <translation id="4950138595962845479">Parinktys...</translation>
 <translation id="4653235815000740718">Kuriant OS atkūrimo mediją iškilo problema. Nepavyko rasti naudojamo saugojimo įrenginio.</translation>
 <translation id="1407489512183974736">Apkarpytas centre</translation>
-<translation id="1870557287802238488">Įgalinti slaptažodžio raginimo rodymą naršant puslapyje.</translation>
 <translation id="2688196195245426394">Įrenginio registravimo serveryje klaida: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">interneto ryšys</translation>
 <translation id="1788636309517085411">Naudoti numatytąją</translation>
@@ -3225,7 +3224,6 @@
 <translation id="6983783921975806247">Registruotas OID</translation>
 <translation id="394984172568887996">Importuota iš „IE“</translation>
 <translation id="5311260548612583999">Asmeninio rakto failas (pasirenkama):</translation>
-<translation id="2831904287943562142">Įgalinti slaptažodžio raginimo rodymą naršant puslapyje. Tada bus galima išsaugoti slaptažodžius daugiau puslapių, bet kartais gali būti suaktyvintas raginimas, jei nepavyksta prisijungti.</translation>
 <translation id="8256319818471787266">Žaismingasis</translation>
 <translation id="7568790562536448087">Atnaujinama</translation>
 <translation id="3910699493603749297">Khmerų klaviatūra</translation>
diff --git a/chrome/app/resources/generated_resources_lv.xtb b/chrome/app/resources/generated_resources_lv.xtb
index 44f59e2..79c321b 100644
--- a/chrome/app/resources/generated_resources_lv.xtb
+++ b/chrome/app/resources/generated_resources_lv.xtb
@@ -455,7 +455,6 @@
 <translation id="4950138595962845479">Opcijas...</translation>
 <translation id="4653235815000740718">Veidojot OS atkopšanas datu nesēju, radās problēma. Nevarēja atrast izmantoto atmiņas ierīci.</translation>
 <translation id="1407489512183974736">Apgriezt un centrēt</translation>
-<translation id="1870557287802238488">Iespējot paroles uzvednes rādīšanu, pārvietojoties lapās.</translation>
 <translation id="2688196195245426394">Reģistrējot ierīci serverī, radās kļūda: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Interneta savienojums</translation>
 <translation id="1788636309517085411">Izmantot noklusējumu</translation>
@@ -3207,7 +3206,6 @@
 <translation id="6983783921975806247">Reģistrētais OID</translation>
 <translation id="394984172568887996">Importēts no IE</translation>
 <translation id="5311260548612583999">Atslēgas fails (neob.):</translation>
-<translation id="2831904287943562142">Tiek iespējota paroles uzvednes rādīšana, pārvietojoties lapā. Tādējādi paroles var saglabāt lielākā skaitā lapu, taču dažreiz uzvedne var tikt aktivizēta nesekmīgiem pieteikšanās mēģinājumiem.</translation>
 <translation id="8256319818471787266">Džeris</translation>
 <translation id="7568790562536448087">Notiek atjaunināšana</translation>
 <translation id="3910699493603749297">Khmeru tastatūra</translation>
diff --git a/chrome/app/resources/generated_resources_ml.xtb b/chrome/app/resources/generated_resources_ml.xtb
index 612eb37..3f2a0179 100644
--- a/chrome/app/resources/generated_resources_ml.xtb
+++ b/chrome/app/resources/generated_resources_ml.xtb
@@ -456,7 +456,6 @@
 <translation id="4950138595962845479">ഓപ്‌ഷനുകള്‍‌...</translation>
 <translation id="4653235815000740718">OS റിക്കവറി മീഡിയ സൃഷ്ടിക്കുന്നതിനിടയില്‍ ഒരു പ്രശ്നമുണ്ടായി. ഉപയോഗിക്കപ്പെട്ട സംഭരണ ഉപാധി കണ്ടെത്താനായില്ല.</translation>
 <translation id="1407489512183974736">മധ്യഭാഗത്ത് മുറിക്കുക</translation>
-<translation id="1870557287802238488">പേജിലെ നാവിഗേഷനുകളിൽ പാസ്‌വേഡ് ആവശ്യപ്പെടൽ കാണിക്കുന്നത് പ്രവർത്തനക്ഷമമാക്കുക.</translation>
 <translation id="2688196195245426394">ഉപകരണം സെർവറിൽ രജിസ്റ്റർ ചെയ്യുന്നതിൽ പിശക്: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">ഇന്റർനെറ്റ് കണക്ഷൻ</translation>
 <translation id="1788636309517085411">സ്ഥിരസ്ഥിതി ഉപയോഗിക്കുക</translation>
@@ -3224,7 +3223,6 @@
 <translation id="6983783921975806247">രജിസ്‌ട്രേഡ് OID</translation>
 <translation id="394984172568887996">IE ല്‍ നിന്ന് ഇറക്കുമതി ചെയ്തവ</translation>
 <translation id="5311260548612583999">സ്വകാര്യ കീ ഫയല്‍‌ (ഐച്ഛികം):</translation>
-<translation id="2831904287943562142">പേജിലെ നാവിഗേഷനുകളിൽ പാസ്‌വേഡ് ആവശ്യപ്പെടൽ കാണിക്കുന്നത് പ്രവർത്തനക്ഷമമാക്കുക. കൂടുതൽ പേജുകളിൽ പാസ്‌വേഡുകൾ സംരക്ഷിക്കാൻ ഇത് അനുവദിക്കുമെങ്കിലും പരാജയപ്പെട്ട ലോഗിൻ ശ്രമങ്ങളിൽ ചിലപ്പോൾ ആവശ്യപ്പെടൽ പ്രവർത്തനക്ഷമമാക്കാനിടയുണ്ട്.</translation>
 <translation id="8256319818471787266">സ്‌പാർക്കി</translation>
 <translation id="7568790562536448087">അപ്‌ഡേറ്റുചെയ്യുന്നു</translation>
 <translation id="3910699493603749297">ഖമെർ കീബോർഡ്</translation>
diff --git a/chrome/app/resources/generated_resources_mr.xtb b/chrome/app/resources/generated_resources_mr.xtb
index e413813..d5a3daec 100644
--- a/chrome/app/resources/generated_resources_mr.xtb
+++ b/chrome/app/resources/generated_resources_mr.xtb
@@ -454,7 +454,6 @@
 <translation id="4950138595962845479">पर्याय...</translation>
 <translation id="4653235815000740718">OS पुनर्प्राप्ती मीडिया तयार करताना एक समस्या आली. वापरलेले संचय डिव्हाइस आढळू शकले नाही.</translation>
 <translation id="1407489512183974736">मध्यभागी क्रॉप केला</translation>
-<translation id="1870557287802238488">पृष्ठा-मधील नेव्हिगेशनवर संकेतशब्द सूचना दर्शविणे सक्षम करा.</translation>
 <translation id="2688196195245426394">सर्व्हरवर डिव्हाइसची नोंदणी करताना त्रुटी: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">इंटरनेट कनेक्शन</translation>
 <translation id="1788636309517085411">डीफॉल्ट वापरा</translation>
@@ -3224,7 +3223,6 @@
 <translation id="6983783921975806247">नोंदणीकृत OID</translation>
 <translation id="394984172568887996">IE मधून आयातित</translation>
 <translation id="5311260548612583999">खाजगी की फाइल (पर्यायी):</translation>
-<translation id="2831904287943562142">पृष्ठा-मधील नेव्हिगेशनवर संकेतशब्द सूचना दर्शविणे सक्षम करते. हे अधिक पृष्ठांवर संकेतशब्द जतन करण्याकरिता अनुमती देते परंतु कदाचित अयशस्वी प्रयत्नांवर काहीवेळा सूचना ट्रिगर करू शकते.</translation>
 <translation id="8256319818471787266">चमचमते</translation>
 <translation id="7568790562536448087">अद्यतनित करीत आहे</translation>
 <translation id="3910699493603749297">ख्मेर कीबोर्ड</translation>
diff --git a/chrome/app/resources/generated_resources_ms.xtb b/chrome/app/resources/generated_resources_ms.xtb
index 676a854..81567bcc 100644
--- a/chrome/app/resources/generated_resources_ms.xtb
+++ b/chrome/app/resources/generated_resources_ms.xtb
@@ -455,7 +455,6 @@
 <translation id="4950138595962845479">Pilihan...</translation>
 <translation id="4653235815000740718">Terdapat masalah semasa mencipta media pemulihan OS. Peranti storan terpakai tidak dapat dijumpai.</translation>
 <translation id="1407489512183974736">Tengah Dipotong</translation>
-<translation id="1870557287802238488">Dayakan pemaparan gesaan kata laluan di halaman navigasi.</translation>
 <translation id="2688196195245426394">Ralat semasa mendaftarkan peranti dengan pelayan: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Sambungan internet</translation>
 <translation id="1788636309517085411">Gunakan lalai</translation>
@@ -3232,7 +3231,6 @@
 <translation id="6983783921975806247">OID berdaftar</translation>
 <translation id="394984172568887996">Diimport Daripada IE</translation>
 <translation id="5311260548612583999">Fail kunci persendirian (pilihan):</translation>
-<translation id="2831904287943562142">Dayakan pemaparan gesaan kata laluan di halaman navigasi. Ini membolehkan penyimpan kata laluan pada lebih halaman tetapi kadangkala mungkin mencetuskan gesaan pada cubaan log masuk tidak berjaya.</translation>
 <translation id="8256319818471787266">Sparky</translation>
 <translation id="7568790562536448087">Mengemas kini</translation>
 <translation id="3910699493603749297">Papan kekunci bahasa Khmer</translation>
diff --git a/chrome/app/resources/generated_resources_nl.xtb b/chrome/app/resources/generated_resources_nl.xtb
index 0de8dbb..c3ca2718 100644
--- a/chrome/app/resources/generated_resources_nl.xtb
+++ b/chrome/app/resources/generated_resources_nl.xtb
@@ -462,7 +462,6 @@
 <translation id="4950138595962845479">Opties...</translation>
 <translation id="4653235815000740718">Er is een probleem opgetreden tijdens het maken van het OS-herstelmedium. Het gebruikte opslagapparaat kan niet worden gevonden.</translation>
 <translation id="1407489512183974736">Midden bijsnijden</translation>
-<translation id="1870557287802238488">Weergeven van wachtwoordprompt bij navigatie op pagina inschakelen.</translation>
 <translation id="2688196195245426394">Fout bij het registreren van het apparaat bij de server: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Internetverbinding</translation>
 <translation id="1788636309517085411">Standaard gebruiken</translation>
@@ -3228,7 +3227,6 @@
 <translation id="6983783921975806247">Geregistreerde OID</translation>
 <translation id="394984172568887996">Geïmporteerd uit Internet Explorer</translation>
 <translation id="5311260548612583999">Privésleutelbestand (optioneel):</translation>
-<translation id="2831904287943562142">Weergeven van de wachtwoord bij navigatie op pagina inschakelen. Hiermee kunnen wachtwoorden op meer pagina's worden opgeslagen, maar kan de prompt soms worden geactiveerd bij mislukte inlogpogingen.</translation>
 <translation id="8256319818471787266">Bello</translation>
 <translation id="7568790562536448087">Bijwerken</translation>
 <translation id="3910699493603749297">Khmer toetsenbord</translation>
diff --git a/chrome/app/resources/generated_resources_no.xtb b/chrome/app/resources/generated_resources_no.xtb
index 61fdd4ac..04a90cc 100644
--- a/chrome/app/resources/generated_resources_no.xtb
+++ b/chrome/app/resources/generated_resources_no.xtb
@@ -450,7 +450,6 @@
 <translation id="4950138595962845479">Alternativer</translation>
 <translation id="4653235815000740718">Det oppstod et problem under opprettelse av gjenopprettingsmedium for operativsystem. Fant ikke lagringsenheten som har blitt brukt.</translation>
 <translation id="1407489512183974736">Midstill og beskjær</translation>
-<translation id="1870557287802238488">Slå på visning av passordforespørsler i navigeringen på sider.</translation>
 <translation id="2688196195245426394">Feil under registreringen av enheten hos tjeneren: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Internett-tilkobling</translation>
 <translation id="1788636309517085411">Bruk standard</translation>
@@ -3199,7 +3198,6 @@
 <translation id="6983783921975806247">Registrert OID</translation>
 <translation id="394984172568887996">Importert fra Internet Explorer</translation>
 <translation id="5311260548612583999">Privat nøkkelfil (valgfritt):</translation>
-<translation id="2831904287943562142">Slå på visning av passordforespørsler i navigeringen på sider. Dette gjør det mulig å lagre passord på flere sider. Det kan imidlertid noen ganger føre til at forespørselen vises ved mislykkede påloggingsforsøk.</translation>
 <translation id="8256319818471787266">Fido</translation>
 <translation id="7568790562536448087">Oppdaterer</translation>
 <translation id="3910699493603749297">Khmer-tastatur</translation>
diff --git a/chrome/app/resources/generated_resources_pl.xtb b/chrome/app/resources/generated_resources_pl.xtb
index 6a1b93d..1a2c330 100644
--- a/chrome/app/resources/generated_resources_pl.xtb
+++ b/chrome/app/resources/generated_resources_pl.xtb
@@ -448,7 +448,6 @@
 <translation id="4950138595962845479">Opcje</translation>
 <translation id="4653235815000740718">Wystąpił problem podczas tworzenia nośnika odzyskiwania systemu operacyjnego. Nie można znaleźć użytego urządzenia pamięci masowej.</translation>
 <translation id="1407489512183974736">Wyśrodkuj i przytnij</translation>
-<translation id="1870557287802238488">Włącz wyświetlanie prośby o hasło w nawigacji na stronie.</translation>
 <translation id="2688196195245426394">Podczas rejestrowania urządzenia na serwerze wystąpił błąd: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Połączenie internetowe</translation>
 <translation id="1788636309517085411">Użyj wartości domyślnej</translation>
@@ -3192,7 +3191,6 @@
 <translation id="6983783921975806247">Zarejestrowany identyfikator OID</translation>
 <translation id="394984172568887996">Importowane z IE</translation>
 <translation id="5311260548612583999">Plik kluczy (opcjonalnie):</translation>
-<translation id="2831904287943562142">Włącz wyświetlanie prośby o hasło w nawigacji na stronie. Pozwala to zapisywać hasła na wielu stronach, ale prośba może się czasem wyświetlić w przypadku nieudanej próby logowania.</translation>
 <translation id="8256319818471787266">Tofik</translation>
 <translation id="7568790562536448087">Aktualizowanie</translation>
 <translation id="3910699493603749297">Klawiatura khmerska</translation>
diff --git a/chrome/app/resources/generated_resources_pt-BR.xtb b/chrome/app/resources/generated_resources_pt-BR.xtb
index 5365e67..f9fc269c4 100644
--- a/chrome/app/resources/generated_resources_pt-BR.xtb
+++ b/chrome/app/resources/generated_resources_pt-BR.xtb
@@ -448,7 +448,6 @@
 <translation id="4950138595962845479">Opções...</translation>
 <translation id="4653235815000740718">Ocorreu um problema ao criar a mídia de recuperação de sistema operacional. Não foi possível encontrar o dispositivo de armazenamento usado.</translation>
 <translation id="1407489512183974736">Cortar para centralizar</translation>
-<translation id="1870557287802238488">Ativar exibição de solicitação de senha para navegação na página.</translation>
 <translation id="2688196195245426394">Erro ao registrar o dispositivo no cliente: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Conexão com a Internet</translation>
 <translation id="1788636309517085411">Usar padrão</translation>
@@ -3199,7 +3198,6 @@
 <translation id="6983783921975806247">OID registrado</translation>
 <translation id="394984172568887996">Importado do IE</translation>
 <translation id="5311260548612583999">Arq. de chave privada (opcional):</translation>
-<translation id="2831904287943562142">Ativar exibição da solicitação de senha para navegação na página. Isso permite salvar senhas em mais páginas, mas pode, por vezes, acionar a solicitação em tentativas mal-sucedidas de login.</translation>
 <translation id="8256319818471787266">Totó</translation>
 <translation id="7568790562536448087">Atualização</translation>
 <translation id="3910699493603749297">Teclado em khmer</translation>
diff --git a/chrome/app/resources/generated_resources_pt-PT.xtb b/chrome/app/resources/generated_resources_pt-PT.xtb
index 2e6d5ea4..8c5b6ba 100644
--- a/chrome/app/resources/generated_resources_pt-PT.xtb
+++ b/chrome/app/resources/generated_resources_pt-PT.xtb
@@ -454,7 +454,6 @@
 <translation id="4950138595962845479">Opções...</translation>
 <translation id="4653235815000740718">Ocorreu um problema ao criar o suporte de dados de recuperação do SO. Não foi possível localizar o dispositivo de armazenamento utilizado.</translation>
 <translation id="1407489512183974736">Cortado no centro</translation>
-<translation id="1870557287802238488">Ativar apresentação da solicitação de palavra-passe em navegações de página.</translation>
 <translation id="2688196195245426394">Erro ao registar o dispositivo no servidor: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Ligação à internet</translation>
 <translation id="1788636309517085411">Utilizar predefinição</translation>
@@ -3206,7 +3205,6 @@
 <translation id="6983783921975806247">OID registado</translation>
 <translation id="394984172568887996">Importado do IE</translation>
 <translation id="5311260548612583999">Ficheiro chave privada (opcional):</translation>
-<translation id="2831904287943562142">Ative a apresentação da solicitação de palavra-passe em navegações de página. Isto permite guardar palavras-passe em mais páginas, mas pode acionar ocasionalmente o aviso de tentativas de início de sessão sem êxito.</translation>
 <translation id="8256319818471787266">Pantufa</translation>
 <translation id="7568790562536448087">A atualizar</translation>
 <translation id="3910699493603749297">Teclado khmer</translation>
diff --git a/chrome/app/resources/generated_resources_ro.xtb b/chrome/app/resources/generated_resources_ro.xtb
index 0c4dee73..c2e5a1ff 100644
--- a/chrome/app/resources/generated_resources_ro.xtb
+++ b/chrome/app/resources/generated_resources_ro.xtb
@@ -458,7 +458,6 @@
 <translation id="4950138595962845479">Opțiuni...</translation>
 <translation id="4653235815000740718">A apărut o problemă la crearea suportului de recuperare a sistemului de operare. Nu s-a găsit dispozitivul de stocare utilizat.</translation>
 <translation id="1407489512183974736">Pe centru, decupat</translation>
-<translation id="1870557287802238488">Activează afișarea solicitării de parolă pentru navigările în pagină.</translation>
 <translation id="2688196195245426394">Eroare la înregistrarea gadgetului pe server: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Conexiune la internet</translation>
 <translation id="1788636309517085411">Utilizează setările prestabilite</translation>
@@ -3239,7 +3238,6 @@
 <translation id="6983783921975806247">OID înregistrat</translation>
 <translation id="394984172568887996">Importate din IE</translation>
 <translation id="5311260548612583999">Fișier cheie privată (opțional):</translation>
-<translation id="2831904287943562142">Activează afișarea solicitării de parolă pentru navigările în pagină. Aceasta permite salvarea parolelor pe mai multe pagini, însă uneori poate să declanșeze solicitarea în cazul încercărilor de conectare nereușite.</translation>
 <translation id="8256319818471787266">Lăbuș</translation>
 <translation id="7568790562536448087">Se actualizează</translation>
 <translation id="3910699493603749297">Tastatură khmeră</translation>
diff --git a/chrome/app/resources/generated_resources_ru.xtb b/chrome/app/resources/generated_resources_ru.xtb
index 9c120d82..12b64f64 100644
--- a/chrome/app/resources/generated_resources_ru.xtb
+++ b/chrome/app/resources/generated_resources_ru.xtb
@@ -447,7 +447,6 @@
 <translation id="4950138595962845479">Параметры…</translation>
 <translation id="4653235815000740718">При создании образа для восстановления системы произошла ошибка. Используемый накопитель не найден.</translation>
 <translation id="1407489512183974736">Кадрировать и выровнять по центру</translation>
-<translation id="1870557287802238488">Показывать запросы на сохранение паролей во время навигации</translation>
 <translation id="2688196195245426394">Ошибка при регистрации устройства на сервере: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Подключение к Интернету</translation>
 <translation id="1788636309517085411">Использовать по умолчанию</translation>
@@ -3197,7 +3196,6 @@
 <translation id="6983783921975806247">Зарегистрированный OID</translation>
 <translation id="394984172568887996">Импортировано из IE</translation>
 <translation id="5311260548612583999">Файл закрытого ключа (необязательно):</translation>
-<translation id="2831904287943562142">Позволяет сохранять пароли для большего числа страниц. Однако учтите, что запросы на сохранение будут отображаться даже в том случае, если вы неверно введете имя пользователя или пароль.</translation>
 <translation id="8256319818471787266">Дружок</translation>
 <translation id="7568790562536448087">Обновление</translation>
 <translation id="3910699493603749297">Кхмерская раскладка</translation>
@@ -3347,7 +3345,7 @@
 <translation id="5931146425219109062">Просмотр и изменение ваших данных на посещаемых сайтах</translation>
 <translation id="3655670868607891010">Если эта проблема возникает часто, изучите <ph name="HELP_LINK"/>.</translation>
 <translation id="4504940961672722399">Активируйте это расширение, нажав на значок или с помощью комбинации клавиш <ph name="EXTENSION_SHORTCUT"/>.</translation>
-<translation id="2523966157338854187">Заданные страницы:</translation>
+<translation id="2523966157338854187">Заданные страницы</translation>
 <translation id="4176463684765177261">Отключено</translation>
 <translation id="2483350027598201151">МБ</translation>
 <translation id="154603084978752493">Добавить как поисковую &amp;систему...</translation>
@@ -3418,7 +3416,7 @@
 <translation id="4910673011243110136">Частные сети</translation>
 <translation id="2527167509808613699">при любом типе подключения</translation>
 <translation id="653019979737152879">Синхронизация файла &quot;<ph name="FILE_NAME"/>&quot;…</translation>
-<translation id="8662795692588422978">Люди</translation>
+<translation id="8662795692588422978">Пользователи</translation>
 <translation id="8072988827236813198">Закрепить вкладки</translation>
 <translation id="2673589024369449924">Создать ярлык этого профиля на рабочем столе</translation>
 <translation id="4330523403413375536">Включить экспериментальные инструменты разработчика. Используйте панель настроек инструментов разработчика для переключения между экспериментами.</translation>
@@ -4982,7 +4980,7 @@
 <translation id="3954582159466790312">Вк&amp;лючить звук</translation>
 <translation id="1110772031432362678">Сети не найдены.</translation>
 <translation id="6187344976531853059">Перенос окон на другой рабочий стол дает неожиданные эффекты.</translation>
-<translation id="1839913225882990152">Описание проблемы.</translation>
+<translation id="1839913225882990152">Описание проблемы</translation>
 <translation id="3936390757709632190">&amp;Открыть аудиозапись на новой вкладке</translation>
 <translation id="8559748832541950395">Вы можете в любое время отключить запись Истории голосового управления или <ph name="BEGIN_LINK"/>изменить<ph name="END_LINK"/> сохраненные данные. Когда эта функция включена, мы можем получать данные со всех устройств, на которых вы вошли в аккаунт Google.</translation>
 <translation id="143027896309062157">Просмотр и изменение данных на вашем компьютере и посещаемых сайтах</translation>
@@ -5453,7 +5451,7 @@
 <translation id="8941882480823041320">К предыдущему слову</translation>
 <translation id="2489435327075806094">Скорость указателя:</translation>
 <translation id="2574102660421949343">Файлы cookie с сайта <ph name="DOMAIN"/> разрешены.</translation>
-<translation id="2773948261276885771">добавить</translation>
+<translation id="2773948261276885771">Довавить</translation>
 <translation id="3688526734140524629">Выбрать другую версию</translation>
 <translation id="4959447747655704388">Если вы готовы подвергнуть риску ваши личные данные, вы можете <ph name="BEGIN_LINK"/>перейти на зараженный сайт<ph name="END_LINK"/>.</translation>
 <translation id="7030084719913890980">Этот сайт пострадал от злоумышленников и может установить на ваш компьютер вредоносное ПО, которое крадет или удаляет личную информацию (например, фотографии, пароли, сообщения и реквизиты банковских карт).</translation>
@@ -5479,7 +5477,7 @@
 <translation id="4746971725921104503">Похоже, здесь уже есть пользователь с таким именем. <ph name="LINK_START"/>Импортировать данные пользователя <ph name="USER_DISPLAY_NAME"/> на это устройство<ph name="LINK_END"/>?</translation>
 <translation id="8142699993796781067">Частные сети</translation>
 <translation id="3517839692979918726"><ph name="APP_NAME"/> хочет предоставить доступ к вашему экрану. Выберите окно, которое вы хотите показать.</translation>
-<translation id="17513872634828108">Открыть вкладки</translation>
+<translation id="17513872634828108">Открытые вкладки</translation>
 <translation id="1374468813861204354">подсказки</translation>
 <translation id="5906065664303289925">Аппаратный адрес:</translation>
 <translation id="2498436043474441766">Добавление принтеров</translation>
diff --git a/chrome/app/resources/generated_resources_sk.xtb b/chrome/app/resources/generated_resources_sk.xtb
index d400445..cc817b8 100644
--- a/chrome/app/resources/generated_resources_sk.xtb
+++ b/chrome/app/resources/generated_resources_sk.xtb
@@ -454,7 +454,6 @@
 <translation id="4950138595962845479">Možnosti...</translation>
 <translation id="4653235815000740718">Pri vytváraní obnovovacieho média OS sa vyskytol problém. Nepodarilo sa nájsť používané zariadenie s ukladacím priestorom.</translation>
 <translation id="1407489512183974736">Orezať na stred</translation>
-<translation id="1870557287802238488">Povolenie zobrazovania výzvy na zadanie hesla v navigačných poliach na stránke</translation>
 <translation id="2688196195245426394">Pri registrácii zariadenia na serveri <ph name="CLIENT_ERROR"/> sa vyskytla chyba.</translation>
 <translation id="1528372117901087631">Pripojenie k internetu</translation>
 <translation id="1788636309517085411">Použiť predvolenú pozíciu</translation>
@@ -3205,7 +3204,6 @@
 <translation id="6983783921975806247">Registrovaný identifikátor OID</translation>
 <translation id="394984172568887996">Importované z prehliadača IE</translation>
 <translation id="5311260548612583999">Súkromný kľúč (nepovinné):</translation>
-<translation id="2831904287943562142">Povolí zobrazovanie výzvy na zadanie hesla v navigačných poliach na stránke. Umožní to ukladať heslá na viacerých stránkach, avšak môže niekedy vyvolať výzvu pri neúspešných pokusoch o prihlásenie.</translation>
 <translation id="8256319818471787266">Rexo</translation>
 <translation id="7568790562536448087">Prebieha aktualizácia</translation>
 <translation id="3910699493603749297">Klávesnica pre khmérčinu</translation>
diff --git a/chrome/app/resources/generated_resources_sl.xtb b/chrome/app/resources/generated_resources_sl.xtb
index ea463ba..ac585849 100644
--- a/chrome/app/resources/generated_resources_sl.xtb
+++ b/chrome/app/resources/generated_resources_sl.xtb
@@ -454,7 +454,6 @@
 <translation id="4950138595962845479">Možnosti ...</translation>
 <translation id="4653235815000740718">Pri ustvarjanju nosilca podatkov za obnovitev operacijskega sistema je prišlo do težave. Uporabljene naprave za shranjevanje ni bilo mogoče najti.</translation>
 <translation id="1407489512183974736">Na sredino in obrezano</translation>
-<translation id="1870557287802238488">Omogoči prikazovanje poziva za geslo v krmarjenjih na strani.</translation>
 <translation id="2688196195245426394">Napaka pri registraciji naprave v strežniku: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Internetna povezava</translation>
 <translation id="1788636309517085411">Uporabi privzeto</translation>
@@ -3218,7 +3217,6 @@
 <translation id="6983783921975806247">Registriran OID</translation>
 <translation id="394984172568887996">Uvoženo iz IE</translation>
 <translation id="5311260548612583999">Dat. z zaseb. klj. (neobv.)</translation>
-<translation id="2831904287943562142">Omogoči prikaz poziva za geslo v krmarjenjih na strani. Tako se lahko gesla shranjujejo na več straneh, vendar se včasih poziv sproži pri neuspešnih poskusih prijave.</translation>
 <translation id="8256319818471787266">Piki</translation>
 <translation id="7568790562536448087">Posodabljanje</translation>
 <translation id="3910699493603749297">Tipkovnica za kmerščino</translation>
diff --git a/chrome/app/resources/generated_resources_sr.xtb b/chrome/app/resources/generated_resources_sr.xtb
index db7c9554..a312122 100644
--- a/chrome/app/resources/generated_resources_sr.xtb
+++ b/chrome/app/resources/generated_resources_sr.xtb
@@ -454,7 +454,6 @@
 <translation id="4950138595962845479">Опције...</translation>
 <translation id="4653235815000740718">Дошло је до проблема при прављењу медијума за обнављање ОС-а. Употребљени меморијски уређај није пронађен.</translation>
 <translation id="1407489512183974736">Опсеци централно</translation>
-<translation id="1870557287802238488">Омогући приказивање упита за лозинку при навигацијама по страницама.</translation>
 <translation id="2688196195245426394">Грешка при регистровању уређаја на сервер: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Интернет веза</translation>
 <translation id="1788636309517085411">Користи подразумевано</translation>
@@ -3213,7 +3212,6 @@
 <translation id="6983783921975806247">Регистровани OID</translation>
 <translation id="394984172568887996">Увезено из IE прегледача</translation>
 <translation id="5311260548612583999">Приватни кључ (опционално)</translation>
-<translation id="2831904287943562142">Омогућава приказивање упита за лозинку при навигацијама по страницама. То омогућава чување лозинки на још страница, али може понекад да покрене упит при неуспешним покушајима пријављивања.</translation>
 <translation id="8256319818471787266">Искрица</translation>
 <translation id="7568790562536448087">Ажурирање</translation>
 <translation id="3910699493603749297">Кмерска тастатура</translation>
diff --git a/chrome/app/resources/generated_resources_sv.xtb b/chrome/app/resources/generated_resources_sv.xtb
index 4cb9dea..c7312ef 100644
--- a/chrome/app/resources/generated_resources_sv.xtb
+++ b/chrome/app/resources/generated_resources_sv.xtb
@@ -459,7 +459,6 @@
 <translation id="4950138595962845479">Alternativ...</translation>
 <translation id="4653235815000740718">Det uppstod ett problem när återställningsmedia skapades för operativsystemet. Det gick inte att hitta lagringsenheten som användes.</translation>
 <translation id="1407489512183974736">Centrera och beskär</translation>
-<translation id="1870557287802238488">Aktivera fråga om att spara lösenord vid navigering på sidan.</translation>
 <translation id="2688196195245426394">Det uppstod ett fel när enheten registrerades med servern: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Internetanslutning</translation>
 <translation id="1788636309517085411">Använd standardinställning</translation>
@@ -3212,7 +3211,6 @@
 <translation id="6983783921975806247">Registrerat OID</translation>
 <translation id="394984172568887996">Importerat från IE</translation>
 <translation id="5311260548612583999">Privat nyckelfil (valfritt):</translation>
-<translation id="2831904287943562142">Aktivera fråga om att spara lösenord vid navigering på sidan. Detta gör att du kan spara lösenordet på fler sidor, men i vissa fall kan det också leda till att frågan visas vid misslyckade inloggningsförsök.</translation>
 <translation id="8256319818471787266">Ludde</translation>
 <translation id="7568790562536448087">Uppdaterar</translation>
 <translation id="3910699493603749297">Khmeriskt tangentbord</translation>
diff --git a/chrome/app/resources/generated_resources_sw.xtb b/chrome/app/resources/generated_resources_sw.xtb
index bfa550f..c00500b 100644
--- a/chrome/app/resources/generated_resources_sw.xtb
+++ b/chrome/app/resources/generated_resources_sw.xtb
@@ -457,7 +457,6 @@
 <translation id="4950138595962845479">Chaguo...</translation>
 <translation id="4653235815000740718">Kulikuwa na tatizo wakati wa kuunda media ya kufufua OS. Kifaa cha hifadhi kilichotumiwa hakikuweza kupatikana.</translation>
 <translation id="1407489512183974736">Imepogolewa Katikati</translation>
-<translation id="1870557287802238488">Washa uonyeshaji wa swali kuhusu nenosiri wakati wa kudurusu kurasa za ndani.</translation>
 <translation id="2688196195245426394">Hitilafu wakati wa kusajili kifaa kwa seva: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Muunganisho wa mtandao</translation>
 <translation id="1788636309517085411">Tumia chaguo-msingi</translation>
@@ -3209,7 +3208,6 @@
 <translation id="6983783921975806247">OID Iliyosajiliwa</translation>
 <translation id="394984172568887996">Zilizoingizwa Kutoka IE</translation>
 <translation id="5311260548612583999">Faili ya ufunguo wa kibinafsi (hiari):</translation>
-<translation id="2831904287943562142">Washa uonyeshaji wa swali la nenosiri kwa kudurusu kurasa za ndani. Hili linaruhusu kuhifadhi manenosiri kwenye kurasa zaidi lakini wakati mwingine linaweza kuanzisha swali kwa majaribio ambayo hayajafaulu kuingia katika akaunti.</translation>
 <translation id="8256319818471787266">Spaki</translation>
 <translation id="7568790562536448087">Inasasisha</translation>
 <translation id="3910699493603749297">Kibodi ya Khmer</translation>
diff --git a/chrome/app/resources/generated_resources_ta.xtb b/chrome/app/resources/generated_resources_ta.xtb
index 54e43e0..9826aca 100644
--- a/chrome/app/resources/generated_resources_ta.xtb
+++ b/chrome/app/resources/generated_resources_ta.xtb
@@ -455,7 +455,6 @@
 <translation id="4950138595962845479">விருப்பங்கள்...</translation>
 <translation id="4653235815000740718">OS மீட்பு மீடியாவை உருவாக்குவதில் சிக்கல் ஏற்பட்டது. பயன்படுத்தப்பட்ட சேகரிக்கப்பட்ட சாதனத்தைக் கண்டறிய முடியவில்லை.</translation>
 <translation id="1407489512183974736">மையமாக வெட்டப்பட்டது</translation>
-<translation id="1870557287802238488">பக்கத்தின் உள்ளான வழிசெலுத்தல்களில் கடவுச்சொல் குறித்த கேள்வியை இயக்கவும்.</translation>
 <translation id="2688196195245426394">வேறு சேவையகத்துடன் சாதனத்தைப் பதிவுசெய்யும்போது பிழை: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">இணைய இணைப்பு</translation>
 <translation id="1788636309517085411">இயல்புநிலையைப் பயன்படுத்து</translation>
@@ -763,7 +762,7 @@
 <translation id="3280431534455935878">தயாராகிறது</translation>
 <translation id="5543983818738093899">நிலையைச் சரிபார்க்கிறது...</translation>
 <translation id="3897092660631435901">மெனு</translation>
-<translation id="5624407043686221179">சர்வபுலக் கீழ்த்தோன்றல் பட்டியில் உள்ள தலைப்புகளைத் தனிப்படுத்து</translation>
+<translation id="5624407043686221179">சர்வபுலக் கீழ்த்தோன்றல் பட்டியில் உள்ள தலைப்புகளுக்கு முக்கியத்துவம் தரவும்</translation>
 <translation id="7024867552176634416">பயன்படுத்துவதற்கு, அகற்றத்தக்க சேமிப்பக சாதனத்தைத் தேர்வு செய்க</translation>
 <translation id="7794058097940213561">சாதனத்தை வடிவமை</translation>
 <translation id="1119069657431255176">Bzip2 compressed tar archive</translation>
@@ -1139,7 +1138,7 @@
 <translation id="7219357088166514551"><ph name="ENGINE"/> இல் தேடுக அல்லது URL ஐத் தட்டச்சு செய்க</translation>
 <translation id="1832511806131704864">ஃபோன் மாற்றம் புதுப்பிக்கப்பட்டது</translation>
 <translation id="4684427112815847243">அனைத்தையும் ஒத்திசை</translation>
-<translation id="5630163645818715367">சிறந்த உலாவியான chrome, இப்போது மெட்டீரியல் வடிவமைப்பில் கிடைக்கிறது</translation>
+<translation id="5630163645818715367">உலாவியின் மேல் குரோமில் மெட்டீரியல் வடிவமைப்பு</translation>
 <translation id="2498857833812906273">Chromeஐ நிறுத்தும் போது, ஹோஸ்ட் செய்த பயன்பாடுகள் இயங்கினால் அறிவிப்பைக் காட்டவும்.</translation>
 <translation id="4699357559218762027">(தானாக துவக்கப்பட்டது)</translation>
 <translation id="4037463823853863991">Android க்கான அணுகல் தாவலின் மாற்றியை இயக்கவும்.</translation>
@@ -2461,7 +2460,7 @@
 <translation id="7434509671034404296">டெவலப்பர்</translation>
 <translation id="7668654391829183341">அறியப்படாத சாதனம்</translation>
 <translation id="2712173769900027643">அனுமதி கேள்</translation>
-<translation id="2053298192223252950">chrome உலாவியின் மெட்டீரியல் வடிவமைப்புக் கூறுகளை இயக்கும் அல்லது முடக்கும்.</translation>
+<translation id="2053298192223252950">உலாவியின் குரோமில் மெட்டீரியல் வடிவமைப்புக் கூறுகளை இயக்கும் அல்லது முடக்கும்.</translation>
 <translation id="1790550373387225389">விளக்கக்காட்சி பயன்முறையில் உள்நுழை</translation>
 <translation id="6447842834002726250">குக்கீகள்</translation>
 <translation id="8059178146866384858">&quot;$1&quot; என்ற பெயருள்ள கோப்பு ஏற்கனவே உள்ளது. வேறு பெயரைத் தேர்வுசெய்க.</translation>
@@ -3202,7 +3201,6 @@
 <translation id="6983783921975806247">பதிவுசெய்யப்பட்ட OID</translation>
 <translation id="394984172568887996">IE இலிருந்து இறக்குமதி செய்யப்பட்டது</translation>
 <translation id="5311260548612583999">தனிப்பட்ட விசை கோப்பு (விரும்பினால்):</translation>
-<translation id="2831904287943562142">பக்கத்தின் உள்ளான வழிசெலுத்தல்களில் கடவுச்சொல் குறித்த கேள்வியை இயக்கவும். இது அதிக பக்கங்களில் கடவுச்சொற்களைச் சேமிப்பதை அனுமதிக்கும் எனினும், தோல்வியுறும் உள்நுழைவு முயற்சிகளில் கடவுச்சொல் குறித்த கேள்வியைக் கேட்கலாம்.</translation>
 <translation id="8256319818471787266">ஸ்பார்க்கி</translation>
 <translation id="7568790562536448087">புதுப்பிக்கிறது</translation>
 <translation id="3910699493603749297">கெமர் விசைப்பலகை</translation>
diff --git a/chrome/app/resources/generated_resources_te.xtb b/chrome/app/resources/generated_resources_te.xtb
index a22c46f7..0257d59 100644
--- a/chrome/app/resources/generated_resources_te.xtb
+++ b/chrome/app/resources/generated_resources_te.xtb
@@ -452,7 +452,6 @@
 <translation id="4950138595962845479">ఎంపికలు...</translation>
 <translation id="4653235815000740718">OS రికవరీ మీడియాని సృష్టిస్తున్నప్పుడు ఒక లోపం సంభవించింది. ఉపయోగించిన నిల్వ పరికరం కనుగొనబడలేదు.</translation>
 <translation id="1407489512183974736">మధ్యకు కత్తిరించు</translation>
-<translation id="1870557287802238488">పేజీలో నావిగేషన్‌ల్లో పాస్‌వర్డ్ ప్రాంప్ట్‌ని చూపడాన్ని ప్రారంభించండి.</translation>
 <translation id="2688196195245426394">పరికరం సర్వర్‌తో నమోదు అవుతున్నప్పుడు లోపం: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">ఇంటర్నెట్ కనెక్షన్</translation>
 <translation id="1788636309517085411">డిఫాల్ట్ ఉపయోగించు</translation>
@@ -3215,7 +3214,6 @@
 <translation id="6983783921975806247">రిజిస్టర్ చేసిన OID</translation>
 <translation id="394984172568887996">IE నుండి దిగుమతి చెయ్యబడింది</translation>
 <translation id="5311260548612583999">వ్యక్తిగత కీ ఫైల్ (ఇచ్ఛాపూరితం):</translation>
-<translation id="2831904287943562142">పేజీలో నావిగేషన్‌ల్లో పాస్‌వర్డ్ ప్రాంప్ట్‌ని చూపడాన్ని ప్రారంభించండి. ఇది మరిన్ని పేజీల్లో పాస్‌వర్డ్‌లను సేవ్ చేయడానికి అనుమతిస్తుంది కానీ కొన్నిసార్లు విజయవంతం కాని లాగిన్ ప్రయత్నాల్లో ప్రాంప్ట్ చేయడాన్ని ప్రారంభించవచ్చు.</translation>
 <translation id="8256319818471787266">స్పార్కీ</translation>
 <translation id="7568790562536448087">నవీకరిస్తోంది</translation>
 <translation id="3910699493603749297">ఖ్మేర్ కీబోర్డ్</translation>
diff --git a/chrome/app/resources/generated_resources_th.xtb b/chrome/app/resources/generated_resources_th.xtb
index eab4e9c..59458f2 100644
--- a/chrome/app/resources/generated_resources_th.xtb
+++ b/chrome/app/resources/generated_resources_th.xtb
@@ -445,7 +445,6 @@
 <translation id="4950138595962845479">ตัวเลือก...</translation>
 <translation id="4653235815000740718">เกิดปัญหาขณะสร้างสื่อการกู้คืนระบบปฏิบัติการ ไม่พบอุปกรณ์จัดเก็บข้อมูลที่ใช้</translation>
 <translation id="1407489512183974736">ครอบตัดที่กึ่งกลาง</translation>
-<translation id="1870557287802238488">เปิดใช้การแสดงหน้าต่างสอบถามรหัสผ่านบนการนำทางในหน้าเว็บ</translation>
 <translation id="2688196195245426394">เกิดข้อผิดพลาดขณะลงทะเบียนอุปกรณ์กับเซิร์ฟเวอร์: <ph name="CLIENT_ERROR"/></translation>
 <translation id="1528372117901087631">การเชื่อมต่ออินเทอร์เน็ต</translation>
 <translation id="1788636309517085411">ใช้ค่าเริ่มต้น</translation>
@@ -3179,7 +3178,6 @@
 <translation id="6983783921975806247">OID ที่ลงทะเบียนแล้ว</translation>
 <translation id="394984172568887996">นำเข้าจาก IE</translation>
 <translation id="5311260548612583999">ไฟล์กุญแจส่วนตัว (ตัวเลือก):</translation>
-<translation id="2831904287943562142">เปิดใช้การแสดงหน้าต่างสอบถามรหัสผ่านบนการนำทางในหน้าเว็บ ซึ่งจะอนุญาตให้บันทึกรหัสผ่านบนหน้าเพิ่มเติมได้ แต่บางครั้งอาจทริกเกอร์หน้าต่างสอบถามรหัสผ่านสำหรับการพยายามเข้าสู่ระบบที่ไม่สำเร็จ</translation>
 <translation id="8256319818471787266">สปาร์กกี้</translation>
 <translation id="7568790562536448087">การอัปเดต</translation>
 <translation id="3910699493603749297">แป้นพิมพ์ภาษากัมพูชา</translation>
diff --git a/chrome/app/resources/generated_resources_tr.xtb b/chrome/app/resources/generated_resources_tr.xtb
index 5ce87a7..272310d 100644
--- a/chrome/app/resources/generated_resources_tr.xtb
+++ b/chrome/app/resources/generated_resources_tr.xtb
@@ -459,7 +459,6 @@
 <translation id="4950138595962845479">Seçenekler...</translation>
 <translation id="4653235815000740718">OS kurtarma medyası oluşturulurken bir sorunla karşılaşıldı. Kullanılan depolama cihazı bulunamadı.</translation>
 <translation id="1407489512183974736">Ortala ve Kırp</translation>
-<translation id="1870557287802238488">Sayfa içi gezinmelerde şifre isteminin görüntülenmesini etkinleştir.</translation>
 <translation id="2688196195245426394">Cihaz sunucuya kaydedilirken hata oluştu: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">İnternet bağlantısı</translation>
 <translation id="1788636309517085411">Varsayılanı kullan</translation>
@@ -3215,7 +3214,6 @@
 <translation id="6983783921975806247">Kayıtlı OID</translation>
 <translation id="394984172568887996">IE'den Al</translation>
 <translation id="5311260548612583999">Özel anahtar dosyası (isteğe bağlı):</translation>
-<translation id="2831904287943562142">Sayfa içi gezinmelerde şifre isteğini göstermeyi etkinleştirin. Bu seçenek, şifrelerin daha fazla sayfada kaydedilmesine olanak sağlar, ancak bazen başarılı olmayan giriş denemelerinde isteği tetikler.</translation>
 <translation id="8256319818471787266">Çomar</translation>
 <translation id="7568790562536448087">Güncelleniyor</translation>
 <translation id="3910699493603749297">Kmer klavye</translation>
diff --git a/chrome/app/resources/generated_resources_uk.xtb b/chrome/app/resources/generated_resources_uk.xtb
index ac6a37e..640891b 100644
--- a/chrome/app/resources/generated_resources_uk.xtb
+++ b/chrome/app/resources/generated_resources_uk.xtb
@@ -447,7 +447,6 @@
 <translation id="4950138595962845479">Параметри...</translation>
 <translation id="4653235815000740718">Під час створення носія для відновлення ОС виникла проблема. Використовуваний пристрій пам’яті неможливо знайти.</translation>
 <translation id="1407489512183974736">Обрізати по центру</translation>
-<translation id="1870557287802238488">Показувати запит на зберігання пароля під час навігації сторінкою.</translation>
 <translation id="2688196195245426394">Помилка під час реєстрації пристрою на сервері: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Інтернет-з’єднання</translation>
 <translation id="1788636309517085411">Використати параметр за умовчанням</translation>
@@ -3172,7 +3171,6 @@
 <translation id="6983783921975806247">Зареєстрований ідентифікатор об'єкта (OID)</translation>
 <translation id="394984172568887996">Імпортовано із IE</translation>
 <translation id="5311260548612583999">Файл секретного ключа (необов'язково):</translation>
-<translation id="2831904287943562142">Показувати запит на зберігання пароля під час навігації сторінкою. Ви зможете зберігати паролі на більшій кількості сторінок, однак запити можуть з’являтися, навіть коли ви введете неправильний пароль.</translation>
 <translation id="8256319818471787266">Шибеник</translation>
 <translation id="7568790562536448087">Оновлення</translation>
 <translation id="3910699493603749297">Кхмерська клавіатура</translation>
diff --git a/chrome/app/resources/generated_resources_vi.xtb b/chrome/app/resources/generated_resources_vi.xtb
index fb6fb264..2ae6c9eb 100644
--- a/chrome/app/resources/generated_resources_vi.xtb
+++ b/chrome/app/resources/generated_resources_vi.xtb
@@ -457,7 +457,6 @@
 <translation id="4950138595962845479">Tùy chọn...</translation>
 <translation id="4653235815000740718">Đã xảy ra sự cố khi tạo phương tiện khôi phục hệ điều hành. Không thể tìm thấy thiết bị lưu trữ đã sử dụng.</translation>
 <translation id="1407489512183974736">Cắt giữa</translation>
-<translation id="1870557287802238488">Cho phép hiển thị lời nhắc mật khẩu trên điều hướng trong trang.</translation>
 <translation id="2688196195245426394">Lỗi khi đăng ký thiết bị với máy chủ: <ph name="CLIENT_ERROR"/>.</translation>
 <translation id="1528372117901087631">Kết nối Internet</translation>
 <translation id="1788636309517085411">Sử dụng mặc định</translation>
@@ -3224,7 +3223,6 @@
 <translation id="6983783921975806247">OID đã Đăng ký</translation>
 <translation id="394984172568887996">Được Nhập từ IE</translation>
 <translation id="5311260548612583999">Tệp khóa cá nhân (tùy chọn):</translation>
-<translation id="2831904287943562142">Cho phép hiển thị lời nhắc mật khẩu trên điều hướng trong trang. Điều này cho phép lưu mật khẩu trên nhiều trang hơn nhưng đôi khi có thể kích hoạt lời nhắc trong các lần đăng nhập không thành công.</translation>
 <translation id="8256319818471787266">Cún con tinh nghịch</translation>
 <translation id="7568790562536448087">Đang cập nhật</translation>
 <translation id="3910699493603749297">Bàn phím tiếng Khmer</translation>
diff --git a/chrome/app/resources/generated_resources_zh-CN.xtb b/chrome/app/resources/generated_resources_zh-CN.xtb
index 6316cb2..c73bb0b 100644
--- a/chrome/app/resources/generated_resources_zh-CN.xtb
+++ b/chrome/app/resources/generated_resources_zh-CN.xtb
@@ -442,7 +442,6 @@
 <translation id="4950138595962845479">选项...</translation>
 <translation id="4653235815000740718">创建操作系统恢复媒体时出现问题。找不到已使用的存储设备。</translation>
 <translation id="1407489512183974736">居中并裁剪</translation>
-<translation id="1870557287802238488">允许在页内浏览时显示保存密码提示。</translation>
 <translation id="2688196195245426394">向服务器注册设备时出错:<ph name="CLIENT_ERROR"/>。</translation>
 <translation id="1528372117901087631">互联网连接。</translation>
 <translation id="1788636309517085411">使用默认设置</translation>
@@ -3174,7 +3173,6 @@
 <translation id="6983783921975806247">已注册的 OID</translation>
 <translation id="394984172568887996">从 IE 中导入</translation>
 <translation id="5311260548612583999">私有密钥文件(可选):</translation>
-<translation id="2831904287943562142">允许在页内浏览时显示保存密码提示。启用此项后,用户可以在更多页面上保存密码,但是登录尝试失败时可能会触发该提示。</translation>
 <translation id="8256319818471787266">狗狗</translation>
 <translation id="7568790562536448087">更新</translation>
 <translation id="3910699493603749297">高棉语键盘</translation>
diff --git a/chrome/app/resources/generated_resources_zh-TW.xtb b/chrome/app/resources/generated_resources_zh-TW.xtb
index 715ffb6f8..7f7da72 100644
--- a/chrome/app/resources/generated_resources_zh-TW.xtb
+++ b/chrome/app/resources/generated_resources_zh-TW.xtb
@@ -443,7 +443,6 @@
 <translation id="4950138595962845479">選項...</translation>
 <translation id="4653235815000740718">建立作業系統還原媒體時發生問題,找不到使用的儲存裝置。</translation>
 <translation id="1407489512183974736">置中並剪裁</translation>
-<translation id="1870557287802238488">允許在網頁內瀏覽時顯示密碼提示。</translation>
 <translation id="2688196195245426394">向伺服器註冊裝置時發生錯誤:<ph name="CLIENT_ERROR"/>。</translation>
 <translation id="1528372117901087631">網際網路連線</translation>
 <translation id="1788636309517085411">使用預設值</translation>
@@ -3187,7 +3186,6 @@
 <translation id="6983783921975806247">已註冊的 OID</translation>
 <translation id="394984172568887996">從 IE 匯入</translation>
 <translation id="5311260548612583999">秘密金鑰檔案 (選擇性):</translation>
-<translation id="2831904287943562142">允許在網頁內瀏覽時顯示密碼提示。這可讓您在更多網頁上儲存密碼,但也可能在登入嘗試失敗時觸發提示。</translation>
 <translation id="8256319818471787266">小黃</translation>
 <translation id="7568790562536448087">更新</translation>
 <translation id="3910699493603749297">高棉文鍵盤</translation>
diff --git a/chrome/app/resources/google_chrome_strings_kn.xtb b/chrome/app/resources/google_chrome_strings_kn.xtb
index 0256fae..e6294e4 100644
--- a/chrome/app/resources/google_chrome_strings_kn.xtb
+++ b/chrome/app/resources/google_chrome_strings_kn.xtb
@@ -95,7 +95,7 @@
 <translation id="8823341990149967727">Chrome ನ ಅವಧಿ ಮುಗಿದಿದೆ</translation>
 <translation id="4424024547088906515">ಈ ಸರ್ವರ್ <ph name="DOMAIN"/> ಆಗಿದೆ ಎಂಬುದನ್ನು ಸಾಬೀತುಪಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ; ಅದರ ಸುರಕ್ಷತಾ ಪ್ರಮಾಣಪತ್ರವು Chrome ಪಾಲಿಗೆ ವಿಶ್ವಾಸಾರ್ಹವಾಗಿಲ್ಲ. ಇದು ತಪ್ಪು ಕಾನ್ಫಿಗರೇಶನ್‌ನಿಂದ ಅಥವಾ ಆಕ್ರಮಣಕಾರರು ನಿಮ್ಮ ಸಂಪರ್ಕದಲ್ಲಿ ಒಳನುಸುಳಿರುವುದರಿಂದ ಆಗಿರಬಹುದು.</translation>
 <translation id="473775607612524610">ನವೀಕರಣ</translation>
-<translation id="5618769508111928343">ನಿಮ್ಮ ಮಾಹಿತಿಯನ್ನು ಸಂರಕ್ಷಿಸುವ ನಿಟ್ಟಿನಲ್ಲಿ <ph name="SITE"/> ಎನಿಕ್ರಿಪ್ಶನ್ ಬಳಸುತ್ತದೆ. Chrome ಈ ಸಮಯದಲ್ಲಿ <ph name="SITE"/> ಗೆ ಸಂಪರ್ಕಿಸಲು ಪ್ರಯತ್ನಿಸಿದಾಗ, ಅಸಹಜ ಮತ್ತು ತಪ್ಪು ರುಜುವಾತುಗಳನ್ನು ವೆಬ್‌ಸೈಟ್ ಹಿಂತಿರುಗಿಸುತ್ತದೆ. ಓರ್ವ ದಾಳಿಕೋರನು <ph name="SITE"/> ನಂತೆ ನಟಿಸಲು ಪ್ರಯತ್ನಿಸಿರಬಹುದು ಇಲ್ಲವೇ ವೈ-ಫೈ ಸೈನ್-ಇನ್ ಪರದೆ ಸಂಪರ್ಕಕ್ಕೆ ಧಕ್ಕೆಯುಂಟು ಮಾಡಿರಬಹುದು. ಯಾವುದೇ ಡೇಟಾವನ್ನು ವಿನಿಮಯ ಮಾಡಿಕೊಳ್ಳುವ ಮೊದಲೇ ಸಂಪರ್ಕವನ್ನು Chrome ನಿಲ್ಲಿಸಿರುವ ಕಾರಣ, ನಿಮ್ಮ ಮಾಹಿತಿ ಈಗಲೂ ಸುರಕ್ಷಿತವಾಗಿದೆ.</translation>
+<translation id="5618769508111928343">ನಿಮ್ಮ ಮಾಹಿತಿಯನ್ನು ಸಂರಕ್ಷಿಸುವ ನಿಟ್ಟಿನಲ್ಲಿ <ph name="SITE"/> ಎನಿಕ್ರಿಪ್ಶನ್ ಬಳಸುತ್ತದೆ. Chrome ಈ ಸಮಯದಲ್ಲಿ <ph name="SITE"/> ಗೆ ಸಂಪರ್ಕಿಸಲು ಪ್ರಯತ್ನಿಸಿದಾಗ, ಅಸಹಜ ಮತ್ತು ತಪ್ಪು ರುಜುವಾತುಗಳನ್ನು ವೆಬ್‌ಸೈಟ್ ಹಿಂತಿರುಗಿಸುತ್ತದೆ. ಓರ್ವ ದಾಳಿಕೋರನು <ph name="SITE"/> ನಂತೆ ನಟಿಸಲು ಪ್ರಯತ್ನಿಸಿರಬಹುದು ಇಲ್ಲವೇ Wi-Fi ಸೈನ್-ಇನ್ ಪರದೆ ಸಂಪರ್ಕಕ್ಕೆ ಧಕ್ಕೆಯುಂಟು ಮಾಡಿರಬಹುದು. ಯಾವುದೇ ಡೇಟಾವನ್ನು ವಿನಿಮಯ ಮಾಡಿಕೊಳ್ಳುವ ಮೊದಲೇ ಸಂಪರ್ಕವನ್ನು Chrome ನಿಲ್ಲಿಸಿರುವ ಕಾರಣ, ನಿಮ್ಮ ಮಾಹಿತಿ ಈಗಲೂ ಸುರಕ್ಷಿತವಾಗಿದೆ.</translation>
 <translation id="6600954340915313787">Chrome ಗೆ ನಕಲಿಸಲಾಗಿದೆ</translation>
 <translation id="2576431527583832481">Chrome ಈಗ ತಾನೇ ಉತ್ತಮಗೊಂಡಿದೆ! ಹೊಸ ಆವೃತ್ತಿ ಲಭ್ಯವಿದೆ.</translation>
 <translation id="4633000520311261472">Chrome ಸುರಕ್ಷಿತವಾಗಿರಿಸುವಂತೆ ಮಾಡಲು, <ph name="IDS_EXTENSION_WEB_STORE_TITLE"/> ನಲ್ಲಿ ಪಟ್ಟಿ ಮಾಡಲಾದ ಕೆಲವು ವಿಸ್ತರಣೆಗಳನ್ನು ನಾವು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದ್ದೇವೆ ಮತ್ತು ಅವುಗಳನ್ನು ನಿಮ್ಮ ಅರಿವಿಲ್ಲದೆ ಸೇರಿಸಿರಬಹುದು.</translation>
diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp
new file mode 100644
index 0000000..13c3ead
--- /dev/null
+++ b/chrome/app/settings_chromium_strings.grdp
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Settings-specific Chromium strings (included from chromium_strings.grd). -->
+<grit-part>
+  <!-- Sync Page -->
+  <message name="IDS_SETTINGS_SYNC_DATA_ENCRYPTED_TEXT" desc="Text alerting the user that synced data is encrypted.">
+    For added security, Chromium will encrypt your data.
+  </message>
+</grit-part>
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp
new file mode 100644
index 0000000..c03e904
--- /dev/null
+++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Settings-specific Google Chrome strings (included from google_chrome_strings.grd). -->
+<grit-part>
+  <!-- Sync Page -->
+  <message name="IDS_SETTINGS_SYNC_DATA_ENCRYPTED_TEXT" desc="Text alerting the user that synced data is encrypted.">
+    For added security, Google Chrome will encrypt your data.
+  </message>
+</grit-part>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 82b696f..7271871 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -5,58 +5,58 @@
   <message name="IDS_SETTINGS_ACCESSIBILITY_PAGE_TITLE" desc="Name of the settings page which displays accessibility preferences.">
     Accessibility
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_MORE_FEATURES_LINK" desc="Link which opens page where users can install extensions which provide additional accessibility features.">
+  <message name="IDS_SETTINGS_MORE_FEATURES_LINK" desc="Link which opens page where users can install extensions which provide additional accessibility features.">
     Add additional accessibility features
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_OPTIONS_IN_MENU_LABEL" desc="Label for checkbox which enables showing accessibilitly options in the system menu.">
+  <message name="IDS_SETTINGS_OPTIONS_IN_MENU_LABEL" desc="Label for checkbox which enables showing accessibilitly options in the system menu.">
     Show accessibility options in the system menu
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_LARGE_MOUSE_CURSOR_LABEL" desc="Label for checkbox which enables showing a larger mouse cursor than normal.">
+  <message name="IDS_SETTINGS_LARGE_MOUSE_CURSOR_LABEL" desc="Label for checkbox which enables showing a larger mouse cursor than normal.">
     Show large mouse cursor
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_HIGH_CONTRAST_LABEL" desc="Label for checkbox which enables high-contrast UI.">
+  <message name="IDS_SETTINGS_HIGH_CONTRAST_LABEL" desc="Label for checkbox which enables high-contrast UI.">
     Use high contrast mode
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_STICKY_KEYS_LABEL" desc="Label for checkbox which enables sticky keys.">
+  <message name="IDS_SETTINGS_STICKY_KEYS_LABEL" desc="Label for checkbox which enables sticky keys.">
     Enable sticky keys
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_STICKY_KEYS_SUBLABEL" desc="Sub-label describing what the term 'sticky keys' means.">
+  <message name="IDS_SETTINGS_STICKY_KEYS_SUBLABEL" desc="Sub-label describing what the term 'sticky keys' means.">
     (to perform keyboard shortcuts by typing them sequentially)
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_CHROMEVOX_LABEL" desc="Label for checkbox which enables ChromeVox">
+  <message name="IDS_SETTINGS_CHROMEVOX_LABEL" desc="Label for checkbox which enables ChromeVox">
     Enable ChromeVox
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_CHROMEVOX_SUBLABEL" desc="Sub-label describingn what ChromeVox is.">
+  <message name="IDS_SETTINGS_CHROMEVOX_SUBLABEL" desc="Sub-label describingn what ChromeVox is.">
     (spoken feedback)
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_SCREEN_MAGNIFIER_LABEL" desc="Label for checkbox which enables the screen magnifier">
+  <message name="IDS_SETTINGS_SCREEN_MAGNIFIER_LABEL" desc="Label for checkbox which enables the screen magnifier">
     Enable screen magnifier
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_TAP_DRAGGING_LABEL" desc="Label for checkbox which enables tap dragging.">
+  <message name="IDS_SETTINGS_TAP_DRAGGING_LABEL" desc="Label for checkbox which enables tap dragging.">
     Enable tap dragging
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_CLICK_ON_STOP_LABEL" desc="Label for checkbox which enables automatically clicking when the mouse pointer stops.">
+  <message name="IDS_SETTINGS_CLICK_ON_STOP_LABEL" desc="Label for checkbox which enables automatically clicking when the mouse pointer stops.">
     Automatically click when the mouse pointer stops
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_DELAY_BEFORE_CLICK_LABEL" desc="Label for dropdown menu which contains various time delays for clicks.">
+  <message name="IDS_SETTINGS_DELAY_BEFORE_CLICK_LABEL" desc="Label for dropdown menu which contains various time delays for clicks.">
     Delay before click:
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_DELAY_BEFORE_CLICK_EXTREMELY_SHORT" desc="Description of an extremely short delay before clicks.">
-    extremeley short
+  <message name="IDS_SETTINGS_DELAY_BEFORE_CLICK_EXTREMELY_SHORT" desc="Description of an extremely short delay before clicks.">
+    extremely short
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_DELAY_BEFORE_CLICK_VERY_SHORT" desc="Description of a very short delay before clicks.">
+  <message name="IDS_SETTINGS_DELAY_BEFORE_CLICK_VERY_SHORT" desc="Description of a very short delay before clicks.">
     very short
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_DELAY_BEFORE_CLICK_SHORT" desc="Description of a short delay before clicks.">
+  <message name="IDS_SETTINGS_DELAY_BEFORE_CLICK_SHORT" desc="Description of a short delay before clicks.">
     short
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_DELAY_BEFORE_CLICK_LONG" desc="Description of a long delay before clicks.">
+  <message name="IDS_SETTINGS_DELAY_BEFORE_CLICK_LONG" desc="Description of a long delay before clicks.">
     long
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_DELAY_BEFORE_CLICK_VERY_LONG" desc="Description of a very long delay before clicks.">
+  <message name="IDS_SETTINGS_DELAY_BEFORE_CLICK_VERY_LONG" desc="Description of a very long delay before clicks.">
     very long
   </message>
-  <message name="IDS_SETTINGS_ACCESSIBILITY_ON_SCREEN_KEYBOARD_LABEL" desc="Label for checkbox which enables an on-screen keyboard.">
+  <message name="IDS_SETTINGS_ON_SCREEN_KEYBOARD_LABEL" desc="Label for checkbox which enables an on-screen keyboard.">
     Enable on-screen keyboard
   </message>
 
@@ -64,24 +64,39 @@
   <message name="IDS_SETTINGS_APPEARANCE_PAGE_TITLE" desc="Name of the settings page which displays appearance preferences.">
     Appearance
   </message>
-  <message name="IDS_SETTINGS_APPEARANCE_SHOW_HOME_BUTTON_LABEL" desc="Label for the checkbox which enables or disables showing the home button in the toolbar.">
+  <message name="IDS_SETTINGS_SET_WALLPAPER" desc="Name of the control which allows the user to set the wallpaper.">
+    Set wallpaper
+  </message>
+  <message name="IDS_SETTINGS_GET_THEMES" desc="Name of the control which allows the user to get themes for the browser.">
+    Get themes
+  </message>
+  <message name="IDS_SETTINGS_RESET_TO_DEFAULT_THEME" desc="Name of the control which resets the browser theme back to the default theme.">
+    Reset to default theme
+  </message>
+  <message name="IDS_SETTINGS_SHOW_HOME_BUTTON" desc="Label for the checkbox which enables or disables showing the home button in the toolbar.">
     Show home button
   </message>
-  <message name="IDS_SETTINGS_APPEARANCE_SHOW_BOOKMARKS_BAR_LABEL" desc="Label for the checkbox which enables or disables showing the bookmarks bar in the toolbar.">
+  <message name="IDS_SETTINGS_SHOW_BOOKMARKS_BAR" desc="Label for the checkbox which enables or disables showing the bookmarks bar in the toolbar.">
     Always show the bookmarks bar
   </message>
+  <message name="IDS_SETTINGS_HOME_PAGE_NTP" desc="Description of the New Tab Page when set as the home page.">
+    New Tab Page
+  </message>
+  <message name="IDS_SETTINGS_CHANGE_HOME_PAGE" desc="Label of the control to change the home page.">
+    Change
+  </message>
 
   <!-- Downloads Page -->
   <message name="IDS_SETTINGS_DOWNLOADS_PAGE_TITLE" desc="Name of the settings page which displays download preferences.">
     Downloads
   </message>
-  <message name="IDS_SETTINGS_DOWNLOADS_LOCATION_LABEL" desc="Label for the input which allows the user to specify the default download directory.">
+  <message name="IDS_SETTINGS_DOWNLOAD_LOCATION" desc="Label for the input which allows the user to specify the default download directory.">
     Download location:
   </message>
-  <message name="IDS_SETTINGS_DOWNLOADS_CHANGE_LOCATION_BUTTON" desc="Text for the button which allows the user to change the default download directory.">
+  <message name="IDS_SETTINGS_CHANGE_DOWNLOAD_LOCATION" desc="Text for the button which allows the user to change the default download directory.">
     Change
   </message>
-  <message name="IDS_SETTINGS_DOWNLOADS_PROMPT_FOR_DOWNLOAD_LABEL" desc="Label for the checkbox which enables a prompt for the user to choose a download location for each download instead of using the default.">
+  <message name="IDS_SETTINGS_PROMPT_FOR_DOWNLOAD" desc="Label for the checkbox which enables a prompt for the user to choose a download location for each download instead of using the default.">
     Ask where to save each file before downloading
   </message>
 
@@ -89,13 +104,13 @@
   <message name="IDS_SETTINGS_DATE_TIME_PAGE_TITLE" desc="Name of the settings page which displays date and time preferences.">
     Date &amp; Time
   </message>
-  <message name="IDS_SETTINGS_DATE_TIME_TIME_ZONE_LABEL" desc="Label for the picker which allows users to choose their time zone.">
+  <message name="IDS_SETTINGS_TIME_ZONE" desc="Label for the picker which allows users to choose their time zone.">
     Time zone:
   </message>
-  <message name="IDS_SETTINGS_DATE_TIME_24_HOUR_CLOCK_LABEL" desc="Label for the checkbox which enables a 24-hour clock (as opposed to a 12-hour clock).">
+  <message name="IDS_SETTINGS_USE_24_HOUR_CLOCK" desc="Label for the checkbox which enables a 24-hour clock (as opposed to a 12-hour clock).">
     Use 24-hour clock
   </message>
-  <message name="IDS_SETTINGS_DATE_TIME_AUTOMATICALLY_SET" desc="Text which explains that the date and time are automatically set.">
+  <message name="IDS_SETTINGS_DATE_TIME_SET_AUTOMATICALLY" desc="Text which explains that the date and time are automatically set.">
     Date and time are set automatically.
   </message>
 
@@ -153,4 +168,85 @@
     Add
   </message>
 
+  <!-- Sync Page -->
+  <message name="IDS_SETTINGS_SYNC_PAGE_TITLE" desc="Name of the settings page which manages syncing data between multiple browser instances with the same Google profile.">
+    Advanced sync settings
+  </message>
+  <message name="IDS_SETTINGS_SYNC_EVERYTHING_MENU_OPTION" desc="Name of the menu option which, when selected, causes all properties to be synced.">
+    Sync everything
+  </message>
+  <message name="IDS_SETTINGS_CHOOSE_WHAT_TO_SYNC_MENU_OPTION" desc="Name of the menu option which, when selected, allows the user to select a subset of properties to be synced.">
+    Choose what to sync
+  </message>
+  <message name="IDS_SETTINGS_APPS_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing apps between multiple browser instances.">
+    Apps
+  </message>
+  <message name="IDS_SETTINGS_EXTENSIONS_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing extensions between multiple browser instances.">
+    Extensions
+  </message>
+  <message name="IDS_SETTINGS_SETTINGS_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing settings between multiple browser instances.">
+    Settings
+  </message>
+  <message name="IDS_SETTINGS_AUTOFILL_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing autofill settings between multiple browser instances.">
+    Autofill
+  </message>
+  <message name="IDS_SETTINGS_HISTORY_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing history between multiple browser instances.">
+    History
+  </message>
+  <message name="IDS_SETTINGS_THEMES_AND_WALLPAPERS_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing themes and wallpapers between multiple browser instances.">
+    Themes &amp; Wallpapers
+  </message>
+  <message name="IDS_SETTINGS_BOOKMARKS_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing bookmarks between multiple browser instances.">
+    Bookmarks
+  </message>
+  <message name="IDS_SETTINGS_PASSWORDS_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing passwords between multiple browser instances.">
+    Passwords
+  </message>
+  <message name="IDS_SETTINGS_OPEN_TABS_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing open tabs between multiple browser instances.">
+    Open Tabs
+  </message>
+  <message name="IDS_SETTINGS_ENCRYPTION_OPTIONS_TITLE" desc="Title for the section which includes options for encrypting sync settings.">
+    Encryption options
+  </message>
+  <message name="IDS_SETTINGS_ENCRYPT_WITH_GOOGLE_CREDENTIALS_LABEL" desc="Label for the radio button which, when selected, causes synced settings to be encrypted with the Google login for the current browser profile.">
+    Encrypt synced passwords with your Google credentials
+  </message>
+  <message name="IDS_SETTINGS_ENCRYPT_WITH_SYNC_PASSPHRASE_LABEL" desc="Label for the radio button which, when selected, causes synced settings to be encrypted with a user-provided password.">
+    Encrypt all synced data with your own sync passphrase.
+  </message>
+  <message name="IDS_SETTINGS_ENCRYPT_WITH_SYNC_PASSPHRASE_LEARN_MORE_LINK" desc="Text for the link which explains how synced settings are encrypted with a user-provided password">
+    Learn more
+  </message>
+  <message name="IDS_SETTINGS_USE_DEFAULT_SETTINGS_BUTTON" desc="Text for button which, when clicked, activates the default sync settings.">
+    Use default settings
+  </message>
+  <message name="IDS_SETTINGS_CANCEL_BUTTON" desc="Text for the button which, when clicked, discards changes made to sync settings and navigates away from the sync settings page.">
+    Cancel
+  </message>
+  <message name="IDS_SETTINGS_OK_BUTTON" desc="Text for the button which, when clicked, saves changes made to sync settings and navigates away from the sync settings page.">
+    OK
+  </message>
+
+  <!-- Users Page -->
+  <message name="IDS_SETTINGS_USERS_PAGE_TITLE" desc="Name of the settings page which manages users on the device.">
+    Manage other users
+  </message>
+  <message name="IDS_SETTINGS_USERS_MODIFIED_BY_OWNER_LABEL" desc="Label saying settings may only be modified by the device owner.">
+    These settings may only be modified by the owner:
+  </message>
+  <message name="IDS_SETTINGS_USERS_GUEST_BROWSING_LABEL" desc="Label for the guest browsing setting.">
+    Enable Guest browsing
+  </message>
+  <message name="IDS_SETTINGS_USERS_SUPERVISED_USERS_LABEL" desc="Label for the supervised users setting.">
+    Enable supervised users
+  </message>
+  <message name="IDS_SETTINGS_USERS_SHOW_ON_SIGNIN_LABEL" desc="Label for the 'show users on sign-in screen' setting.">
+    Show usernames and photos on the sign-in screen
+  </message>
+  <message name="IDS_SETTINGS_USERS_RESTRICT_SIGNIN_LABEL" desc="Label for the setting for restricting sign in to specific users.">
+    Restrict sign-in to the following users:
+  </message>
+  <message name="IDS_SETTINGS_USERS_ADD_USERS_LABEL" desc="Label for the input field for adding users.">
+    Add users
+  </message>
 </grit-part>
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index eca9ac7..3764cad 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -399,6 +399,8 @@
       </if>
       <structure type="chrome_scaled_image" name="IDR_INFOBAR_3D_BLOCKED" file="common/infobar_3d_blocked.png" />
       <structure type="chrome_scaled_image" name="IDR_INFOBAR_ALT_NAV_URL" file="common/infobar_alt_nav_url.png" />
+      <!-- TODO(dominickn) Replace this with the correct image. -->
+      <structure type="chrome_scaled_image" name="IDR_INFOBAR_APP_BANNER" file="common/infobar_geolocation.png" />
       <structure type="chrome_scaled_image" name="IDR_INFOBAR_AUTOLOGIN" file="common/infobar_autologin.png" />
       <structure type="chrome_scaled_image" name="IDR_INFOBAR_COOKIE" file="common/infobar_cookie.png" />
       <if expr="not is_android">
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 8750336..393fd9b 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -429,6 +429,16 @@
     keyboard::switches::kFloatingVirtualKeyboardEnabled},
 };
 
+const Experiment::Choice kSmartVirtualKeyboardChoices[] = {
+  { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
+  { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
+    keyboard::switches::kSmartVirtualKeyboard,
+    keyboard::switches::kSmartVirtualKeyboardDisabled},
+  { IDS_GENERIC_EXPERIMENT_CHOICE_ENABLED,
+    keyboard::switches::kSmartVirtualKeyboard,
+    keyboard::switches::kSmartVirtualKeyboardEnabled},
+};
+
 const Experiment::Choice kGestureTypingChoices[] = {
   { IDS_GENERIC_EXPERIMENT_CHOICE_DEFAULT, "", "" },
   { IDS_GENERIC_EXPERIMENT_CHOICE_DISABLED,
@@ -1402,6 +1412,13 @@
     MULTI_VALUE_TYPE(kFloatingVirtualKeyboardChoices)
   },
   {
+    "smart-virtual-keyboard",
+    IDS_FLAGS_SMART_VIRTUAL_KEYBOARD_NAME,
+    IDS_FLAGS_SMART_VIRTUAL_KEYBOARD_DESCRIPTION,
+    kOsCrOS,
+    MULTI_VALUE_TYPE(kSmartVirtualKeyboardChoices)
+  },
+  {
     "gesture-typing",
     IDS_FLAGS_GESTURE_TYPING_NAME,
     IDS_FLAGS_GESTURE_TYPING_DESCRIPTION,
@@ -1416,11 +1433,11 @@
     MULTI_VALUE_TYPE(kGestureEditingChoices)
   },
   {
-    "disable-smart-virtual-keyboard",
-    IDS_FLAGS_DISABLE_SMART_VIRTUAL_KEYBOARD_NAME,
-    IDS_FLAGS_DISABLE_SMART_VIRTUAL_KEYBOARD_DESCRIPTION,
+    "enable-fullscreen-app-list",
+    IDS_FLAGS_FULLSCREEN_APP_LIST_NAME,
+    IDS_FLAGS_FULLSCREEN_APP_LIST_DESCRIPTION,
     kOsCrOS,
-    SINGLE_VALUE_TYPE(keyboard::switches::kDisableSmartVirtualKeyboard)
+    SINGLE_VALUE_TYPE(ash::switches::kAshEnableFullscreenAppList)
   },
 #endif
   {
diff --git a/chrome/browser/android/banners/app_banner_data_fetcher_android.cc b/chrome/browser/android/banners/app_banner_data_fetcher_android.cc
index 29934f46..eaba3f1 100644
--- a/chrome/browser/android/banners/app_banner_data_fetcher_android.cc
+++ b/chrome/browser/android/banners/app_banner_data_fetcher_android.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/android/banners/app_banner_data_fetcher_android.h"
 
 #include "chrome/browser/android/banners/app_banner_infobar_delegate_android.h"
+#include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/ui/android/infobars/app_banner_infobar_android.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
@@ -41,9 +42,8 @@
       ? AppBannerDataFetcher::GetAppIdentifier() : native_app_package_;
 }
 
-infobars::InfoBar* AppBannerDataFetcherAndroid::CreateBanner(
-    const SkBitmap* icon,
-    const base::string16& title) {
+void AppBannerDataFetcherAndroid::ShowBanner(const SkBitmap* icon,
+                                             const base::string16& title) {
   content::WebContents* web_contents = GetWebContents();
   DCHECK(web_contents);
 
@@ -66,8 +66,8 @@
     if (infobar)
       RecordDidShowBanner("AppBanner.NativeApp.Shown");
   }
-
-  return infobar;
+  InfoBarService::FromWebContents(web_contents)
+      ->AddInfoBar(make_scoped_ptr(infobar));
 }
 
 }  // namespace banners
diff --git a/chrome/browser/android/banners/app_banner_data_fetcher_android.h b/chrome/browser/android/banners/app_banner_data_fetcher_android.h
index 7114301..e059522e 100644
--- a/chrome/browser/android/banners/app_banner_data_fetcher_android.h
+++ b/chrome/browser/android/banners/app_banner_data_fetcher_android.h
@@ -31,8 +31,8 @@
 
   std::string GetBannerType() override;
   std::string GetAppIdentifier() override;
-  infobars::InfoBar* CreateBanner(const SkBitmap* icon,
-                                  const base::string16& title) override;
+  void ShowBanner(const SkBitmap* icon,
+                  const base::string16& title) override;
 
  private:
   base::android::ScopedJavaGlobalRef<jobject> native_app_data_;
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
index ac212f5c..84a883f 100644
--- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
+++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
@@ -155,33 +155,18 @@
   if (!web_contents)
     return;
 
-  TrackDismissEvent(DISMISS_EVENT_CLOSE_BUTTON);
-
   web_contents->GetMainFrame()->Send(
       new ChromeViewMsg_AppBannerDismissed(
           web_contents->GetMainFrame()->GetRoutingID(),
           event_request_id_));
 
   if (!native_app_data_.is_null()) {
-    AppBannerSettingsHelper::RecordBannerEvent(
-        web_contents, web_contents->GetURL(),
-        native_app_package_,
-        AppBannerSettingsHelper::APP_BANNER_EVENT_DID_BLOCK,
-        AppBannerDataFetcher::GetCurrentTime());
-
-    rappor::SampleDomainAndRegistryFromGURL(g_browser_process->rappor_service(),
-                                            "AppBanner.NativeApp.Dismissed",
-                                            web_contents->GetURL());
+    AppBannerSettingsHelper::RecordBannerDismissEvent(
+        web_contents, native_app_package_, AppBannerSettingsHelper::NATIVE);
   } else if (!web_app_data_.IsEmpty()) {
-    AppBannerSettingsHelper::RecordBannerEvent(
-        web_contents, web_contents->GetURL(),
-        web_app_data_.start_url.spec(),
-        AppBannerSettingsHelper::APP_BANNER_EVENT_DID_BLOCK,
-        AppBannerDataFetcher::GetCurrentTime());
-
-    rappor::SampleDomainAndRegistryFromGURL(g_browser_process->rappor_service(),
-                                            "AppBanner.WebApp.Dismissed",
-                                            web_contents->GetURL());
+    AppBannerSettingsHelper::RecordBannerDismissEvent(
+        web_contents, web_app_data_.start_url.spec(),
+        AppBannerSettingsHelper::WEB);
   }
 }
 
@@ -224,11 +209,9 @@
     SendBannerAccepted(web_contents, "play");
     return was_opened;
   } else if (!web_app_data_.IsEmpty()) {
-    AppBannerSettingsHelper::RecordBannerEvent(
-        web_contents, web_contents->GetURL(),
-        web_app_data_.start_url.spec(),
-        AppBannerSettingsHelper::APP_BANNER_EVENT_DID_ADD_TO_HOMESCREEN,
-        AppBannerDataFetcher::GetCurrentTime());
+    AppBannerSettingsHelper::RecordBannerInstallEvent(
+        web_contents, web_app_data_.start_url.spec(),
+        AppBannerSettingsHelper::WEB);
 
     ShortcutInfo info;
     info.UpdateFromManifest(web_app_data_);
@@ -239,11 +222,7 @@
                    info,
                    *app_icon_.get()));
 
-    TrackInstallEvent(INSTALL_EVENT_WEB_APP_INSTALLED);
     SendBannerAccepted(web_contents, "web");
-    rappor::SampleDomainAndRegistryFromGURL(g_browser_process->rappor_service(),
-                                            "AppBanner.WebApp.Installed",
-                                            web_contents->GetURL());
     return true;
   }
 
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
index 332e0b3..e1eed9b 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
@@ -86,11 +86,11 @@
 void ContextualSearchDelegate::StartSearchTermResolutionRequest(
     const std::string& selection,
     bool use_resolved_search_term,
-    content::ContentViewCore* content_view_core) {
+    content::ContentViewCore* content_view_core,
+    bool may_send_base_page_url) {
   GatherSurroundingTextWithCallback(
-      selection,
-      use_resolved_search_term,
-      content_view_core,
+      selection, use_resolved_search_term, content_view_core,
+      may_send_base_page_url,
       base::Bind(&ContextualSearchDelegate::StartSearchTermRequestFromSelection,
                  AsWeakPtr()));
 }
@@ -98,11 +98,11 @@
 void ContextualSearchDelegate::GatherAndSaveSurroundingText(
     const std::string& selection,
     bool use_resolved_search_term,
-    content::ContentViewCore* content_view_core) {
+    content::ContentViewCore* content_view_core,
+    bool may_send_base_page_url) {
   GatherSurroundingTextWithCallback(
-      selection,
-      use_resolved_search_term,
-      content_view_core,
+      selection, use_resolved_search_term, content_view_core,
+      may_send_base_page_url,
       base::Bind(&ContextualSearchDelegate::SaveSurroundingText, AsWeakPtr()));
   // TODO(donnd): clear the context here, since we're done with it (but risky).
 }
@@ -236,15 +236,16 @@
     const std::string& selection,
     bool use_resolved_search_term,
     content::ContentViewCore* content_view_core,
+    bool may_send_base_page_url,
     HandleSurroundingsCallback callback) {
   // Immediately cancel any request that's in flight, since we're building a new
   // context (and the response disposes of any existing context).
   search_term_fetcher_.reset();
-  // Decide if the URL be sent with the context.
+  // Decide if the URL should be sent with the context.
   GURL page_url(content_view_core->GetWebContents()->GetURL());
   GURL url_to_send;
-  if (CanSendPageURL(page_url,
-                     ProfileManager::GetActiveUserProfile(),
+  if (may_send_base_page_url &&
+      CanSendPageURL(page_url, ProfileManager::GetActiveUserProfile(),
                      template_url_service_)) {
     url_to_send = page_url;
   }
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.h b/chrome/browser/android/contextualsearch/contextual_search_delegate.h
index 6842e14..b7fea2c 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_delegate.h
+++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.h
@@ -59,13 +59,14 @@
   void StartSearchTermResolutionRequest(
       const std::string& selection,
       bool use_resolved_search_term,
-      content::ContentViewCore* content_view_core);
+      content::ContentViewCore* content_view_core,
+      bool may_send_base_page_url);
 
   // Gathers surrounding text and saves it locally for a future query.
-  void GatherAndSaveSurroundingText(
-      const std::string& selection,
-      bool use_resolved_search_term,
-      content::ContentViewCore* content_view_core);
+  void GatherAndSaveSurroundingText(const std::string& selection,
+                                    bool use_resolved_search_term,
+                                    content::ContentViewCore* content_view_core,
+                                    bool may_send_base_page_url);
 
   // Continues making a Search Term Resolution request based on the context
   // set up through calling |GatherAndSaveSurroundingText|.
@@ -103,7 +104,7 @@
   std::string GetSearchTermResolutionUrlString(
       const std::string& selected_text,
       const std::string& base_page_url,
-      const bool use_resolved_search_term);
+      const bool may_send_base_page_url);
 
   // Will gather the surrounding text from the |content_view_core| and call the
   // |callback|.
@@ -111,6 +112,7 @@
       const std::string& selection,
       bool use_resolved_search_term,
       content::ContentViewCore* content_view_core,
+      bool may_send_base_page_url,
       HandleSurroundingsCallback callback);
 
   // Callback for GatherSurroundingTextWithCallback(). Will start the search
@@ -136,7 +138,7 @@
       const ContextualSearchContext& context);
 
   // Checks if we can send the URL for this user. Several conditions are checked
-  // to make sure it's OK to send the url.  These fall into two categories:
+  // to make sure it's OK to send the URL.  These fall into two categories:
   // 1) check if it's allowed by our policy, and 2) ensure that the user is
   // already sending their URL browsing activity to Google.
   bool CanSendPageURL(const GURL& current_page_url,
diff --git a/chrome/browser/android/contextualsearch/contextual_search_manager.cc b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
index 64bd88c..f5b2003 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_manager.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
@@ -77,16 +77,19 @@
     jobject obj,
     jstring j_selection,
     jboolean j_use_resolved_search_term,
-    jobject j_base_content_view_core) {
+    jobject j_base_content_view_core,
+    jboolean j_may_send_base_page_url) {
   ContentViewCore* base_content_view_core =
       ContentViewCore::GetNativeContentViewCore(env, j_base_content_view_core);
   DCHECK(base_content_view_core);
   std::string selection(
       base::android::ConvertJavaStringToUTF8(env, j_selection));
   bool use_resolved_search_term = j_use_resolved_search_term;
+  bool may_send_base_page_url = j_may_send_base_page_url;
   // Calls back to OnSearchTermResolutionResponse.
   delegate_->StartSearchTermResolutionRequest(
-      selection, use_resolved_search_term, base_content_view_core);
+      selection, use_resolved_search_term, base_content_view_core,
+      may_send_base_page_url);
 }
 
 void ContextualSearchManager::GatherSurroundingText(
@@ -94,15 +97,18 @@
     jobject obj,
     jstring j_selection,
     jboolean j_use_resolved_search_term,
-    jobject j_base_content_view_core) {
+    jobject j_base_content_view_core,
+    jboolean j_may_send_base_page_url) {
   ContentViewCore* base_content_view_core =
       ContentViewCore::GetNativeContentViewCore(env, j_base_content_view_core);
   DCHECK(base_content_view_core);
   std::string selection(
       base::android::ConvertJavaStringToUTF8(env, j_selection));
   bool use_resolved_search_term = j_use_resolved_search_term;
-  delegate_->GatherAndSaveSurroundingText(
-      selection, use_resolved_search_term, base_content_view_core);
+  bool may_send_base_page_url = j_may_send_base_page_url;
+  delegate_->GatherAndSaveSurroundingText(selection, use_resolved_search_term,
+                                          base_content_view_core,
+                                          may_send_base_page_url);
 }
 
 void ContextualSearchManager::ContinueSearchTermResolutionRequest(JNIEnv* env,
diff --git a/chrome/browser/android/contextualsearch/contextual_search_manager.h b/chrome/browser/android/contextualsearch/contextual_search_manager.h
index fe25cb6..b69febf 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_manager.h
+++ b/chrome/browser/android/contextualsearch/contextual_search_manager.h
@@ -37,11 +37,13 @@
   // When the server responds with the search term, the Java object is notified
   // by
   // calling OnSearchTermResolutionResponse().
-  void StartSearchTermResolutionRequest(JNIEnv* env,
-                                        jobject obj,
-                                        jstring j_selection,
-                                        jboolean j_use_resolved_search_term,
-                                        jobject j_base_content_view_core);
+  void StartSearchTermResolutionRequest(
+      JNIEnv* env,
+      jobject obj,
+      jstring j_selection,
+      jboolean j_use_resolved_search_term,
+      jobject j_base_content_view_core,
+      jboolean j_may_send_base_page_url);
 
   // Gathers the surrounding text around the selection and saves it locally.
   // Does not send a search term resolution request to the server.
@@ -49,7 +51,8 @@
                              jobject obj,
                              jstring j_selection,
                              jboolean j_use_resolved_search_term,
-                             jobject j_base_content_view_core);
+                             jobject j_base_content_view_core,
+                             jboolean j_may_send_base_page_url);
 
   // Continues making a Search Term Resolution request based on the context
   // set up through calling |GatherSurroundingText|.
diff --git a/chrome/browser/background/background_contents.cc b/chrome/browser/background/background_contents.cc
index f17f863f..6b02c78 100644
--- a/chrome/browser/background/background_contents.cc
+++ b/chrome/browser/background/background_contents.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/renderer_preferences_util.h"
+#include "chrome/browser/task_management/web_contents_tags.h"
 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/notification_service.h"
@@ -43,7 +44,7 @@
   WebContents::CreateParams create_params(profile_, site_instance);
   create_params.routing_id = routing_id;
   create_params.main_frame_routing_id = main_frame_routing_id;
-  create_params.renderer_initiated_creation = true;
+  create_params.renderer_initiated_creation = routing_id != MSG_ROUTING_NONE;
   if (session_storage_namespace) {
     content::SessionStorageNamespaceMap session_storage_namespace_map;
     session_storage_namespace_map.insert(
@@ -60,6 +61,10 @@
   extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
       web_contents_.get());
 
+  // Add the TaskManager-specific tag for the BackgroundContents.
+  task_management::WebContentsTags::CreateForBackgroundContents(
+      web_contents_.get(), this);
+
   // Close ourselves when the application is shutting down.
   registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
                  content::NotificationService::AllSources());
diff --git a/chrome/browser/banners/app_banner_data_fetcher.cc b/chrome/browser/banners/app_banner_data_fetcher.cc
index 8f973ce4..8507486b 100644
--- a/chrome/browser/banners/app_banner_data_fetcher.cc
+++ b/chrome/browser/banners/app_banner_data_fetcher.cc
@@ -12,11 +12,9 @@
 #include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/manifest/manifest_icon_selector.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/render_messages.h"
-#include "components/infobars/core/infobar.h"
 #include "components/rappor/rappor_utils.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
@@ -158,11 +156,7 @@
   FOR_EACH_OBSERVER(Observer, observer_list_,
                     OnDecidedWhetherToShow(this, true));
 
-  infobars::InfoBar* infobar = CreateBanner(app_icon_.get(), app_title_);
-  if (infobar) {
-    InfoBarService::FromWebContents(web_contents)->AddInfoBar(
-        make_scoped_ptr(infobar));
-  }
+  ShowBanner(app_icon_.get(), app_title_);
   is_active_ = false;
 }
 
@@ -205,18 +199,6 @@
   return true;
 }
 
-infobars::InfoBar* AppBannerDataFetcher::CreateBanner(
-    const SkBitmap* icon,
-    const base::string16& title) {
-  content::WebContents* web_contents = GetWebContents();
-  DCHECK(web_contents && !web_app_data_.IsEmpty());
-
-  // TODO(dfalcantara): Desktop doesn't display app banners, yet.  Just pretend
-  //                    that a banner was shown for testing purposes.
-  RecordDidShowBanner("AppBanner.WebApp.Shown");
-  return nullptr;
-}
-
 void AppBannerDataFetcher::RecordDidShowBanner(const std::string& event_name) {
   content::WebContents* web_contents = GetWebContents();
   DCHECK(web_contents);
@@ -310,12 +292,12 @@
 void AppBannerDataFetcher::OnFetchComplete(const GURL& url,
                                            const SkBitmap* icon) {
   if (is_active_)
-    ShowBanner(icon);
+    RequestShowBanner(icon);
 
   Release();
 }
 
-void AppBannerDataFetcher::ShowBanner(const SkBitmap* icon) {
+void AppBannerDataFetcher::RequestShowBanner(const SkBitmap* icon) {
   content::WebContents* web_contents = GetWebContents();
   if (!CheckFetcherIsStillAlive(web_contents)) {
     Cancel();
diff --git a/chrome/browser/banners/app_banner_data_fetcher.h b/chrome/browser/banners/app_banner_data_fetcher.h
index 1f81324..f908db9 100644
--- a/chrome/browser/banners/app_banner_data_fetcher.h
+++ b/chrome/browser/banners/app_banner_data_fetcher.h
@@ -11,6 +11,7 @@
 #include "base/observer_list.h"
 #include "base/time/time.h"
 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher_delegate.h"
+#include "chrome/common/web_application_info.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/manifest.h"
@@ -115,8 +116,8 @@
   bool FetchIcon(const GURL& image_url);
 
   // Creates a banner for the app using the given |icon|.
-  virtual infobars::InfoBar* CreateBanner(const SkBitmap* icon,
-                                          const base::string16& title);
+  virtual void ShowBanner(const SkBitmap* icon,
+                          const base::string16& title) = 0;
 
   // Records that a banner was shown. The |event_name| corresponds to the RAPPOR
   // metric being recorded.
@@ -129,7 +130,7 @@
   void OnFetchComplete(const GURL& url, const SkBitmap* icon) override;
 
   // Shows a banner for the app, if the given |icon| is valid.
-  virtual void ShowBanner(const SkBitmap* icon);
+  virtual void RequestShowBanner(const SkBitmap* icon);
 
   // Record that the banner could be shown at this point, if the triggering
   // heuristic allowed.
diff --git a/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc b/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc
index d452897..d4b3996 100644
--- a/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc
+++ b/chrome/browser/banners/app_banner_data_fetcher_browsertest.cc
@@ -8,6 +8,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/task_runner.h"
+#include "chrome/browser/banners/app_banner_data_fetcher_desktop.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -81,9 +82,9 @@
                   bool expected_to_show) {
     content::WebContents* web_contents =
         browser()->tab_strip_model()->GetActiveWebContents();
-    scoped_refptr<AppBannerDataFetcher> fetcher(
-        new AppBannerDataFetcher(web_contents, weak_factory_.GetWeakPtr(),
-                                 128));
+    scoped_refptr<AppBannerDataFetcherDesktop> fetcher(
+        new AppBannerDataFetcherDesktop(web_contents,
+                                        weak_factory_.GetWeakPtr(), 128));
 
     base::RunLoop run_loop;
     quit_closure_ = run_loop.QuitClosure();
diff --git a/chrome/browser/banners/app_banner_data_fetcher_desktop.cc b/chrome/browser/banners/app_banner_data_fetcher_desktop.cc
new file mode 100644
index 0000000..ff1923c
--- /dev/null
+++ b/chrome/browser/banners/app_banner_data_fetcher_desktop.cc
@@ -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.
+
+#include "chrome/browser/banners/app_banner_data_fetcher_desktop.h"
+
+#include "chrome/browser/banners/app_banner_infobar_delegate_desktop.h"
+#include "chrome/browser/banners/app_banner_settings_helper.h"
+#include "chrome/browser/extensions/bookmark_app_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/web_application_info.h"
+#include "content/public/browser/render_frame_host.h"
+
+namespace infobars {
+class InfoBar;
+}  // namespace infobars
+
+namespace banners {
+
+AppBannerDataFetcherDesktop::AppBannerDataFetcherDesktop(
+    content::WebContents* web_contents,
+    base::WeakPtr<Delegate> weak_delegate,
+    int ideal_icon_size)
+    : AppBannerDataFetcher(web_contents, weak_delegate, ideal_icon_size) {
+}
+
+AppBannerDataFetcherDesktop::~AppBannerDataFetcherDesktop() {
+}
+
+void AppBannerDataFetcherDesktop::ShowBanner(const SkBitmap* icon,
+                                             const base::string16& title) {
+  content::WebContents* web_contents = GetWebContents();
+  DCHECK(web_contents && !web_app_data().IsEmpty());
+
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  WebApplicationInfo web_app_info;
+
+  bookmark_app_helper_.reset(
+      new extensions::BookmarkAppHelper(profile, web_app_info, web_contents));
+
+  // This differs from the Android infobar creation, which has an explicit
+  // InfoBarAndroid class interfacing with Java. On Android, the data fetcher
+  // calls the InfoBarService to show the banner. On desktop, an InfoBar class
+  // is not required, so the InfoBarService call is made within the delegate.
+  infobars::InfoBar* infobar = AppBannerInfoBarDelegateDesktop::Create(
+      make_scoped_refptr(this), web_contents, web_app_data(),
+      bookmark_app_helper_.get(), event_request_id());
+  if (infobar) {
+    RecordDidShowBanner("AppBanner.WebApp.Shown");
+  }
+}
+
+void AppBannerDataFetcherDesktop::FinishCreateBookmarkApp(
+    const extensions::Extension* extension,
+    const WebApplicationInfo& web_app_info) {
+  content::WebContents* web_contents = GetWebContents();
+  if (web_contents) {
+    // A null extension pointer indicates that the bookmark app install was
+    // not successful.
+    if (extension == nullptr) {
+      web_contents->GetMainFrame()->Send(
+          new ChromeViewMsg_AppBannerDismissed(
+              web_contents->GetMainFrame()->GetRoutingID(),
+              event_request_id()));
+
+      AppBannerSettingsHelper::RecordBannerDismissEvent(
+          web_contents, web_app_data().start_url.spec(),
+          AppBannerSettingsHelper::WEB);
+    } else {
+      web_contents->GetMainFrame()->Send(
+          new ChromeViewMsg_AppBannerAccepted(
+              web_contents->GetMainFrame()->GetRoutingID(),
+              event_request_id(), "web"));
+
+      AppBannerSettingsHelper::RecordBannerInstallEvent(
+          web_contents, web_app_data().start_url.spec(),
+          AppBannerSettingsHelper::WEB);
+    }
+  }
+}
+
+}  // namespace banners
diff --git a/chrome/browser/banners/app_banner_data_fetcher_desktop.h b/chrome/browser/banners/app_banner_data_fetcher_desktop.h
new file mode 100644
index 0000000..995d7b36
--- /dev/null
+++ b/chrome/browser/banners/app_banner_data_fetcher_desktop.h
@@ -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.
+
+#ifndef CHROME_BROWSER_BANNERS_APP_BANNER_DATA_FETCHER_DESKTOP_H_
+#define CHROME_BROWSER_BANNERS_APP_BANNER_DATA_FETCHER_DESKTOP_H_
+
+#include "chrome/browser/banners/app_banner_data_fetcher.h"
+
+namespace extensions {
+class BookmarkAppHelper;
+class Extension;
+}  // namespace extensions
+
+namespace banners {
+
+// Fetches data required to show a banner for the URL currently shown by the
+// WebContents. Extends the regular fetch to support desktop web apps.
+class AppBannerDataFetcherDesktop : public AppBannerDataFetcher {
+ public:
+  AppBannerDataFetcherDesktop(content::WebContents* web_contents,
+                              base::WeakPtr<Delegate> weak_delegate,
+                              int ideal_icon_size);
+
+  void ShowBanner(const SkBitmap* icon, const base::string16& title) override;
+
+  // Callback for finishing bookmark app creation
+  void FinishCreateBookmarkApp(const extensions::Extension* extension,
+                               const WebApplicationInfo& web_app_info);
+
+ protected:
+  ~AppBannerDataFetcherDesktop() override;
+
+ private:
+  scoped_ptr<extensions::BookmarkAppHelper> bookmark_app_helper_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppBannerDataFetcherDesktop);
+};
+
+}  // namespace banners
+
+#endif  // CHROME_BROWSER_BANNERS_APP_BANNER_DATA_FETCHER_DESKTOP_H_
diff --git a/chrome/browser/banners/app_banner_infobar_delegate_desktop.cc b/chrome/browser/banners/app_banner_infobar_delegate_desktop.cc
new file mode 100644
index 0000000..ef551c53
--- /dev/null
+++ b/chrome/browser/banners/app_banner_infobar_delegate_desktop.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/banners/app_banner_infobar_delegate_desktop.h"
+
+#include "chrome/browser/banners/app_banner_data_fetcher_desktop.h"
+#include "chrome/browser/banners/app_banner_metrics.h"
+#include "chrome/browser/banners/app_banner_settings_helper.h"
+#include "chrome/browser/extensions/bookmark_app_helper.h"
+#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/infobars/core/infobar.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace banners {
+
+AppBannerInfoBarDelegateDesktop::AppBannerInfoBarDelegateDesktop(
+    scoped_refptr<AppBannerDataFetcherDesktop> fetcher,
+    const content::Manifest& web_manifest,
+    extensions::BookmarkAppHelper* bookmark_app_helper,
+    int event_request_id)
+    : ConfirmInfoBarDelegate(),
+      fetcher_(fetcher),
+      web_manifest_(web_manifest),
+      bookmark_app_helper_(bookmark_app_helper),
+      event_request_id_(event_request_id) {
+}
+
+AppBannerInfoBarDelegateDesktop::~AppBannerInfoBarDelegateDesktop() {
+}
+
+// static
+infobars::InfoBar* AppBannerInfoBarDelegateDesktop::Create(
+    scoped_refptr<AppBannerDataFetcherDesktop> fetcher,
+    content::WebContents* web_contents,
+    const content::Manifest& web_manifest,
+    extensions::BookmarkAppHelper* bookmark_app_helper,
+    int event_request_id) {
+  InfoBarService* infobar_service =
+      InfoBarService::FromWebContents(web_contents);
+  return infobar_service->AddInfoBar(infobar_service->CreateConfirmInfoBar(
+      scoped_ptr<ConfirmInfoBarDelegate>(new AppBannerInfoBarDelegateDesktop(
+          fetcher, web_manifest, bookmark_app_helper, event_request_id))));
+}
+
+infobars::InfoBarDelegate::Type
+AppBannerInfoBarDelegateDesktop::GetInfoBarType() const {
+  return PAGE_ACTION_TYPE;
+}
+
+int AppBannerInfoBarDelegateDesktop::GetIconID() const {
+  return IDR_INFOBAR_APP_BANNER;
+}
+
+base::string16 AppBannerInfoBarDelegateDesktop::GetMessageText() const {
+  return l10n_util::GetStringUTF16(IDS_ADD_TO_SHELF_INFOBAR_TITLE);
+}
+
+base::string16 AppBannerInfoBarDelegateDesktop::GetButtonLabel(
+    InfoBarButton button) const {
+  return l10n_util::GetStringUTF16((button == BUTTON_OK)
+                                       ? IDS_ADD_TO_SHELF_INFOBAR_ADD_BUTTON
+                                       : IDS_ADD_TO_SHELF_INFOBAR_NEVER_BUTTON);
+}
+
+bool AppBannerInfoBarDelegateDesktop::Accept() {
+  bookmark_app_helper_->CreateFromAppBanner(
+      base::Bind(&AppBannerDataFetcherDesktop::FinishCreateBookmarkApp,
+                 fetcher_),
+      web_manifest_);
+  return true;
+}
+
+bool AppBannerInfoBarDelegateDesktop::Cancel() {
+  content::WebContents* web_contents =
+      InfoBarService::WebContentsFromInfoBar(infobar());
+  if (web_contents) {
+    fetcher_.get()->Cancel();
+
+    web_contents->GetMainFrame()->Send(
+        new ChromeViewMsg_AppBannerDismissed(
+            web_contents->GetMainFrame()->GetRoutingID(),
+            event_request_id_));
+
+    AppBannerSettingsHelper::RecordBannerDismissEvent(
+        web_contents, web_manifest_.start_url.spec(),
+        AppBannerSettingsHelper::WEB);
+  }
+  return true;
+}
+
+void AppBannerInfoBarDelegateDesktop::InfoBarDismissed() {
+  Cancel();
+}
+
+}  // namespace banners
diff --git a/chrome/browser/banners/app_banner_infobar_delegate_desktop.h b/chrome/browser/banners/app_banner_infobar_delegate_desktop.h
new file mode 100644
index 0000000..61d29730
--- /dev/null
+++ b/chrome/browser/banners/app_banner_infobar_delegate_desktop.h
@@ -0,0 +1,73 @@
+// 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_BANNERS_APP_BANNER_INFOBAR_DELEGATE_DESKTOP_H_
+#define CHROME_BROWSER_BANNERS_APP_BANNER_INFOBAR_DELEGATE_DESKTOP_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+#include "content/public/common/manifest.h"
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+namespace extensions {
+class BookmarkAppHelper;
+class Extension;
+}  // namespace extensions
+
+namespace infobars {
+class InfoBar;
+}  // namespace infobars
+
+namespace banners {
+
+class AppBannerDataFetcherDesktop;
+
+class AppBannerInfoBarDelegateDesktop : public ConfirmInfoBarDelegate {
+
+ public:
+  ~AppBannerInfoBarDelegateDesktop() override;
+
+  static infobars::InfoBar* Create(
+      scoped_refptr<AppBannerDataFetcherDesktop> fetcher,
+      content::WebContents* web_contents,
+      const content::Manifest& web_manifest,
+      extensions::BookmarkAppHelper* bookmark_app_helper,
+      int event_request_id);
+
+  // ConfirmInfoBarDelegate overrides.
+  base::string16 GetMessageText() const override;
+  base::string16 GetButtonLabel(InfoBarButton button) const override;
+
+  bool Accept() override;
+  bool Cancel() override;
+
+  // InfoBarDelegate override.
+  void InfoBarDismissed() override;
+
+ protected:
+  AppBannerInfoBarDelegateDesktop(
+      scoped_refptr<AppBannerDataFetcherDesktop> fetcher,
+      const content::Manifest& web_manifest,
+      extensions::BookmarkAppHelper* bookmark_app_helper,
+      int event_request_id);
+
+ private:
+  scoped_refptr<AppBannerDataFetcherDesktop> fetcher_;
+  content::Manifest web_manifest_;
+  extensions::BookmarkAppHelper* bookmark_app_helper_;
+  int event_request_id_;
+
+  Type GetInfoBarType() const override;
+  int GetIconID() const override;
+
+  DISALLOW_COPY_AND_ASSIGN(AppBannerInfoBarDelegateDesktop);
+};
+
+}  // namespace banners
+
+#endif  // CHROME_BROWSER_BANNERS_APP_BANNER_INFOBAR_DELEGATE_DESKTOP_H_
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc
index fdbf80b..dd3615d 100644
--- a/chrome/browser/banners/app_banner_manager.cc
+++ b/chrome/browser/banners/app_banner_manager.cc
@@ -34,6 +34,14 @@
       weak_factory_(this) {
 }
 
+AppBannerManager::AppBannerManager(content::WebContents* web_contents,
+                                   int icon_size)
+    : content::WebContentsObserver(web_contents),
+      ideal_icon_size_(icon_size),
+      data_fetcher_(nullptr),
+      weak_factory_(this) {
+}
+
 AppBannerManager::~AppBannerManager() {
   CancelActiveFetcher();
 }
@@ -63,7 +71,6 @@
   data_fetcher_->Start(validated_url);
 }
 
-
 bool AppBannerManager::HandleNonWebApp(const std::string& platform,
                                        const GURL& url,
                                        const std::string& id) {
@@ -76,13 +83,6 @@
     data_fetcher_.get()->ReplaceWebContents(web_contents);
 }
 
-AppBannerDataFetcher* AppBannerManager::CreateAppBannerDataFetcher(
-    base::WeakPtr<AppBannerDataFetcher::Delegate> weak_delegate,
-    const int ideal_icon_size) {
-  return new AppBannerDataFetcher(web_contents(), weak_delegate,
-                                  ideal_icon_size);
-}
-
 void AppBannerManager::CancelActiveFetcher() {
   if (data_fetcher_ != nullptr) {
     data_fetcher_->Cancel();
diff --git a/chrome/browser/banners/app_banner_manager.h b/chrome/browser/banners/app_banner_manager.h
index a84be60..e2eeab4 100644
--- a/chrome/browser/banners/app_banner_manager.h
+++ b/chrome/browser/banners/app_banner_manager.h
@@ -44,12 +44,14 @@
                      const GURL& validated_url) override;
 
  protected:
+  AppBannerManager(content::WebContents* web_contents, int icon_size);
+
   void ReplaceWebContents(content::WebContents* web_contents);
 
   // Creates an AppBannerDataFetcher, which constructs an app banner.
   virtual AppBannerDataFetcher* CreateAppBannerDataFetcher(
       base::WeakPtr<AppBannerDataFetcher::Delegate> weak_delegate,
-      const int ideal_icon_size);
+      const int ideal_icon_size) = 0;
 
   // Return whether the AppBannerDataFetcher is active.
   bool IsFetcherActive();
diff --git a/chrome/browser/banners/app_banner_manager_desktop.cc b/chrome/browser/banners/app_banner_manager_desktop.cc
new file mode 100644
index 0000000..e00bcc53
--- /dev/null
+++ b/chrome/browser/banners/app_banner_manager_desktop.cc
@@ -0,0 +1,32 @@
+// 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/banners/app_banner_manager_desktop.h"
+
+#include "chrome/browser/banners/app_banner_data_fetcher_desktop.h"
+#include "extensions/common/constants.h"
+
+namespace {
+// TODO(dominickn) Enforce the set of icons which will guarantee the best
+// user experience.
+int kMinimumIconSize = extension_misc::EXTENSION_ICON_LARGE;
+}  // anonymous namespace
+
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(banners::AppBannerManagerDesktop);
+
+namespace banners {
+
+AppBannerDataFetcher* AppBannerManagerDesktop::CreateAppBannerDataFetcher(
+    base::WeakPtr<AppBannerDataFetcher::Delegate> weak_delegate,
+    const int ideal_icon_size) {
+  return new AppBannerDataFetcherDesktop(web_contents(), weak_delegate,
+                                         ideal_icon_size);
+}
+
+AppBannerManagerDesktop::AppBannerManagerDesktop(
+    content::WebContents* web_contents)
+    : AppBannerManager(web_contents, kMinimumIconSize) {
+}
+
+}  // namespace banners
diff --git a/chrome/browser/banners/app_banner_manager_desktop.h b/chrome/browser/banners/app_banner_manager_desktop.h
new file mode 100644
index 0000000..be12de8
--- /dev/null
+++ b/chrome/browser/banners/app_banner_manager_desktop.h
@@ -0,0 +1,32 @@
+// 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_BANNERS_APP_BANNER_MANAGER_DESKTOP_H_
+#define CHROME_BROWSER_BANNERS_APP_BANNER_MANAGER_DESKTOP_H_
+
+#include "chrome/browser/banners/app_banner_manager.h"
+
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace banners {
+
+class AppBannerManagerDesktop
+    : public AppBannerManager,
+      public content::WebContentsUserData<AppBannerManagerDesktop> {
+
+ protected:
+  AppBannerDataFetcher* CreateAppBannerDataFetcher(
+      base::WeakPtr<AppBannerDataFetcher::Delegate> weak_delegate,
+      const int ideal_icon_size) override;
+
+ private:
+  explicit AppBannerManagerDesktop(content::WebContents* web_contents);
+  friend class content::WebContentsUserData<AppBannerManagerDesktop>;
+
+  DISALLOW_COPY_AND_ASSIGN(AppBannerManagerDesktop);
+};
+
+}  // namespace banners
+
+#endif  // CHROME_BROWSER_BANNERS_APP_BANNER_MANAGER_DESKTOP_H_
diff --git a/chrome/browser/banners/app_banner_settings_helper.cc b/chrome/browser/banners/app_banner_settings_helper.cc
index 19e71101..7306d7b9 100644
--- a/chrome/browser/banners/app_banner_settings_helper.cc
+++ b/chrome/browser/banners/app_banner_settings_helper.cc
@@ -8,11 +8,14 @@
 #include <string>
 
 #include "base/command_line.h"
+#include "chrome/browser/banners/app_banner_data_fetcher.h"
 #include "chrome/browser/banners/app_banner_metrics.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
+#include "components/rappor/rappor_utils.h"
 #include "content/public/browser/web_contents.h"
 #include "net/base/escape.h"
 #include "url/gurl.h"
@@ -95,6 +98,44 @@
   }
 }
 
+void AppBannerSettingsHelper::RecordBannerInstallEvent(
+    content::WebContents* web_contents,
+    const std::string& package_name_or_start_url,
+    AppBannerRapporMetric rappor_metric) {
+  banners::TrackInstallEvent(banners::INSTALL_EVENT_WEB_APP_INSTALLED);
+
+  AppBannerSettingsHelper::RecordBannerEvent(
+      web_contents, web_contents->GetURL(),
+      package_name_or_start_url,
+      AppBannerSettingsHelper::APP_BANNER_EVENT_DID_ADD_TO_HOMESCREEN,
+      banners::AppBannerDataFetcher::GetCurrentTime());
+
+  rappor::SampleDomainAndRegistryFromGURL(
+      g_browser_process->rappor_service(),
+      (rappor_metric == WEB ? "AppBanner.WebApp.Installed"
+                            : "AppBanner.NativeApp.Installed"),
+      web_contents->GetURL());
+}
+
+void AppBannerSettingsHelper::RecordBannerDismissEvent(
+    content::WebContents* web_contents,
+    const std::string& package_name_or_start_url,
+    AppBannerRapporMetric rappor_metric) {
+  banners::TrackDismissEvent(banners::DISMISS_EVENT_CLOSE_BUTTON);
+
+  AppBannerSettingsHelper::RecordBannerEvent(
+      web_contents, web_contents->GetURL(),
+      package_name_or_start_url,
+      AppBannerSettingsHelper::APP_BANNER_EVENT_DID_BLOCK,
+      banners::AppBannerDataFetcher::GetCurrentTime());
+
+  rappor::SampleDomainAndRegistryFromGURL(
+      g_browser_process->rappor_service(),
+      (rappor_metric == WEB ? "AppBanner.WebApp.Dismissed"
+                            : "AppBanner.NativeApp.Dismissed"),
+      web_contents->GetURL());
+}
+
 void AppBannerSettingsHelper::RecordBannerEvent(
     content::WebContents* web_contents,
     const GURL& origin_url,
diff --git a/chrome/browser/banners/app_banner_settings_helper.h b/chrome/browser/banners/app_banner_settings_helper.h
index 8e0e971..b7180211 100644
--- a/chrome/browser/banners/app_banner_settings_helper.h
+++ b/chrome/browser/banners/app_banner_settings_helper.h
@@ -46,6 +46,11 @@
     APP_BANNER_EVENT_NUM_EVENTS,
   };
 
+  enum AppBannerRapporMetric {
+    WEB,
+    NATIVE,
+  };
+
   // The content setting basically records a simplified subset of history.
   // For privacy reasons this needs to be cleared. The ClearHistoryForURLs
   // function removes any information from the banner content settings for the
@@ -53,6 +58,18 @@
   static void ClearHistoryForURLs(Profile* profile,
                                   const std::set<GURL>& origin_urls);
 
+  // Record a banner installation event, for either a WEB or NATIVE app.
+  static void RecordBannerInstallEvent(
+      content::WebContents* web_contents,
+      const std::string& package_name_or_start_url,
+      AppBannerRapporMetric rappor_metric);
+
+  // Record a banner dismissal event, for either a WEB or NATIVE app.
+  static void RecordBannerDismissEvent(
+      content::WebContents* web_contents,
+      const std::string& package_name_or_start_url,
+      AppBannerRapporMetric rappor_metric);
+
   static void RecordBannerEvent(content::WebContents* web_contents,
                                 const GURL& origin_url,
                                 const std::string& package_name_or_start_url,
diff --git a/chrome/browser/bookmarks/enhanced_bookmarks_features.cc b/chrome/browser/bookmarks/enhanced_bookmarks_features.cc
index bbe6335..84e840c 100644
--- a/chrome/browser/bookmarks/enhanced_bookmarks_features.cc
+++ b/chrome/browser/bookmarks/enhanced_bookmarks_features.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/common/chrome_switches.h"
+#include "components/enhanced_bookmarks/enhanced_bookmark_utils.h"
 #include "components/variations/variations_associated_data.h"
 
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
@@ -16,10 +17,9 @@
 
 namespace {
 
-const char kFieldTrialName[] = "EnhancedBookmarks";
-
 bool GetBookmarksExperimentExtensionID(std::string* extension_id) {
-  *extension_id = variations::GetVariationParamValue(kFieldTrialName, "id");
+  *extension_id = variations::GetVariationParamValue(
+      enhanced_bookmarks::kFieldTrialName, "id");
   if (extension_id->empty())
     return false;
 
@@ -46,7 +46,7 @@
   // experience is not a big list of flat colors. However as a precautionary
   // measure it is possible to disable this collection of images from finch.
   std::string disable_fetching = variations::GetVariationParamValue(
-      kFieldTrialName, "DisableImagesFetching");
+      enhanced_bookmarks::kFieldTrialName, "DisableImagesFetching");
   return disable_fetching.empty();
 }
 #endif  // defined(OS_ANDROID)
@@ -83,8 +83,8 @@
           switches::kEnableDomDistiller)) {
     return true;
   }
-  if (variations::GetVariationParamValue(
-          kFieldTrialName, "enable-dom-distiller") == "1")
+  if (variations::GetVariationParamValue(enhanced_bookmarks::kFieldTrialName,
+                                         "enable-dom-distiller") == "1")
     return true;
 
   return false;
@@ -95,8 +95,8 @@
           switches::kEnableSyncArticles)) {
     return true;
   }
-  if (variations::GetVariationParamValue(
-          kFieldTrialName, "enable-sync-articles") == "1")
+  if (variations::GetVariationParamValue(enhanced_bookmarks::kFieldTrialName,
+                                         "enable-sync-articles") == "1")
     return true;
 
   return false;
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 3987476..d79c712 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -298,9 +298,6 @@
         <!-- manifest file of Connectivity Diagnostics app -->
         <include name="IDR_CONNECTIVITY_DIAGNOSTICS_MANIFEST" file="resources\chromeos\connectivity_diagnostics\manifest.json" type="BINDATA" />
         <include name="IDR_CONNECTIVITY_DIAGNOSTICS_LAUNCHER_MANIFEST" file="resources\chromeos\connectivity_diagnostics_launcher\manifest.json" type="BINDATA" />
-        <!-- manifest file of built-in speech synthesis extension -->
-        <include name="IDR_SPEECH_SYNTHESIS_MANIFEST" file="resources\chromeos\speech_synthesis\manifest.json" type="BINDATA" />
-        <include name="IDR_SPEECH_SYNTHESIS_GUEST_MANIFEST" file="resources\chromeos\speech_synthesis\manifest_guest.json" type="BINDATA" />
         <include name="IDR_DRIVE_INTERNALS_CSS" file="resources\chromeos\drive_internals.css" type="BINDATA" />
         <include name="IDR_DRIVE_INTERNALS_HTML" file="resources\chromeos\drive_internals.html" flattenhtml="true" type="BINDATA" />
         <include name="IDR_DRIVE_INTERNALS_JS" file="resources\chromeos\drive_internals.js" type="BINDATA" />
diff --git a/chrome/browser/captive_portal/captive_portal_browsertest.cc b/chrome/browser/captive_portal/captive_portal_browsertest.cc
index 2c8e9159..72fe2bf7 100644
--- a/chrome/browser/captive_portal/captive_portal_browsertest.cc
+++ b/chrome/browser/captive_portal/captive_portal_browsertest.cc
@@ -342,7 +342,7 @@
                                 net::URLRequestStatus::FAILED,
                                 net::ERR_CONNECTION_TIMED_OUT));
     } else if (end_job_operation == FAIL_JOBS_WITH_CERT_ERROR) {
-      ASSERT_TRUE(job->request()->url().SchemeIs(url::kHttpsScheme));
+      DCHECK(job->request()->url().SchemeIsCryptographic());
       net::SSLInfo info;
       info.cert_status = net::CERT_STATUS_COMMON_NAME_INVALID;
       info.cert = new net::X509Certificate(
diff --git a/chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc b/chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc
index ce0c9c7..0a9e3fd 100644
--- a/chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc
+++ b/chrome/browser/captive_portal/captive_portal_tab_helper_unittest.cc
@@ -17,6 +17,7 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/test/test_renderer_host.h"
 #include "net/base/net_errors.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -76,6 +77,14 @@
     ChromeRenderViewHostTestHarness::SetUp();
     web_contents1_.reset(CreateTestWebContents());
     web_contents2_.reset(CreateTestWebContents());
+
+    // This will simulate the initialization of the RenderFrame in the renderer
+    // process. This is needed because WebContents does not initialize a
+    // RenderFrame on construction, and the tests expect one to exist.
+    content::RenderFrameHostTester::For(main_render_frame1())
+        ->InitializeRenderFrameIfNeeded();
+    content::RenderFrameHostTester::For(main_render_frame2())
+        ->InitializeRenderFrameIfNeeded();
   }
 
   void TearDown() override {
diff --git a/chrome/browser/chrome_browser_field_trials_desktop.cc b/chrome/browser/chrome_browser_field_trials_desktop.cc
index b5f2f1f..ab4097ee 100644
--- a/chrome/browser/chrome_browser_field_trials_desktop.cc
+++ b/chrome/browser/chrome_browser_field_trials_desktop.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/auto_launch_trial.h"
 #include "chrome/browser/google/google_brand.h"
 #include "chrome/browser/prerender/prerender_field_trial.h"
+#include "chrome/browser/tracing/background_tracing_field_trial.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/variations/variations_util.h"
 #include "components/variations/variations_associated_data.h"
@@ -46,6 +47,7 @@
   prerender::ConfigurePrerender(parsed_command_line);
   AutoLaunchChromeFieldTrial();
   SetupLightSpeedTrials();
+  tracing::SetupBackgroundTracingFieldTrial();
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 117a7d43..78664bf 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -240,6 +240,10 @@
 #include "chrome/browser/media/webrtc_logging_handler_host.h"
 #endif
 
+#if defined(ENABLE_MEDIA_ROUTER)
+#include "chrome/browser/media/router/presentation_service_delegate_impl.h"
+#endif
+
 using base::FileDescriptor;
 using blink::WebWindowFeatures;
 using content::AccessTokenStore;
@@ -1168,6 +1172,32 @@
 
 }  // namespace
 
+// When Chrome is updated on non-Windows platforms, the new files (like
+// V8 natives and snapshot) can have the same names as the previous
+// versions. Since the renderers for an existing Chrome browser process
+// are likely not compatible with the new files, the browser keeps hold
+// of the old files using an open fd. This fd is passed to subprocesses
+// like renderers.  Here we add the flag to tell the subprocesses where
+// to find these file descriptors.
+void ChromeContentBrowserClient::AppendMappedFileCommandLineSwitches(
+    base::CommandLine* command_line) {
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
+  std::string process_type =
+      command_line->GetSwitchValueASCII(switches::kProcessType);
+  if (process_type != switches::kZygoteProcess) {
+    // We want to pass the natives by fd because after an update the file may
+    // be updated, but we want the newly launched renderers to get the old one,
+    // opened by the browser when it started.
+    DCHECK(natives_fd_exists());
+    command_line->AppendSwitch(::switches::kV8NativesPassedByFD);
+    if (snapshot_fd_exists())
+      command_line->AppendSwitch(::switches::kV8SnapshotPassedByFD);
+  }
+#endif  // V8_USE_EXTERNAL_STARTUP_DATA
+#endif  // OS_POSIX && !OS_MACOSX
+}
+
 void ChromeContentBrowserClient::AppendExtraCommandLineSwitches(
     base::CommandLine* command_line,
     int child_process_id) {
@@ -1226,15 +1256,6 @@
                                   homedir.value().c_str());
 #endif
 
-#if defined(OS_POSIX) && !defined(OS_MACOSX)
-#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
-  if (process_type != switches::kZygoteProcess) {
-    command_line->AppendSwitch(::switches::kV8NativesPassedByFD);
-    command_line->AppendSwitch(::switches::kV8SnapshotPassedByFD);
-  }
-#endif  // V8_USE_EXTERNAL_STARTUP_DATA
-#endif  // OS_POSIX && !OS_MACOSX
-
   if (process_type == switches::kRendererProcess) {
     content::RenderProcessHost* process =
         content::RenderProcessHost::FromID(child_process_id);
@@ -2221,7 +2242,7 @@
     int child_process_id,
     FileDescriptorInfo* mappings) {
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
-  if (v8_natives_fd_.get() == -1 || v8_snapshot_fd_.get() == -1) {
+  if (!natives_fd_exists()) {
     int v8_natives_fd = -1;
     int v8_snapshot_fd = -1;
     if (gin::V8Initializer::OpenV8FilesForChildProcesses(&v8_natives_fd,
@@ -2230,9 +2251,12 @@
       v8_snapshot_fd_.reset(v8_snapshot_fd);
     }
   }
-  DCHECK(v8_natives_fd_.get() != -1 && v8_snapshot_fd_.get() != -1);
+  // V8 can't start up without the source of the natives, but it can
+  // start up (slower) without the snapshot.
+  DCHECK(natives_fd_exists());
   mappings->Share(kV8NativesDataDescriptor, v8_natives_fd_.get());
-  mappings->Share(kV8SnapshotDataDescriptor, v8_snapshot_fd_.get());
+  if (snapshot_fd_exists())
+    mappings->Share(kV8SnapshotDataDescriptor, v8_snapshot_fd_.get());
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
 
 #if defined(OS_ANDROID)
@@ -2361,6 +2385,18 @@
 #endif
 }
 
+content::PresentationServiceDelegate*
+ChromeContentBrowserClient::GetPresentationServiceDelegate(
+      content::WebContents* web_contents) {
+#if defined(ENABLE_MEDIA_ROUTER)
+  if (switches::MediaRouterEnabled()) {
+    return media_router::PresentationServiceDelegateImpl::
+        GetOrCreateForWebContents(web_contents);
+  }
+#endif
+  return nullptr;
+}
+
 void ChromeContentBrowserClient::RecordURLMetric(const std::string& metric,
                                                  const GURL& url) {
   if (url.is_valid()) {
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 89f7b223..b998246 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -112,6 +112,8 @@
       const std::string& alias_name) override;
   void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
                                       int child_process_id) override;
+  void AppendMappedFileCommandLineSwitches(
+      base::CommandLine* command_line) override;
   std::string GetApplicationLocale() override;
   std::string GetAcceptLangs(content::BrowserContext* context) override;
   const gfx::ImageSkia* GetDefaultFavicon() override;
@@ -256,6 +258,8 @@
                const content::OpenURLParams& params,
                const base::Callback<void(content::WebContents*)>& callback)
       override;
+  content::PresentationServiceDelegate* GetPresentationServiceDelegate(
+      content::WebContents* web_contents) override;
 
   void RecordURLMetric(const std::string& metric, const GURL& url) override;
 
@@ -304,6 +308,8 @@
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
   base::ScopedFD v8_natives_fd_;
   base::ScopedFD v8_snapshot_fd_;
+  bool natives_fd_exists() { return v8_natives_fd_ != -1; }
+  bool snapshot_fd_exists() { return v8_snapshot_fd_ != -1; }
 #endif  // OS_POSIX && !OS_MACOSX
 
   // Vector of additional ChromeContentBrowserClientParts.
diff --git a/chrome/browser/chromeos/attestation/platform_verification_flow.cc b/chrome/browser/chromeos/attestation/platform_verification_flow.cc
index 03170f4..cb39766a 100644
--- a/chrome/browser/chromeos/attestation/platform_verification_flow.cc
+++ b/chrome/browser/chromeos/attestation/platform_verification_flow.cc
@@ -24,7 +24,6 @@
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "components/user_manager/user.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/chromeos/events/event_rewriter.cc b/chrome/browser/chromeos/events/event_rewriter.cc
index 05a7b9c..4d75023 100644
--- a/chrome/browser/chromeos/events/event_rewriter.cc
+++ b/chrome/browser/chromeos/events/event_rewriter.cc
@@ -898,13 +898,12 @@
 
 int EventRewriter::RewriteModifierClick(const ui::MouseEvent& mouse_event,
                                         int* flags) {
-  // Remap Search+Button1 to Button3.
-  const int kSearchLeftButton =
-      (ui::EF_COMMAND_DOWN | ui::EF_LEFT_MOUSE_BUTTON);
-  if (((*flags & kSearchLeftButton) == kSearchLeftButton) &&
+  // Remap Alt+Button1 to Button3.
+  const int kAltLeftButton = (ui::EF_ALT_DOWN | ui::EF_LEFT_MOUSE_BUTTON);
+  if (((*flags & kAltLeftButton) == kAltLeftButton) &&
       ((mouse_event.type() == ui::ET_MOUSE_PRESSED) ||
        pressed_device_ids_.count(mouse_event.source_device_id()))) {
-    *flags &= ~kSearchLeftButton;
+    *flags &= ~kAltLeftButton;
     *flags |= ui::EF_RIGHT_MOUSE_BUTTON;
     if (mouse_event.type() == ui::ET_MOUSE_PRESSED)
       pressed_device_ids_.insert(mouse_event.source_device_id());
diff --git a/chrome/browser/chromeos/events/event_rewriter.h b/chrome/browser/chromeos/events/event_rewriter.h
index 3c1a5f3..bfe4daf 100644
--- a/chrome/browser/chromeos/events/event_rewriter.h
+++ b/chrome/browser/chromeos/events/event_rewriter.h
@@ -35,7 +35,7 @@
 // - converts top-row function keys to special keys where necessary;
 // - handles various key combinations like Search+Backspace -> Delete
 //   and Search+number to Fnumber;
-// - handles key/pointer combinations like Search+Button1 -> Button3.
+// - handles key/pointer combinations like Alt+Button1 -> Button3.
 class EventRewriter : public ui::EventRewriter {
  public:
   enum DeviceType {
diff --git a/chrome/browser/chromeos/events/event_rewriter_unittest.cc b/chrome/browser/chromeos/events/event_rewriter_unittest.cc
index dd997c7..71104227 100644
--- a/chrome/browser/chromeos/events/event_rewriter_unittest.cc
+++ b/chrome/browser/chromeos/events/event_rewriter_unittest.cc
@@ -3112,18 +3112,18 @@
   device_list.push_back(10);
   ui::TouchFactory::GetInstance()->SetPointerDeviceForTest(device_list);
 
-  // Remap Control to Search.
+  // Remap Control to Alt.
   TestingPrefServiceSyncable prefs;
   chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
   IntegerPrefMember control;
   control.Init(prefs::kLanguageRemapControlKeyTo, &prefs);
-  control.SetValue(chromeos::input_method::kSearchKey);
+  control.SetValue(chromeos::input_method::kAltKey);
 
   EventRewriter rewriter(NULL);
   rewriter.KeyboardDeviceAddedForTesting(kKeyboardDeviceId, "PC Keyboard");
   rewriter.set_pref_service_for_testing(&prefs);
 
-  // Check that Control + Left Button is converted (via Search + Left Button)
+  // Check that Control + Left Button is converted (via Alt + Left Button)
   // to Right Button.
   ui::ScopedXI2Event xev;
   xev.InitGenericButtonEvent(10, ui::ET_MOUSE_PRESSED, gfx::Point(),
@@ -3138,7 +3138,7 @@
   EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
   EXPECT_FALSE(ui::EF_LEFT_MOUSE_BUTTON & result->flags());
   EXPECT_FALSE(ui::EF_CONTROL_DOWN & result->flags());
-  EXPECT_FALSE(ui::EF_COMMAND_DOWN & result->flags());
+  EXPECT_FALSE(ui::EF_ALT_DOWN & result->flags());
   EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
 #endif
 }
@@ -3155,28 +3155,28 @@
   TestingPrefServiceSyncable prefs;
   EventRewriter rewriter(NULL);
   rewriter.set_pref_service_for_testing(&prefs);
-  const int kLeftAndSearchFlag = ui::EF_LEFT_MOUSE_BUTTON | ui::EF_COMMAND_DOWN;
+  const int kLeftAndAltFlag = ui::EF_LEFT_MOUSE_BUTTON | ui::EF_ALT_DOWN;
 
-  // Test Search + Left click.
+  // Test Alt + Left click.
   {
     ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
-                         ui::EventTimeForNow(), kLeftAndSearchFlag,
+                         ui::EventTimeForNow(), kLeftAndAltFlag,
                          ui::EF_LEFT_MOUSE_BUTTON);
     ui::EventTestApi test_press(&press);
     test_press.set_source_device_id(10);
     // Sanity check.
     EXPECT_EQ(ui::ET_MOUSE_PRESSED, press.type());
-    EXPECT_EQ(kLeftAndSearchFlag, press.flags());
+    EXPECT_EQ(kLeftAndAltFlag, press.flags());
     scoped_ptr<ui::Event> new_event;
     const ui::MouseEvent* result =
         RewriteMouseButtonEvent(&rewriter, press, &new_event);
     EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
-    EXPECT_FALSE(kLeftAndSearchFlag & result->flags());
+    EXPECT_FALSE(kLeftAndAltFlag & result->flags());
     EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
   }
   {
     ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
-                           ui::EventTimeForNow(), kLeftAndSearchFlag,
+                           ui::EventTimeForNow(), kLeftAndAltFlag,
                            ui::EF_LEFT_MOUSE_BUTTON);
     ui::EventTestApi test_release(&release);
     test_release.set_source_device_id(10);
@@ -3184,41 +3184,41 @@
     const ui::MouseEvent* result =
         RewriteMouseButtonEvent(&rewriter, release, &new_event);
     EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
-    EXPECT_FALSE(kLeftAndSearchFlag & result->flags());
+    EXPECT_FALSE(kLeftAndAltFlag & result->flags());
     EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
   }
 #if defined(USE_X11)
-  // Test Search + Left click, using XI2 native events.
+  // Test Alt + Left click, using XI2 native events.
   {
     ui::ScopedXI2Event xev;
     xev.InitGenericButtonEvent(10, ui::ET_MOUSE_PRESSED, gfx::Point(),
-                               kLeftAndSearchFlag);
+                               kLeftAndAltFlag);
     ui::MouseEvent press(xev);
     // Sanity check.
     EXPECT_EQ(ui::ET_MOUSE_PRESSED, press.type());
-    EXPECT_EQ(kLeftAndSearchFlag, press.flags());
+    EXPECT_EQ(kLeftAndAltFlag, press.flags());
     scoped_ptr<ui::Event> new_event;
     const ui::MouseEvent* result =
         RewriteMouseButtonEvent(&rewriter, press, &new_event);
     EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
-    EXPECT_FALSE(kLeftAndSearchFlag & result->flags());
+    EXPECT_FALSE(kLeftAndAltFlag & result->flags());
     EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
   }
   {
     ui::ScopedXI2Event xev;
     xev.InitGenericButtonEvent(10, ui::ET_MOUSE_RELEASED, gfx::Point(),
-                               kLeftAndSearchFlag);
+                               kLeftAndAltFlag);
     ui::MouseEvent release(xev);
     scoped_ptr<ui::Event> new_event;
     const ui::MouseEvent* result =
         RewriteMouseButtonEvent(&rewriter, release, &new_event);
     EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
-    EXPECT_FALSE(kLeftAndSearchFlag & result->flags());
+    EXPECT_FALSE(kLeftAndAltFlag & result->flags());
     EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
   }
 #endif
 
-  // No SEARCH in first click.
+  // No ALT in frst click.
   {
     ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
                          ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
@@ -3233,18 +3233,18 @@
   }
   {
     ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
-                           ui::EventTimeForNow(), kLeftAndSearchFlag,
+                           ui::EventTimeForNow(), kLeftAndAltFlag,
                            ui::EF_LEFT_MOUSE_BUTTON);
     ui::EventTestApi test_release(&release);
     test_release.set_source_device_id(10);
     scoped_ptr<ui::Event> new_event;
     const ui::MouseEvent* result =
         RewriteMouseButtonEvent(&rewriter, release, &new_event);
-    EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON | ui::EF_COMMAND_DOWN, result->flags());
+    EXPECT_TRUE((ui::EF_LEFT_MOUSE_BUTTON | ui::EF_ALT_DOWN) & result->flags());
     EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, result->changed_button_flags());
   }
 #if defined(USE_X11)
-  // No SEARCH in first click, using XI2 native events.
+  // No ALT in frst click, using XI2 native events.
   {
     ui::ScopedXI2Event xev;
     xev.InitGenericButtonEvent(10, ui::ET_MOUSE_PRESSED, gfx::Point(),
@@ -3259,20 +3259,20 @@
   {
     ui::ScopedXI2Event xev;
     xev.InitGenericButtonEvent(10, ui::ET_MOUSE_RELEASED, gfx::Point(),
-                               kLeftAndSearchFlag);
+                               kLeftAndAltFlag);
     ui::MouseEvent release(xev);
     scoped_ptr<ui::Event> new_event;
     const ui::MouseEvent* result =
         RewriteMouseButtonEvent(&rewriter, release, &new_event);
-    EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON | ui::EF_COMMAND_DOWN, result->flags());
+    EXPECT_TRUE((ui::EF_LEFT_MOUSE_BUTTON | ui::EF_ALT_DOWN) & result->flags());
     EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, result->changed_button_flags());
   }
 #endif
 
-  // SEARCH on different device.
+  // ALT on different device.
   {
     ui::MouseEvent press(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
-                         ui::EventTimeForNow(), kLeftAndSearchFlag,
+                         ui::EventTimeForNow(), kLeftAndAltFlag,
                          ui::EF_LEFT_MOUSE_BUTTON);
     ui::EventTestApi test_press(&press);
     test_press.set_source_device_id(11);
@@ -3280,24 +3280,24 @@
     const ui::MouseEvent* result =
         RewriteMouseButtonEvent(&rewriter, press, &new_event);
     EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
-    EXPECT_FALSE(kLeftAndSearchFlag & result->flags());
+    EXPECT_FALSE(kLeftAndAltFlag & result->flags());
     EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
   }
   {
     ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
-                           ui::EventTimeForNow(), kLeftAndSearchFlag,
+                           ui::EventTimeForNow(), kLeftAndAltFlag,
                            ui::EF_LEFT_MOUSE_BUTTON);
     ui::EventTestApi test_release(&release);
     test_release.set_source_device_id(10);
     scoped_ptr<ui::Event> new_event;
     const ui::MouseEvent* result =
         RewriteMouseButtonEvent(&rewriter, release, &new_event);
-    EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON | ui::EF_COMMAND_DOWN, result->flags());
+    EXPECT_TRUE((ui::EF_LEFT_MOUSE_BUTTON | ui::EF_ALT_DOWN) & result->flags());
     EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, result->changed_button_flags());
   }
   {
     ui::MouseEvent release(ui::ET_MOUSE_RELEASED, gfx::Point(), gfx::Point(),
-                           ui::EventTimeForNow(), kLeftAndSearchFlag,
+                           ui::EventTimeForNow(), kLeftAndAltFlag,
                            ui::EF_LEFT_MOUSE_BUTTON);
     ui::EventTestApi test_release(&release);
     test_release.set_source_device_id(11);
@@ -3305,44 +3305,44 @@
     const ui::MouseEvent* result =
         RewriteMouseButtonEvent(&rewriter, release, &new_event);
     EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
-    EXPECT_FALSE(kLeftAndSearchFlag & result->flags());
+    EXPECT_FALSE(kLeftAndAltFlag & result->flags());
     EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
   }
 #if defined(USE_X11)
-  // SEARCH on different device, using XI2 native events.
+  // ALT on different device, using XI2 native events.
   {
     ui::ScopedXI2Event xev;
     xev.InitGenericButtonEvent(11, ui::ET_MOUSE_PRESSED, gfx::Point(),
-                               kLeftAndSearchFlag);
+                               kLeftAndAltFlag);
     ui::MouseEvent press(xev);
     scoped_ptr<ui::Event> new_event;
     const ui::MouseEvent* result =
         RewriteMouseButtonEvent(&rewriter, press, &new_event);
     EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
-    EXPECT_FALSE(kLeftAndSearchFlag & result->flags());
+    EXPECT_FALSE(kLeftAndAltFlag & result->flags());
     EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
   }
   {
     ui::ScopedXI2Event xev;
     xev.InitGenericButtonEvent(10, ui::ET_MOUSE_RELEASED, gfx::Point(),
-                               kLeftAndSearchFlag);
+                               kLeftAndAltFlag);
     ui::MouseEvent release(xev);
     scoped_ptr<ui::Event> new_event;
     const ui::MouseEvent* result =
         RewriteMouseButtonEvent(&rewriter, release, &new_event);
-    EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON | ui::EF_COMMAND_DOWN, result->flags());
+    EXPECT_TRUE((ui::EF_LEFT_MOUSE_BUTTON | ui::EF_ALT_DOWN) & result->flags());
     EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, result->changed_button_flags());
   }
   {
     ui::ScopedXI2Event xev;
     xev.InitGenericButtonEvent(11, ui::ET_MOUSE_RELEASED, gfx::Point(),
-                               kLeftAndSearchFlag);
+                               kLeftAndAltFlag);
     ui::MouseEvent release(xev);
     scoped_ptr<ui::Event> new_event;
     const ui::MouseEvent* result =
         RewriteMouseButtonEvent(&rewriter, release, &new_event);
     EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & result->flags());
-    EXPECT_FALSE(kLeftAndSearchFlag & result->flags());
+    EXPECT_FALSE(kLeftAndAltFlag & result->flags());
     EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, result->changed_button_flags());
   }
 #endif
diff --git a/chrome/browser/chromeos/extensions/external_cache.cc b/chrome/browser/chromeos/extensions/external_cache.cc
index 5d8e3c25..df59b97 100644
--- a/chrome/browser/chromeos/extensions/external_cache.cc
+++ b/chrome/browser/chromeos/extensions/external_cache.cc
@@ -106,7 +106,7 @@
       return;
     }
   }
-  LOG(ERROR) << "ExternalCache cannot find external_crx " << path.value();
+  DLOG(ERROR) << "ExternalCache cannot find external_crx " << path.value();
 }
 
 void ExternalCache::RemoveExtensions(const std::vector<std::string>& ids) {
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc
index e03e5bc..2026e43 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -12,6 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
@@ -31,13 +32,17 @@
 #include "components/storage_monitor/storage_monitor.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
+#include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
 #include "storage/browser/fileapi/external_mount_points.h"
 
 namespace file_manager {
 namespace {
 
+const uint32 kAccessCapabilityReadWrite = 0;
+const uint32 kFilesystemTypeGenericHierarchical = 2;
 const char kFileManagerMTPMountNamePrefix[] = "fileman-mtp-";
 const char kMtpVolumeIdPrefix [] = "mtp:";
+const char kRootPath[] = "/";
 
 // Registers |path| as the "Downloads" folder to the FileSystem API backend.
 // If another folder is already mounted. It revokes and overrides the old one.
@@ -280,11 +285,13 @@
     drive::DriveIntegrationService* drive_integration_service,
     chromeos::PowerManagerClient* power_manager_client,
     chromeos::disks::DiskMountManager* disk_mount_manager,
-    chromeos::file_system_provider::Service* file_system_provider_service)
+    chromeos::file_system_provider::Service* file_system_provider_service,
+    GetMtpStorageInfoCallback get_mtp_storage_info_callback)
     : profile_(profile),
       drive_integration_service_(drive_integration_service),
       disk_mount_manager_(disk_mount_manager),
       file_system_provider_service_(file_system_provider_service),
+      get_mtp_storage_info_callback_(get_mtp_storage_info_callback),
       snapshot_manager_(new SnapshotManager(profile_)),
       weak_ptr_factory_(this) {
   DCHECK(disk_mount_manager);
@@ -701,17 +708,36 @@
           path);
   DCHECK(result);
 
-  bool disable_mtp_write = base::CommandLine::ForCurrentProcess()->HasSwitch(
-      chromeos::switches::kDisableMtpWriteSupport);
+  // Resolve mtp storage name and get MtpStorageInfo.
+  std::string storage_name;
+  base::RemoveChars(info.location(), kRootPath, &storage_name);
+  DCHECK(!storage_name.empty());
+
+  const MtpStorageInfo* mtp_storage_info;
+  if (get_mtp_storage_info_callback_.is_null()) {
+    mtp_storage_info = storage_monitor::StorageMonitor::GetInstance()
+                           ->media_transfer_protocol_manager()
+                           ->GetStorageInfo(storage_name);
+  } else {
+    mtp_storage_info = get_mtp_storage_info_callback_.Run(storage_name);
+  }
+  DCHECK(mtp_storage_info);
+
+  // Mtp write is enabled only when the device is writable and supports generic
+  // hierarchical file system.
+  const bool read_only =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          chromeos::switches::kDisableMtpWriteSupport) ||
+      mtp_storage_info->access_capability() != kAccessCapabilityReadWrite ||
+      mtp_storage_info->filesystem_type() != kFilesystemTypeGenericHierarchical;
 
   content::BrowserThread::PostTask(
       content::BrowserThread::IO, FROM_HERE,
       base::Bind(&MTPDeviceMapService::RegisterMTPFileSystem,
                  base::Unretained(MTPDeviceMapService::GetInstance()),
-                 info.location(), fsid, disable_mtp_write /* read_only */));
+                 info.location(), fsid, read_only));
 
-  linked_ptr<Volume> volume(
-      Volume::CreateForMTP(path, label, disable_mtp_write));
+  linked_ptr<Volume> volume(Volume::CreateForMTP(path, label, read_only));
   DoMountEvent(chromeos::MOUNT_ERROR_NONE, volume);
 }
 
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.h b/chrome/browser/chromeos/file_manager/volume_manager.h
index 97b8c7b2..81166f4 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager.h
+++ b/chrome/browser/chromeos/file_manager/volume_manager.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/basictypes.h"
+#include "base/callback.h"
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/memory/linked_ptr.h"
@@ -24,6 +25,7 @@
 #include "chromeos/disks/disk_mount_manager.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/storage_monitor/removable_storage_observer.h"
+#include "device/media_transfer_protocol/mtp_storage_info.pb.h"
 
 class Profile;
 
@@ -196,12 +198,18 @@
                       public chromeos::file_system_provider::Observer,
                       public storage_monitor::RemovableStorageObserver {
  public:
+  // Returns MediaTransferProtocolManager. Used for injecting
+  // FakeMediaTransferProtocolManager for testing.
+  typedef base::Callback<const MtpStorageInfo*(const std::string&)>
+      GetMtpStorageInfoCallback;
+
   VolumeManager(
       Profile* profile,
       drive::DriveIntegrationService* drive_integration_service,
       chromeos::PowerManagerClient* power_manager_client,
       chromeos::disks::DiskMountManager* disk_mount_manager,
-      chromeos::file_system_provider::Service* file_system_provider_service);
+      chromeos::file_system_provider::Service* file_system_provider_service,
+      GetMtpStorageInfoCallback get_mtp_storage_info_callback);
   ~VolumeManager() override;
 
   // Returns the instance corresponding to the |context|.
@@ -297,6 +305,7 @@
   base::ObserverList<VolumeManagerObserver> observers_;
   chromeos::file_system_provider::Service*
       file_system_provider_service_;  // Not owned by this class.
+  GetMtpStorageInfoCallback get_mtp_storage_info_callback_;
   std::map<std::string, linked_ptr<Volume>> mounted_volumes_;
   scoped_ptr<SnapshotManager> snapshot_manager_;
 
diff --git a/chrome/browser/chromeos/file_manager/volume_manager_factory.cc b/chrome/browser/chromeos/file_manager/volume_manager_factory.cc
index 0d0eb08..4b64ecb 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager_factory.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager_factory.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/file_manager/volume_manager_factory.h"
 
 #include "base/basictypes.h"
+#include "base/bind.h"
 #include "base/memory/singleton.h"
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
 #include "chrome/browser/chromeos/file_manager/volume_manager.h"
@@ -14,6 +15,8 @@
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/disks/disk_mount_manager.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/storage_monitor/storage_monitor.h"
+#include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
 
 namespace file_manager {
 
@@ -44,11 +47,11 @@
     content::BrowserContext* context) const {
   Profile* const profile = Profile::FromBrowserContext(context);
   VolumeManager* instance = new VolumeManager(
-      profile,
-      drive::DriveIntegrationServiceFactory::GetForProfile(profile),
+      profile, drive::DriveIntegrationServiceFactory::GetForProfile(profile),
       chromeos::DBusThreadManager::Get()->GetPowerManagerClient(),
       chromeos::disks::DiskMountManager::GetInstance(),
-      chromeos::file_system_provider::ServiceFactory::Get(context));
+      chromeos::file_system_provider::ServiceFactory::Get(context),
+      VolumeManager::GetMtpStorageInfoCallback());
   instance->Initialize();
   return instance;
 }
diff --git a/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc b/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc
index f27aadeb..79e3914 100644
--- a/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/volume_manager_unittest.cc
@@ -21,6 +21,7 @@
 #include "chromeos/disks/disk_mount_manager.h"
 #include "components/storage_monitor/storage_info.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "device/media_transfer_protocol/mtp_storage_info.pb.h"
 #include "extensions/browser/extension_registry.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -149,12 +150,14 @@
               new chromeos::file_system_provider::Service(
                   profile_.get(),
                   extension_registry_.get())),
-          volume_manager_(
-              new VolumeManager(profile_.get(),
-                                NULL,  // DriveIntegrationService
-                                power_manager_client,
-                                disk_manager,
-                                file_system_provider_service_.get())) {
+          volume_manager_(new VolumeManager(
+              profile_.get(),
+              NULL,  // DriveIntegrationService
+              power_manager_client,
+              disk_manager,
+              file_system_provider_service_.get(),
+              base::Bind(&ProfileEnvironment::GetFakeMtpStorageInfo,
+                         base::Unretained(this)))) {
       file_system_provider_service_->SetFileSystemFactoryForTesting(base::Bind(
           &chromeos::file_system_provider::FakeProvidedFileSystem::Create));
     }
@@ -163,11 +166,17 @@
     VolumeManager* volume_manager() const { return volume_manager_.get(); }
 
    private:
+    const MtpStorageInfo* GetFakeMtpStorageInfo(
+        const std::string& /*storage_name*/) {
+      return &fake_mtp_storage_info_;
+    }
+
     scoped_ptr<TestingProfile> profile_;
     scoped_ptr<extensions::ExtensionRegistry> extension_registry_;
     scoped_ptr<chromeos::file_system_provider::Service>
         file_system_provider_service_;
     scoped_ptr<VolumeManager> volume_manager_;
+    const MtpStorageInfo fake_mtp_storage_info_;
   };
 
   void SetUp() override {
diff --git a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
index dc10ab14..d2e8786 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
@@ -465,7 +465,8 @@
 
 // MergeSession test is running merge session process for an existing profile
 // that was generated in PRE_PRE_MergeSession test.
-IN_PROC_BROWSER_TEST_P(OAuth2Test, PRE_MergeSession) {
+// Disabled due to flakiness: crbug.com/496832
+IN_PROC_BROWSER_TEST_P(OAuth2Test, DISABLED_PRE_MergeSession) {
   SetupGaiaServerForExpiredAccount();
   SimulateNetworkOnline();
   LoginAsExistingUser();
@@ -481,7 +482,8 @@
 // MergeSession test is attempting to merge session for an existing profile
 // that was generated in PRE_PRE_MergeSession test. This attempt should fail
 // since FakeGaia instance isn't configured to return relevant tokens/cookies.
-IN_PROC_BROWSER_TEST_P(OAuth2Test, MergeSession) {
+// Disabled due to flakiness: crbug.com/496832
+IN_PROC_BROWSER_TEST_P(OAuth2Test, DISABLED_MergeSession) {
   SimulateNetworkOnline();
 
   content::WindowedNotificationObserver(
diff --git a/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc b/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc
index 890bd89..f2f347b 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc
@@ -307,18 +307,18 @@
 }
 
 void OAuth2LoginManager::OnListAccountsSuccess(
-    const std::vector<std::pair<std::string, bool>>& accounts) {
+    const std::vector<gaia::ListedAccount>& accounts) {
   MergeVerificationOutcome outcome = POST_MERGE_SUCCESS;
   // Let's analyze which accounts we see logged in here:
   std::string user_email = gaia::CanonicalizeEmail(GetPrimaryAccountId());
   if (!accounts.empty()) {
     bool found = false;
     bool first = true;
-    for (std::vector<std::pair<std::string, bool> >::const_iterator iter =
+    for (std::vector<gaia::ListedAccount>::const_iterator iter =
              accounts.begin();
          iter != accounts.end(); ++iter) {
-      if (gaia::CanonicalizeEmail(iter->first) == user_email) {
-        found = iter->second;
+      if (iter->email == user_email) {
+        found = iter->valid;
         break;
       }
 
diff --git a/chrome/browser/chromeos/login/signin/oauth2_login_manager.h b/chrome/browser/chromeos/login/signin/oauth2_login_manager.h
index ba774c4f..580f3cb 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_login_manager.h
+++ b/chrome/browser/chromeos/login/signin/oauth2_login_manager.h
@@ -157,7 +157,7 @@
   void OnSessionMergeSuccess() override;
   void OnSessionMergeFailure(bool connection_error) override;
   void OnListAccountsSuccess(
-      const std::vector<std::pair<std::string, bool>>& accounts) override;
+      const std::vector<gaia::ListedAccount>& accounts) override;
   void OnListAccountsFailure(bool connection_error) override;
 
   // OAuth2TokenFetcher::Delegate overrides.
diff --git a/chrome/browser/chromeos/login/signin/oauth2_login_verifier.cc b/chrome/browser/chromeos/login/signin/oauth2_login_verifier.cc
index b2f8a8a..c9317a7 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_login_verifier.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_login_verifier.cc
@@ -33,7 +33,7 @@
 void OAuth2LoginVerifier::VerifyUserCookies(Profile* profile) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  std::vector<std::pair<std::string, bool> > accounts;
+  std::vector<gaia::ListedAccount> accounts;
   if (cookie_manager_service_->ListAccounts(&accounts)) {
     OnGaiaAccountsInCookieUpdated(
         accounts, GoogleServiceAuthError(GoogleServiceAuthError::NONE));
@@ -68,8 +68,8 @@
 }
 
 void OAuth2LoginVerifier::OnGaiaAccountsInCookieUpdated(
-      const std::vector<std::pair<std::string, bool> >& accounts,
-      const GoogleServiceAuthError& error) {
+    const std::vector<gaia::ListedAccount>& accounts,
+    const GoogleServiceAuthError& error) {
   if (error.state() == GoogleServiceAuthError::State::NONE) {
     VLOG(1) << "ListAccounts successful.";
     delegate_->OnListAccountsSuccess(accounts);
diff --git a/chrome/browser/chromeos/login/signin/oauth2_login_verifier.h b/chrome/browser/chromeos/login/signin/oauth2_login_verifier.h
index 9c4a52c7..f105a1f 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_login_verifier.h
+++ b/chrome/browser/chromeos/login/signin/oauth2_login_verifier.h
@@ -32,7 +32,7 @@
     // Invoked when account list is retrieved during post-merge session
     // verification.
     virtual void OnListAccountsSuccess(
-        const std::vector<std::pair<std::string, bool>>& accounts) = 0;
+        const std::vector<gaia::ListedAccount>& accounts) = 0;
 
     // Invoked when post-merge session verification fails.
     virtual void OnListAccountsFailure(bool connection_error) = 0;
@@ -57,8 +57,8 @@
       const std::string& account_id,
       const GoogleServiceAuthError& error) override;
   void OnGaiaAccountsInCookieUpdated(
-        const std::vector<std::pair<std::string, bool> >& accounts,
-        const GoogleServiceAuthError& error) override;
+      const std::vector<gaia::ListedAccount>& accounts,
+      const GoogleServiceAuthError& error) override;
 
   OAuth2LoginVerifier::Delegate* delegate_;
   GaiaCookieManagerService* cookie_manager_service_;
diff --git a/chrome/browser/chromeos/memory/oom_priority_manager.cc b/chrome/browser/chromeos/memory/oom_priority_manager.cc
index 4d3969b..76429cf9 100644
--- a/chrome/browser/chromeos/memory/oom_priority_manager.cc
+++ b/chrome/browser/chromeos/memory/oom_priority_manager.cc
@@ -29,6 +29,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
 #include "chrome/browser/chromeos/memory/low_memory_observer.h"
+#include "chrome/browser/chromeos/memory/system_memory_stats_recorder.h"
 #include "chrome/browser/memory_details.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_iterator.h"
@@ -58,10 +59,6 @@
 
 namespace {
 
-// Record a size in megabytes, over a potential interval up to 32 GB.
-#define UMA_HISTOGRAM_MEGABYTES(name, sample)                     \
-    UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 32768, 50)
-
 // The default interval in seconds after which to adjust the oom_score_adj
 // value.
 const int kAdjustmentIntervalSeconds = 10;
@@ -87,23 +84,6 @@
   return reinterpret_cast<int64>(web_contents);
 }
 
-// Records a statistics |sample| for UMA histogram |name| using a linear
-// distribution of buckets.
-void RecordLinearHistogram(const std::string& name,
-                           int sample,
-                           int maximum,
-                           size_t bucket_count) {
-  // Do not use the UMA_HISTOGRAM_... macros here.  They cache the Histogram
-  // instance and thus only work if |name| is constant.
-  base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
-      name,
-      1,  // Minimum. The 0 bin for underflow is automatically added.
-      maximum + 1,  // Ensure bucket size of |maximum| / |bucket_count|.
-      bucket_count + 2,  // Account for the underflow and overflow bins.
-      base::Histogram::kUmaTargetedHistogramFlag);
-  counter->Add(sample);
-}
-
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -370,39 +350,10 @@
     UMA_HISTOGRAM_CUSTOM_COUNTS(
         "Tabs.Discard.IntervalTime2", interval_ms, 100, 100000 * 1000, 50);
   }
-  // Record Chrome's concept of system memory usage at the time of the discard.
-  base::SystemMemoryInfoKB memory;
-  if (base::GetSystemMemoryInfo(&memory)) {
-    // TODO(jamescook): Remove this after R25 is deployed to stable. It does
-    // not have sufficient resolution in the 2-4 GB range and does not properly
-    // account for graphics memory on ARM. Replace with MemAllocatedMB below.
-    int mem_anonymous_mb = (memory.active_anon + memory.inactive_anon) / 1024;
-    UMA_HISTOGRAM_MEGABYTES("Tabs.Discard.MemAnonymousMB", mem_anonymous_mb);
+  // Record chromeos's concept of system memory usage at the time of the
+  // discard.
+  RecordMemoryStats(RECORD_MEMORY_STATS_TAB_DISCARDED);
 
-    // Record graphics GEM object size in a histogram with 50 MB buckets.
-    int mem_graphics_gem_mb = 0;
-    if (memory.gem_size != -1)
-      mem_graphics_gem_mb = memory.gem_size / 1024 / 1024;
-    RecordLinearHistogram(
-        "Tabs.Discard.MemGraphicsMB", mem_graphics_gem_mb, 2500, 50);
-
-    // Record shared memory (used by renderer/GPU buffers).
-    int mem_shmem_mb = memory.shmem / 1024;
-    RecordLinearHistogram("Tabs.Discard.MemShmemMB", mem_shmem_mb, 2500, 50);
-
-    // On Intel, graphics objects are in anonymous pages, but on ARM they are
-    // not. For a total "allocated count" add in graphics pages on ARM.
-    int mem_allocated_mb = mem_anonymous_mb;
-#if defined(ARCH_CPU_ARM_FAMILY)
-    mem_allocated_mb += mem_graphics_gem_mb;
-#endif
-    UMA_HISTOGRAM_CUSTOM_COUNTS(
-        "Tabs.Discard.MemAllocatedMB", mem_allocated_mb, 256, 32768, 50);
-
-    int mem_available_mb =
-        (memory.active_file + memory.inactive_file + memory.free) / 1024;
-    UMA_HISTOGRAM_MEGABYTES("Tabs.Discard.MemAvailableMB", mem_available_mb);
-  }
   // Set up to record the next interval.
   last_discard_time_ = TimeTicks::Now();
 }
diff --git a/chrome/browser/chromeos/memory/system_memory_stats_recorder.cc b/chrome/browser/chromeos/memory/system_memory_stats_recorder.cc
new file mode 100644
index 0000000..20a605cb
--- /dev/null
+++ b/chrome/browser/chromeos/memory/system_memory_stats_recorder.cc
@@ -0,0 +1,94 @@
+// 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/chromeos/memory/system_memory_stats_recorder.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "base/process/process_metrics.h"
+
+// Record a size in megabytes, over a potential interval up to 32 GB.
+#define UMA_HISTOGRAM_AVAILABLE_MEGABYTES(name, sample) \
+  UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 32768, 50)
+
+// Record a size in megabytes, a potential interval from 250MB up to
+// 32 GB.
+#define UMA_HISTOGRAM_ALLOCATED_MEGABYTES(name, sample) \
+  UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 250, 32768, 50)
+
+// Records a statistics |sample| for UMA histogram |name|
+// using a linear distribution of buckets.
+#define UMA_HISTOGRAM_LINEAR(name, sample, max, buckets)                       \
+  STATIC_HISTOGRAM_POINTER_BLOCK(                                              \
+      name, Add(sample),                                                       \
+      base::LinearHistogram::FactoryGet(                                       \
+          name,                                                                \
+          1, /* Minimum. The 0 bin for underflow is automatically added. */    \
+          max + 1,     /* Ensure bucket size of |maximum| / |bucket_count|. */ \
+          buckets + 2, /*  Account for the underflow and overflow bins. */     \
+          base::Histogram::kUmaTargetedHistogramFlag))
+
+#define UMA_HISTOGRAM_MEGABYTES_LINEAR(name, sample) \
+  UMA_HISTOGRAM_LINEAR(name, sample, 2500, 50)
+
+namespace chromeos {
+
+void RecordMemoryStats(RecordMemoryStatsType type) {
+  base::SystemMemoryInfoKB memory;
+  if (!base::GetSystemMemoryInfo(&memory))
+    return;
+  // Record graphics GEM object size in a histogram with 50 MB buckets.
+  int mem_graphics_gem_mb = 0;
+  if (memory.gem_size != -1)
+    mem_graphics_gem_mb = memory.gem_size / 1024 / 1024;
+
+  // Record shared memory (used by renderer/GPU buffers).
+  int mem_shmem_mb = memory.shmem / 1024;
+
+  // On Intel, graphics objects are in anonymous pages, but on ARM they are
+  // not. For a total "allocated count" add in graphics pages on ARM.
+  int mem_allocated_mb = (memory.active_anon + memory.inactive_anon) / 1024;
+#if defined(ARCH_CPU_ARM_FAMILY)
+  mem_allocated_mb += mem_graphics_gem_mb;
+#endif
+
+  int mem_available_mb =
+      (memory.active_file + memory.inactive_file + memory.free) / 1024;
+
+  switch (type) {
+    case RECORD_MEMORY_STATS_TAB_DISCARDED: {
+      UMA_HISTOGRAM_MEGABYTES_LINEAR("Tabs.Discard.MemGraphicsMB",
+                                     mem_graphics_gem_mb);
+      UMA_HISTOGRAM_MEGABYTES_LINEAR("Tabs.Discard.MemShmemMB", mem_shmem_mb);
+      UMA_HISTOGRAM_ALLOCATED_MEGABYTES("Tabs.Discard.MemAllocatedMB",
+                                        mem_allocated_mb);
+      UMA_HISTOGRAM_AVAILABLE_MEGABYTES("Tabs.Discard.MemAvailableMB",
+                                        mem_available_mb);
+      break;
+    }
+    case RECORD_MEMORY_STATS_CONTENTS_OOM_KILLED: {
+      UMA_HISTOGRAM_MEGABYTES_LINEAR("Memory.OOMKill.Contents.MemGraphicsMB",
+                                     mem_graphics_gem_mb);
+      UMA_HISTOGRAM_MEGABYTES_LINEAR("Memory.OOMKill.Contents.MemShmemMB",
+                                     mem_shmem_mb);
+      UMA_HISTOGRAM_ALLOCATED_MEGABYTES(
+          "Memory.OOMKill.Contents.MemAllocatedMB", mem_allocated_mb);
+      UMA_HISTOGRAM_AVAILABLE_MEGABYTES(
+          "Memory.OOMKill.Contents.MemAvailableMB", mem_available_mb);
+      break;
+    }
+    case RECORD_MEMORY_STATS_EXTENSIONS_OOM_KILLED: {
+      UMA_HISTOGRAM_MEGABYTES_LINEAR("Memory.OOMKill.Extensions.MemGraphicsMB",
+                                     mem_graphics_gem_mb);
+      UMA_HISTOGRAM_MEGABYTES_LINEAR("Memory.OOMKill.Extensions.MemShmemMB",
+                                     mem_shmem_mb);
+      UMA_HISTOGRAM_ALLOCATED_MEGABYTES(
+          "Memory.OOMKill.Extensions.MemAllocatedMB", mem_allocated_mb);
+      UMA_HISTOGRAM_AVAILABLE_MEGABYTES(
+          "Memory.OOMKill.Extensions.MemAvailableMB", mem_available_mb);
+      break;
+    }
+  }
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/memory/system_memory_stats_recorder.h b/chrome/browser/chromeos/memory/system_memory_stats_recorder.h
new file mode 100644
index 0000000..decab265
--- /dev/null
+++ b/chrome/browser/chromeos/memory/system_memory_stats_recorder.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 CHROME_BROWSER_CHROMEOS_MEMORY_SYSTEM_MEMORY_STATS_RECORDER_H_
+#define CHROME_BROWSER_CHROMEOS_MEMORY_SYSTEM_MEMORY_STATS_RECORDER_H_
+
+namespace chromeos {
+
+// The type of memory UMA stats to be recorded in RecordMemoryStats.
+enum RecordMemoryStatsType {
+  // When a tab was discarded.
+  RECORD_MEMORY_STATS_TAB_DISCARDED,
+
+  // Right after the renderer for contents was killed.
+  RECORD_MEMORY_STATS_CONTENTS_OOM_KILLED,
+
+  // Right after the renderer for extensions was killed.
+  RECORD_MEMORY_STATS_EXTENSIONS_OOM_KILLED,
+};
+
+void RecordMemoryStats(RecordMemoryStatsType type);
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_MEMORY_SYSTEM_MEMORY_STATS_RECORDER_H_
diff --git a/chrome/browser/chromeos/options/vpn_config_view.cc b/chrome/browser/chromeos/options/vpn_config_view.cc
index 7c3334b..de4648c2 100644
--- a/chrome/browser/chromeos/options/vpn_config_view.cc
+++ b/chrome/browser/chromeos/options/vpn_config_view.cc
@@ -228,6 +228,7 @@
       enable_server_ca_cert_(false),
       enable_otp_(false),
       enable_group_name_(false),
+      user_passphrase_required_(false),
       title_(0),
       layout_(NULL),
       server_textfield_(NULL),
@@ -280,7 +281,7 @@
     else if (server_ca_cert_combobox_ && server_ca_cert_combobox_->enabled())
       return server_ca_cert_combobox_;
   }
-  if (user_passphrase_textfield_)
+  if (user_passphrase_textfield_ && user_passphrase_required_)
     return user_passphrase_textfield_;
   else if (otp_textfield_)
     return otp_textfield_;
@@ -713,7 +714,7 @@
 
   std::string provider_type, server_hostname, username, group_name;
   bool psk_passphrase_required = false;
-  bool user_passphrase_required = true;
+  user_passphrase_required_ = true;
   const base::DictionaryValue* provider_properties;
   if (service_properties.GetDictionaryWithoutPathExpansion(
           shill::kProviderProperty, &provider_properties)) {
@@ -740,7 +741,7 @@
       provider_properties->GetStringWithoutPathExpansion(
           shill::kOpenVPNUserProperty, &username);
       provider_properties->GetBooleanWithoutPathExpansion(
-          shill::kPassphraseRequiredProperty, &user_passphrase_required);
+          shill::kPassphraseRequiredProperty, &user_passphrase_required_);
     }
   }
   bool save_credentials = false;
@@ -764,7 +765,7 @@
   if (psk_passphrase_textfield_)
     psk_passphrase_textfield_->SetShowFake(!psk_passphrase_required);
   if (user_passphrase_textfield_)
-    user_passphrase_textfield_->SetShowFake(!user_passphrase_required);
+    user_passphrase_textfield_->SetShowFake(!user_passphrase_required_);
   if (save_credentials_checkbox_)
     save_credentials_checkbox_->SetChecked(save_credentials);
 
diff --git a/chrome/browser/chromeos/options/vpn_config_view.h b/chrome/browser/chromeos/options/vpn_config_view.h
index 76427dd..a316f1c 100644
--- a/chrome/browser/chromeos/options/vpn_config_view.h
+++ b/chrome/browser/chromeos/options/vpn_config_view.h
@@ -146,6 +146,7 @@
   bool enable_server_ca_cert_;
   bool enable_otp_;
   bool enable_group_name_;
+  bool user_passphrase_required_;
 
   NetworkPropertyUIData ca_cert_ui_data_;
   NetworkPropertyUIData psk_passphrase_ui_data_;
diff --git a/chrome/browser/chromeos/policy/wildcard_login_checker.cc b/chrome/browser/chromeos/policy/wildcard_login_checker.cc
index ab398f3..1e53a69 100644
--- a/chrome/browser/chromeos/policy/wildcard_login_checker.cc
+++ b/chrome/browser/chromeos/policy/wildcard_login_checker.cc
@@ -41,8 +41,8 @@
   CHECK(!user_info_fetcher_);
 
   start_timestamp_ = base::Time::Now();
-
   callback_ = callback;
+
   token_fetcher_.reset(new PolicyOAuth2TokenFetcher());
   token_fetcher_->StartWithSigninContext(
       signin_context.get(), g_browser_process->system_request_context(),
@@ -57,8 +57,8 @@
   CHECK(!user_info_fetcher_);
 
   start_timestamp_ = base::Time::Now();
-
   callback_ = callback;
+
   token_fetcher_.reset(new PolicyOAuth2TokenFetcher());
   token_fetcher_->StartWithRefreshToken(
       refresh_token, g_browser_process->system_request_context(),
@@ -71,6 +71,8 @@
     const StatusCallback& callback) {
   CHECK(!token_fetcher_);
   CHECK(!user_info_fetcher_);
+
+  start_timestamp_ = base::Time::Now();
   callback_ = callback;
 
   StartUserInfoFetcher(access_token);
diff --git a/chrome/browser/content_settings/permission_bubble_request_impl.h b/chrome/browser/content_settings/permission_bubble_request_impl.h
index 985c9d0..2df8111 100644
--- a/chrome/browser/content_settings/permission_bubble_request_impl.h
+++ b/chrome/browser/content_settings/permission_bubble_request_impl.h
@@ -6,10 +6,10 @@
 #define CHROME_BROWSER_CONTENT_SETTINGS_PERMISSION_BUBBLE_REQUEST_IMPL_H_
 
 #include "base/callback.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/browser/ui/website_settings/permission_bubble_request.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 
 class GURL;
 
diff --git a/chrome/browser/content_settings/permission_context_base.cc b/chrome/browser/content_settings/permission_context_base.cc
index d80f3d41..8be0b7d2 100644
--- a/chrome/browser/content_settings/permission_context_base.cc
+++ b/chrome/browser/content_settings/permission_context_base.cc
@@ -9,12 +9,12 @@
 #include "chrome/browser/content_settings/permission_bubble_request_impl.h"
 #include "chrome/browser/content_settings/permission_context_uma_util.h"
 #include "chrome/browser/content_settings/permission_queue_controller.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
 #include "chrome/common/pref_names.h"
 #include "components/content_settings/core/browser/content_settings_utils.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/origin_util.h"
diff --git a/chrome/browser/content_settings/permission_context_base_unittest.cc b/chrome/browser/content_settings/permission_context_base_unittest.cc
index 35f361a..86b153b 100644
--- a/chrome/browser/content_settings/permission_context_base_unittest.cc
+++ b/chrome/browser/content_settings/permission_context_base_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/command_line.h"
 #include "chrome/browser/content_settings/permission_queue_controller.h"
 #include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
@@ -15,7 +16,6 @@
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/mock_render_process_host.h"
diff --git a/chrome/browser/content_settings/permission_infobar_delegate.h b/chrome/browser/content_settings/permission_infobar_delegate.h
index 2f238b8..25bb0b4 100644
--- a/chrome/browser/content_settings/permission_infobar_delegate.h
+++ b/chrome/browser/content_settings/permission_infobar_delegate.h
@@ -6,8 +6,8 @@
 #define CHROME_BROWSER_CONTENT_SETTINGS_PERMISSION_INFOBAR_DELEGATE_H_
 
 #include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "components/content_settings/core/common/content_settings_types.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "components/infobars/core/confirm_infobar_delegate.h"
 #include "content/public/browser/web_contents.h"
 
diff --git a/chrome/browser/content_settings/permission_queue_controller.cc b/chrome/browser/content_settings/permission_queue_controller.cc
index 10cf79b..dab4a8a7 100644
--- a/chrome/browser/content_settings/permission_queue_controller.cc
+++ b/chrome/browser/content_settings/permission_queue_controller.cc
@@ -181,7 +181,7 @@
 
   for (PendingInfobarRequests::iterator i(pending_infobar_requests_.begin());
        i != pending_infobar_requests_.end(); ++i) {
-    if (!i->id().Equals(id))
+    if (id != i->id())
       continue;
 
     InfoBarService* infobar_service = GetInfoBarService(id);
@@ -229,7 +229,7 @@
       pending_requests_to_remove.push_back(i);
       continue;
     }
-    if (i->id().Equals(id)) {
+    if (id == i->id()) {
       // The infobar that called us is i->infobar(), and its delegate is
       // currently in either Accept() or Cancel(). This means that
       // RemoveInfoBar() will be called later on, and that will trigger a
diff --git a/chrome/browser/content_settings/permission_queue_controller_unittest.cc b/chrome/browser/content_settings/permission_queue_controller_unittest.cc
index d49dc2a..aae2004 100644
--- a/chrome/browser/content_settings/permission_queue_controller_unittest.cc
+++ b/chrome/browser/content_settings/permission_queue_controller_unittest.cc
@@ -7,10 +7,10 @@
 #include "base/synchronization/waitable_event.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/content_settings/core/common/content_settings_types.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/mock_render_process_host.h"
diff --git a/chrome/browser/devtools/device/usb/android_usb_device.cc b/chrome/browser/devtools/device/usb/android_usb_device.cc
index fbed997..1e0f3af 100644
--- a/chrome/browser/devtools/device/usb/android_usb_device.cc
+++ b/chrome/browser/devtools/device/usb/android_usb_device.cc
@@ -200,14 +200,8 @@
                        crypto::RSAPrivateKey* rsa_key,
                        const base::Closure& barrier,
                        scoped_refptr<UsbDevice> device,
-                       int interface_id,
-                       bool success) {
+                       int interface_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (!success) {
-    barrier.Run();
-    return;
-  }
-
   if (device->serial_number().empty()) {
     barrier.Run();
     return;
@@ -268,9 +262,7 @@
         continue;
       }
 
-      device->RequestUsbAccess(j, base::Bind(&OpenAndroidDevice, devices,
-                                             rsa_key, barrier, device, j));
-
+      OpenAndroidDevice(devices, rsa_key, barrier, device, j);
       has_android_interface = true;
       break;
     }
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index 18fc3c34..80a336b 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -635,8 +635,9 @@
 
 // Tests that BeforeUnload event gets called on devtools that are opened
 // on another devtools.
+// Disabled because of http://crbug.com/497857
 IN_PROC_BROWSER_TEST_F(DevToolsBeforeUnloadTest,
-                       TestDevToolsOnDevTools) {
+                       DISABLED_TestDevToolsOnDevTools) {
   ASSERT_TRUE(test_server()->Start());
   LoadTestPage(kDebuggerTestPage);
 
diff --git a/chrome/browser/devtools/devtools_target_impl.cc b/chrome/browser/devtools/devtools_target_impl.cc
index 5658553..9d5cac5 100644
--- a/chrome/browser/devtools/devtools_target_impl.cc
+++ b/chrome/browser/devtools/devtools_target_impl.cc
@@ -201,6 +201,12 @@
 // static
 scoped_ptr<DevToolsTargetImpl> DevToolsTargetImpl::CreateForTab(
     content::WebContents* web_contents) {
+  // TODO(dgozman): these checks should not be necessary. See
+  // http://crbug.com/489664.
+  if (!web_contents)
+    return nullptr;
+  if (!DevToolsAgentHost::GetOrCreateFor(web_contents))
+    return nullptr;
   return scoped_ptr<DevToolsTargetImpl>(
       new WebContentsTarget(web_contents, true));
 }
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index 3722001..bde9f9e 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -337,6 +337,9 @@
   switch (status) {
     case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
+#if defined(OS_CHROMEOS)
+    case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
+#endif
     case base::TERMINATION_STATUS_PROCESS_CRASHED:
       if (devtools_bindings_->agent_host_.get())
         devtools_bindings_->Detach();
diff --git a/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc b/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc
index c2782ee..7bdf935 100644
--- a/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc
+++ b/chrome/browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc
@@ -389,7 +389,7 @@
     std::string result;
     EXPECT_TRUE(content::ExecuteScriptAndExtractString(
         contents, kGetLoadIndicatorClassName , &result));
-    EXPECT_EQ("visible", result);
+    EXPECT_EQ("hidden", result);
 
     EXPECT_TRUE(content::ExecuteScriptAndExtractString(
         contents, kGetContent , &result));
diff --git a/chrome/browser/enhanced_bookmarks/android/enhanced_bookmarks_bridge.cc b/chrome/browser/enhanced_bookmarks/android/enhanced_bookmarks_bridge.cc
index 44e308a..62417927 100644
--- a/chrome/browser/enhanced_bookmarks/android/enhanced_bookmarks_bridge.cc
+++ b/chrome/browser/enhanced_bookmarks/android/enhanced_bookmarks_bridge.cc
@@ -23,6 +23,7 @@
 #include "components/bookmarks/common/android/bookmark_type.h"
 #include "components/enhanced_bookmarks/bookmark_server_cluster_service.h"
 #include "components/enhanced_bookmarks/enhanced_bookmark_model.h"
+#include "components/enhanced_bookmarks/enhanced_bookmark_utils.h"
 #include "components/enhanced_bookmarks/image_record.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "content/public/browser/browser_thread.h"
@@ -313,6 +314,10 @@
         bookmarks::prefs::kEditBookmarksEnabled);
 }
 
+static jint GetDefaultViewMode(JNIEnv* env, jclass jcaller) {
+  return enhanced_bookmarks::GetDefaultViewMode();
+}
+
 static jlong Init(JNIEnv* env, jobject obj, jobject j_profile) {
   return reinterpret_cast<jlong>(new EnhancedBookmarksBridge(
         env, obj, ProfileAndroid::FromProfileAndroid(j_profile)));
diff --git a/chrome/browser/extensions/active_script_controller.cc b/chrome/browser/extensions/active_script_controller.cc
index b32e2ed..f4ef4de 100644
--- a/chrome/browser/extensions/active_script_controller.cc
+++ b/chrome/browser/extensions/active_script_controller.cc
@@ -301,7 +301,9 @@
   }
 }
 
-bool ActiveScriptController::OnMessageReceived(const IPC::Message& message) {
+bool ActiveScriptController::OnMessageReceived(
+    const IPC::Message& message,
+    content::RenderFrameHost* render_frame_host) {
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(ActiveScriptController, message)
     IPC_MESSAGE_HANDLER(ExtensionHostMsg_RequestScriptInjectionPermission,
diff --git a/chrome/browser/extensions/active_script_controller.h b/chrome/browser/extensions/active_script_controller.h
index 981f60e..481ce4ec 100644
--- a/chrome/browser/extensions/active_script_controller.h
+++ b/chrome/browser/extensions/active_script_controller.h
@@ -119,7 +119,8 @@
   void LogUMA() const;
 
   // content::WebContentsObserver implementation.
-  bool OnMessageReceived(const IPC::Message& message) override;
+  bool OnMessageReceived(const IPC::Message& message,
+                         content::RenderFrameHost* render_frame_host) override;
   void DidNavigateMainFrame(
       const content::LoadCommittedDetails& details,
       const content::FrameNavigateParams& params) override;
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
index cf04003..878e4d50 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
+++ b/chrome/browser/extensions/api/autofill_private/autofill_private_api.cc
@@ -28,18 +28,6 @@
 static const char kSettingsOrigin[] = "Chrome settings";
 static const char kErrorDataUnavailable[] = "Autofill data unavailable.";
 
-// Converts the UTF-8 strings in |input| to UTF-16 strings and adds them to
-// |output|.
-void UTF8VectorToUTF16Vector(
-    const std::vector<std::string>& input,
-    std::vector<base::string16>* output) {
-  // Ensure output is clear.
-  output->clear();
-
-  for (const std::string& s : input)
-    output->push_back(base::UTF8ToUTF16(s));
-}
-
 // Fills |components| with the address UI components that should be used to
 // input an address for |country_code| when UI BCP 47 language code is
 // |ui_language_code|.
@@ -261,14 +249,18 @@
   }
 
   if (address->phone_numbers) {
-    UTF8VectorToUTF16Vector(*address->phone_numbers, &string16Container);
-    profile.SetRawMultiInfo(
-        autofill::PHONE_HOME_WHOLE_NUMBER, string16Container);
+    std::string phone;
+    if (!address->phone_numbers->empty())
+      phone = address->phone_numbers->at(0);
+    profile.SetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER,
+                       base::UTF8ToUTF16(phone));
   }
 
   if (address->email_addresses) {
-    UTF8VectorToUTF16Vector(*address->email_addresses, &string16Container);
-    profile.SetRawMultiInfo(autofill::EMAIL_ADDRESS, string16Container);
+    std::string email;
+    if (!address->email_addresses->empty())
+      email = address->email_addresses->at(0);
+    profile.SetRawInfo(autofill::EMAIL_ADDRESS, base::UTF8ToUTF16(email));
   }
 
   if (address->language_code)
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_util.cc b/chrome/browser/extensions/api/autofill_private/autofill_util.cc
index 391ca1f..6492a3a 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_util.cc
+++ b/chrome/browser/extensions/api/autofill_private/autofill_util.cc
@@ -24,18 +24,19 @@
 namespace {
 
 // Get the multi-valued element for |type| and return it as a |vector|.
+// TODO(khorimoto): remove this function since multi-valued types are
+// deprecated.
 scoped_ptr<std::vector<std::string>> GetValueList(
     const autofill::AutofillProfile& profile, autofill::ServerFieldType type) {
   scoped_ptr<std::vector<std::string>> list(new std::vector<std::string>);
 
   std::vector<base::string16> values;
   if (autofill::AutofillType(type).group() == autofill::NAME) {
-    profile.GetMultiInfo(
-        autofill::AutofillType(type),
-        g_browser_process->GetApplicationLocale(),
-        &values);
+    values.push_back(
+        profile.GetInfo(autofill::AutofillType(type),
+                        g_browser_process->GetApplicationLocale()));
   } else {
-    profile.GetRawMultiInfo(type, &values);
+    values.push_back(profile.GetRawInfo(type));
   }
 
   // |Get[Raw]MultiInfo()| always returns at least one, potentially empty, item.
diff --git a/chrome/browser/extensions/api/automation_internal/automation_action_adapter.h b/chrome/browser/extensions/api/automation_internal/automation_action_adapter.h
index 3fe5943..1bb98bca 100644
--- a/chrome/browser/extensions/api/automation_internal/automation_action_adapter.h
+++ b/chrome/browser/extensions/api/automation_internal/automation_action_adapter.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_ACTION_ADAPTER_H_
 #define CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_ACTION_ADAPTER_H_
 
+#include "ui/gfx/geometry/point.h"
+
 namespace extensions {
 
 // Adapts an object to receive actions from the Automation extension API.
@@ -23,6 +25,9 @@
   // Sets selection for a start and end index (usually only relevant on text
   // fields).
   virtual void SetSelection(int32 id, int32 start, int32 end) = 0;
+
+  // Shows the context menu resulting from a right click.
+  virtual void ShowContextMenu(int32 id) = 0;
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
index 6b6ec5e..784b11c 100644
--- a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
+++ b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
@@ -168,6 +168,10 @@
     rfh_->AccessibilitySetTextSelection(id, start, end);
   }
 
+  void ShowContextMenu(int32 id) override {
+    rfh_->AccessibilityShowContextMenu(id);
+  }
+
  private:
   content::RenderFrameHost* rfh_;
 
@@ -338,6 +342,10 @@
                            selection_params.end_index);
       break;
     }
+    case api::automation_internal::ACTION_TYPE_SHOWCONTEXTMENU: {
+      adapter->ShowContextMenu(automation_id);
+      break;
+    }
     default:
       NOTREACHED();
   }
diff --git a/chrome/browser/extensions/api/search_engines_private/search_engines_private_api.cc b/chrome/browser/extensions/api/search_engines_private/search_engines_private_api.cc
index 391468d..3e23b25 100644
--- a/chrome/browser/extensions/api/search_engines_private/search_engines_private_api.cc
+++ b/chrome/browser/extensions/api/search_engines_private/search_engines_private_api.cc
@@ -58,8 +58,8 @@
   for (size_t i = 0; i < urls.size(); i++) {
     search_engines_private::SearchEngine engine;
     engine.guid = urls[i]->sync_guid();
-    engine.name = base::UTF16ToASCII(urls[i]->short_name());
-    engine.keyword = base::UTF16ToASCII(urls[i]->keyword());
+    engine.name = base::UTF16ToUTF8(urls[i]->short_name());
+    engine.keyword = base::UTF16ToUTF8(urls[i]->keyword());
     engine.url = urls[i]->url();
     engine.type = urls[i]->show_in_default_list()
         ? search_engines_private::SearchEngineType::SEARCH_ENGINE_TYPE_DEFAULT
@@ -120,8 +120,8 @@
   EXTENSION_FUNCTION_VALIDATE(parameters.get());
 
   TemplateURLData data;
-  data.SetShortName(base::ASCIIToUTF16(parameters->name));
-  data.SetKeyword(base::ASCIIToUTF16(parameters->keyword));
+  data.SetShortName(base::UTF8ToUTF16(parameters->name));
+  data.SetKeyword(base::UTF8ToUTF16(parameters->keyword));
   data.SetURL(parameters->url);
   TemplateURL* turl = new TemplateURL(data);
 
@@ -155,8 +155,8 @@
       template_url_service->GetTemplateURLForGUID(parameters->guid);
 
   template_url_service->ResetTemplateURL(
-      turl, base::ASCIIToUTF16(parameters->name),
-      base::ASCIIToUTF16(parameters->keyword), parameters->url);
+      turl, base::UTF8ToUTF16(parameters->name),
+      base::UTF8ToUTF16(parameters->keyword), parameters->url);
 
   return RespondNow(NoArguments());
 }
@@ -241,7 +241,7 @@
     std::string error_message(l10n_util::GetStringUTF8(error));
     if (error == IDS_HOTWORD_GENERIC_ERROR_MESSAGE) {
       error_message = l10n_util::GetStringFUTF8(
-          error, base::ASCIIToUTF16(chrome::kHotwordLearnMoreURL));
+          error, base::UTF8ToUTF16(chrome::kHotwordLearnMoreURL));
     }
     state->error_msg.reset(new std::string(error_message));
   }
@@ -261,7 +261,7 @@
                      weak_ptr_factory_.GetWeakPtr(), base::Passed(&state),
                      l10n_util::GetStringFUTF16(
                          IDS_HOTWORD_AUDIO_HISTORY_ENABLED,
-                         base::ASCIIToUTF16(user_display_name))));
+                         base::UTF8ToUTF16(user_display_name))));
       return RespondLater();
     }
   }
@@ -278,7 +278,7 @@
     state->availability.push_back(
         search_engines_private::HotwordFeature::HOTWORD_FEATURE_AUDIO_HISTORY);
     state->audio_history_state.reset(new std::string(
-        base::UTF16ToASCII(audio_history_state)));
+        base::UTF16ToUTF8(audio_history_state)));
   }
   Respond(OneArgument(state->ToValue().release()));
 }
diff --git a/chrome/browser/extensions/api/search_engines_private/search_engines_private_event_router.cc b/chrome/browser/extensions/api/search_engines_private/search_engines_private_event_router.cc
index 66460ba..6c50b508 100644
--- a/chrome/browser/extensions/api/search_engines_private/search_engines_private_event_router.cc
+++ b/chrome/browser/extensions/api/search_engines_private/search_engines_private_event_router.cc
@@ -83,8 +83,8 @@
     search_engines_private::SearchEngine* engine =
         new search_engines_private::SearchEngine();
     engine->guid = url->sync_guid();
-    engine->name = base::UTF16ToASCII(url->short_name());
-    engine->keyword = base::UTF16ToASCII(url->keyword());
+    engine->name = base::UTF16ToUTF8(url->short_name());
+    engine->keyword = base::UTF16ToUTF8(url->keyword());
     engine->url = url->url();
     engine->type = url->show_in_default_list()
         ? search_engines_private::SearchEngineType::SEARCH_ENGINE_TYPE_DEFAULT
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index c22a846..11440853 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -2,23 +2,40 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/json/json_reader.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/settings_private/prefs_util.h"
+#include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
+#include "components/url_fixer/url_fixer.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h"
+#include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#endif
 
 namespace extensions {
 
 namespace settings_private = api::settings_private;
 
-namespace prefs_util {
+PrefsUtil::PrefsUtil(Profile* profile) : profile_(profile) {
+}
 
-const TypedPrefMap& GetWhitelistedKeys() {
-  static TypedPrefMap* s_whitelist = nullptr;
+PrefsUtil::~PrefsUtil() {
+}
+
+#if defined(OS_CHROMEOS)
+using CrosSettings = chromeos::CrosSettings;
+#endif
+
+const PrefsUtil::TypedPrefMap& PrefsUtil::GetWhitelistedKeys() {
+  static PrefsUtil::TypedPrefMap* s_whitelist = nullptr;
   if (s_whitelist)
     return *s_whitelist;
-  s_whitelist = new TypedPrefMap();
+  s_whitelist = new PrefsUtil::TypedPrefMap();
   (*s_whitelist)["browser.show_home_button"] =
       settings_private::PrefType::PREF_TYPE_BOOLEAN;
   (*s_whitelist)["bookmark_bar.show_on_all_tabs"] =
@@ -30,6 +47,14 @@
   (*s_whitelist)["homepage"] = settings_private::PrefType::PREF_TYPE_URL;
 
 #if defined(OS_CHROMEOS)
+  (*s_whitelist)["cros.accounts.allowBWSI"] =
+      settings_private::PrefType::PREF_TYPE_BOOLEAN;
+  (*s_whitelist)["cros.accounts.supervisedUsersEnabled"] =
+      settings_private::PrefType::PREF_TYPE_BOOLEAN;
+  (*s_whitelist)["cros.accounts.showUserNamesOnSignIn"] =
+      settings_private::PrefType::PREF_TYPE_BOOLEAN;
+  (*s_whitelist)["cros.accounts.allowGuest"] =
+      settings_private::PrefType::PREF_TYPE_BOOLEAN;
   (*s_whitelist)["settings.accessibility"] =
       settings_private::PrefType::PREF_TYPE_BOOLEAN;
   (*s_whitelist)["settings.a11y.autoclick"] =
@@ -57,38 +82,55 @@
   return *s_whitelist;
 }
 
-scoped_ptr<api::settings_private::PrefObject> GetPref(Profile* profile,
-                                                      const std::string& name) {
+api::settings_private::PrefType PrefsUtil::GetType(const std::string& name,
+                                                   base::Value::Type type) {
+  switch (type) {
+    case base::Value::Type::TYPE_BOOLEAN:
+      return api::settings_private::PrefType::PREF_TYPE_BOOLEAN;
+    case base::Value::Type::TYPE_INTEGER:
+    case base::Value::Type::TYPE_DOUBLE:
+      return api::settings_private::PrefType::PREF_TYPE_NUMBER;
+    case base::Value::Type::TYPE_STRING:
+      return IsPrefTypeURL(name)
+                 ? api::settings_private::PrefType::PREF_TYPE_URL
+                 : api::settings_private::PrefType::PREF_TYPE_STRING;
+    case base::Value::Type::TYPE_LIST:
+      return api::settings_private::PrefType::PREF_TYPE_LIST;
+    default:
+      return api::settings_private::PrefType::PREF_TYPE_NONE;
+  }
+}
+
+scoped_ptr<api::settings_private::PrefObject> PrefsUtil::GetCrosSettingsPref(
+    const std::string& name) {
   scoped_ptr<api::settings_private::PrefObject> pref_object(
       new api::settings_private::PrefObject());
 
-  PrefService* pref_service = FindServiceForPref(profile, name);
+#if defined(OS_CHROMEOS)
+  const base::Value* value = CrosSettings::Get()->GetPref(name);
+  pref_object->key = name;
+  pref_object->type = GetType(name, value->GetType());
+  pref_object->value.reset(value->DeepCopy());
+#endif
+
+  return pref_object.Pass();
+}
+
+scoped_ptr<api::settings_private::PrefObject> PrefsUtil::GetPref(
+    const std::string& name) {
+  scoped_ptr<api::settings_private::PrefObject> pref_object(
+      new api::settings_private::PrefObject());
+
+  if (IsCrosSetting(name))
+    return GetCrosSettingsPref(name);
+
+  PrefService* pref_service = FindServiceForPref(name);
   const PrefService::Preference* pref = pref_service->FindPreference(name);
   if (!pref)
     return pref_object.Pass();
 
   pref_object->key = pref->name();
-  switch (pref->GetType()) {
-    case base::Value::Type::TYPE_BOOLEAN:
-      pref_object->type = api::settings_private::PrefType::PREF_TYPE_BOOLEAN;
-      break;
-    case base::Value::Type::TYPE_INTEGER:
-    case base::Value::Type::TYPE_DOUBLE:
-      pref_object->type = api::settings_private::PrefType::PREF_TYPE_NUMBER;
-      break;
-    case base::Value::Type::TYPE_STRING:
-      pref_object->type =
-          IsPrefTypeURL(name)
-              ? api::settings_private::PrefType::PREF_TYPE_URL
-              : api::settings_private::PrefType::PREF_TYPE_STRING;
-      break;
-    case base::Value::Type::TYPE_LIST:
-      pref_object->type = api::settings_private::PrefType::PREF_TYPE_LIST;
-      break;
-    default:
-      break;
-  }
-
+  pref_object->type = GetType(name, pref->GetType());
   pref_object->value.reset(pref->GetValue()->DeepCopy());
 
   if (pref->IsManaged()) {
@@ -104,7 +146,7 @@
                                     POLICY_ENFORCEMENT_RECOMMENDED
                               : api::settings_private::PolicyEnforcement::
                                     POLICY_ENFORCEMENT_ENFORCED;
-  } else if (!IsPrefUserModifiable(profile, name)) {
+  } else if (!IsPrefUserModifiable(name)) {
     pref_object->policy_source =
         api::settings_private::PolicySource::POLICY_SOURCE_USER;
     pref_object->policy_enforcement =
@@ -114,7 +156,120 @@
   return pref_object.Pass();
 }
 
-bool IsPrefTypeURL(const std::string& pref_name) {
+bool PrefsUtil::SetPref(const std::string& pref_name,
+                        const base::Value* value) {
+  if (IsCrosSetting(pref_name))
+    return SetCrosSettingsPref(pref_name, value);
+
+  PrefService* pref_service = FindServiceForPref(pref_name);
+
+  if (!IsPrefUserModifiable(pref_name))
+    return false;
+
+  const PrefService::Preference* pref =
+      pref_service->FindPreference(pref_name.c_str());
+  if (!pref)
+    return false;
+
+  DCHECK_EQ(pref->GetType(), value->GetType());
+
+  scoped_ptr<base::Value> temp_value;
+
+  switch (pref->GetType()) {
+    case base::Value::TYPE_INTEGER: {
+      // In JS all numbers are doubles.
+      double double_value;
+      if (!value->GetAsDouble(&double_value))
+        return false;
+
+      int int_value = static_cast<int>(double_value);
+      temp_value.reset(new base::FundamentalValue(int_value));
+      value = temp_value.get();
+      break;
+    }
+    case base::Value::TYPE_STRING: {
+      std::string original;
+      if (!value->GetAsString(&original))
+        return false;
+
+      if (IsPrefTypeURL(pref_name)) {
+        GURL fixed = url_fixer::FixupURL(original, std::string());
+        temp_value.reset(new base::StringValue(fixed.spec()));
+        value = temp_value.get();
+      }
+      break;
+    }
+    case base::Value::TYPE_LIST: {
+      // In case we have a List pref we got a JSON string.
+      std::string json_string;
+      if (!value->GetAsString(&json_string))
+        return false;
+
+      temp_value.reset(base::JSONReader::DeprecatedRead(json_string));
+      value = temp_value.get();
+      if (!value->IsType(base::Value::TYPE_LIST))
+        return false;
+
+      break;
+    }
+    case base::Value::TYPE_BOOLEAN:
+    case base::Value::TYPE_DOUBLE:
+      break;
+    default:
+      return false;
+  }
+
+  // TODO(orenb): Process setting metrics here and in the CrOS setting method
+  // too (like "ProcessUserMetric" in CoreOptionsHandler).
+  pref_service->Set(pref_name.c_str(), *value);
+  return true;
+}
+
+bool PrefsUtil::SetCrosSettingsPref(const std::string& pref_name,
+                                    const base::Value* value) {
+#if defined(OS_CHROMEOS)
+  chromeos::OwnerSettingsServiceChromeOS* service =
+      chromeos::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
+          profile_);
+
+  // Returns false if not the owner, for settings requiring owner.
+  if (service && service->HandlesSetting(pref_name))
+    return service->Set(pref_name, *value);
+
+  chromeos::CrosSettings::Get()->Set(pref_name, *value);
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool PrefsUtil::AppendToListCrosSetting(const std::string& setting,
+                                        const base::Value& value) {
+#if defined(OS_CHROMEOS)
+  chromeos::OwnerSettingsServiceChromeOS* service =
+      chromeos::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
+          profile_);
+  DCHECK(service);
+  return service->AppendToList(setting, value);
+#else
+  return false;
+#endif
+}
+
+bool PrefsUtil::RemoveFromListCrosSetting(const std::string& setting,
+                                          const base::Value& value) {
+#if defined(OS_CHROMEOS)
+  chromeos::OwnerSettingsServiceChromeOS* service =
+      chromeos::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
+          profile_);
+  DCHECK(service);
+  return service->RemoveFromList(setting, value);
+#else
+  return false;
+#endif
+}
+
+bool PrefsUtil::IsPrefTypeURL(const std::string& pref_name) {
   settings_private::PrefType pref_type =
       settings_private::PrefType::PREF_TYPE_NONE;
 
@@ -126,24 +281,23 @@
   return pref_type == settings_private::PrefType::PREF_TYPE_URL;
 }
 
-bool IsPrefUserModifiable(Profile* profile, const std::string& pref_name) {
+bool PrefsUtil::IsPrefUserModifiable(const std::string& pref_name) {
   if (pref_name != prefs::kBrowserGuestModeEnabled &&
       pref_name != prefs::kBrowserAddPersonEnabled) {
     return true;
   }
 
-  PrefService* pref_service = profile->GetPrefs();
+  PrefService* pref_service = profile_->GetPrefs();
   const PrefService::Preference* pref =
       pref_service->FindPreference(pref_name.c_str());
-  if (!pref || !pref->IsUserModifiable() || profile->IsSupervised())
+  if (!pref || !pref->IsUserModifiable() || profile_->IsSupervised())
     return false;
 
   return true;
 }
 
-PrefService* FindServiceForPref(Profile* profile,
-                                const std::string& pref_name) {
-  PrefService* user_prefs = profile->GetPrefs();
+PrefService* PrefsUtil::FindServiceForPref(const std::string& pref_name) {
+  PrefService* user_prefs = profile_->GetPrefs();
 
   // Proxy is a peculiar case: on ChromeOS, settings exist in both user
   // prefs and local state, but chrome://settings should affect only user prefs.
@@ -170,6 +324,12 @@
   return user_prefs;
 }
 
-}  // namespace prefs_util
+bool PrefsUtil::IsCrosSetting(const std::string& pref_name) {
+#if defined(OS_CHROMEOS)
+  return CrosSettings::Get()->IsCrosSettings(pref_name);
+#else
+  return false;
+#endif
+}
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.h b/chrome/browser/extensions/api/settings_private/prefs_util.h
index fb4bef5..73224b04 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.h
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.h
@@ -17,31 +17,62 @@
 
 namespace extensions {
 
-namespace prefs_util {
+class PrefsUtil {
 
-using TypedPrefMap = std::map<std::string, api::settings_private::PrefType>;
+ public:
+  using TypedPrefMap = std::map<std::string, api::settings_private::PrefType>;
 
-// Gets the list of whitelisted pref keys -- that is, those which correspond to
-// prefs that clients of the settingsPrivate API may retrieve and manipulate.
-const TypedPrefMap& GetWhitelistedKeys();
+  explicit PrefsUtil(Profile* profile);
+  virtual ~PrefsUtil();
 
-// Gets the value of the pref with the given |name|. Returns a pointer to an
-// empty PrefObject if no pref is found for |name|.
-scoped_ptr<api::settings_private::PrefObject> GetPref(Profile* profile,
-                                                      const std::string& name);
+  // Gets the list of whitelisted pref keys -- that is, those which correspond
+  // to prefs that clients of the settingsPrivate API may retrieve and
+  // manipulate.
+  const TypedPrefMap& GetWhitelistedKeys();
 
-// Returns whether |pref_name| corresponds to a pref whose type is URL.
-bool IsPrefTypeURL(const std::string& pref_name);
+  // Gets the value of the pref with the given |name|. Returns a pointer to an
+  // empty PrefObject if no pref is found for |name|.
+  virtual scoped_ptr<api::settings_private::PrefObject> GetPref(
+      const std::string& name);
 
-// Returns whether |pref_name| corresponds to a pref that is user modifiable
-// (i.e., not made restricted by a user or device policy).
-bool IsPrefUserModifiable(Profile* profile, const std::string& pref_name);
+  // Sets the pref with the given name and value in the proper PrefService.
+  virtual bool SetPref(const std::string& name, const base::Value* value);
 
-// Returns a pointer to the appropriate PrefService instance for the given
-// |pref_name|.
-PrefService* FindServiceForPref(Profile* profile, const std::string& pref_name);
+  // Appends the given |value| to the list setting specified by the path in
+  // |setting|.
+  virtual bool AppendToListCrosSetting(const std::string& setting,
+                                       const base::Value& value);
 
-}  // namespace prefs_util
+  // Removes the given |value| from the list setting specified by the path in
+  // |setting|.
+  virtual bool RemoveFromListCrosSetting(const std::string& setting,
+                                         const base::Value& value);
+
+  // Returns a pointer to the appropriate PrefService instance for the given
+  // |pref_name|.
+  virtual PrefService* FindServiceForPref(const std::string& pref_name);
+
+  // Returns whether or not the given pref is a CrOS-specific setting.
+  virtual bool IsCrosSetting(const std::string& pref_name);
+
+ protected:
+  // Returns whether |pref_name| corresponds to a pref whose type is URL.
+  bool IsPrefTypeURL(const std::string& pref_name);
+
+  // Returns whether |pref_name| corresponds to a pref that is user modifiable
+  // (i.e., not made restricted by a user or device policy).
+  bool IsPrefUserModifiable(const std::string& pref_name);
+
+  api::settings_private::PrefType GetType(const std::string& name,
+                                          base::Value::Type type);
+
+  scoped_ptr<api::settings_private::PrefObject> GetCrosSettingsPref(
+      const std::string& name);
+
+  bool SetCrosSettingsPref(const std::string& name, const base::Value* value);
+
+  Profile* profile_;  // weak
+};
 
 }  // namespace extensions
 
diff --git a/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc b/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc
index 8030ed78..d2e48cf 100644
--- a/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc
+++ b/chrome/browser/extensions/api/settings_private/settings_private_apitest.cc
@@ -13,76 +13,24 @@
 #include "content/public/test/test_utils.h"
 #include "extensions/common/switches.h"
 
+#if defined(OS_CHROMEOS)
+#include "chromeos/chromeos_switches.h"
+#endif
+
 namespace extensions {
 
 namespace {
 
-const char kTestPrefName[] = "download.default_directory";
-const char kTestPrefValue[] = "/Downloads";
-
-class TestDelegate : public SettingsPrivateDelegate {
- public:
-  explicit TestDelegate(Profile* profile) : SettingsPrivateDelegate(profile) {}
-
-  bool SetPref(const std::string& name, const base::Value* value) override {
-    // Write to the actual pref service, so that the SettingsPrivateEventRouter
-    // dispatches an onPrefsChanged event.
-    PrefService* pref_service = profile_->GetPrefs();
-    pref_service->Set(name.c_str(), *value);
-    return true;
-  }
-
-  scoped_ptr<base::Value> GetPref(const std::string& name) override {
-    if (name.compare(kTestPrefName) != 0)
-      return base::Value::CreateNullValue();
-
-    return CreateTestPrefObject()->ToValue();
-  }
-
-  scoped_ptr<base::Value> GetAllPrefs() override {
-    base::ListValue* list_value = new base::ListValue();
-    list_value->Append(CreateTestPrefObject()->ToValue().release());
-    return make_scoped_ptr(list_value);
-  }
-
-  ~TestDelegate() override {}
-
- private:
-  scoped_ptr<api::settings_private::PrefObject> CreateTestPrefObject() {
-    scoped_ptr<api::settings_private::PrefObject> pref_object(
-        new api::settings_private::PrefObject());
-    pref_object->key = std::string(kTestPrefName);
-    pref_object->type = api::settings_private::PrefType::PREF_TYPE_STRING;
-    pref_object->value.reset(new base::StringValue(kTestPrefValue));
-    return pref_object.Pass();
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(TestDelegate);
-};
-
 class SettingsPrivateApiTest : public ExtensionApiTest {
  public:
   SettingsPrivateApiTest() {}
   ~SettingsPrivateApiTest() override {}
 
-  static KeyedService* GetSettingsPrivateDelegate(
-      content::BrowserContext* profile) {
-    CHECK(s_test_delegate_);
-    return s_test_delegate_;
-  }
-
   void SetUpCommandLine(base::CommandLine* command_line) override {
     ExtensionApiTest::SetUpCommandLine(command_line);
-  }
-
-  void SetUpOnMainThread() override {
-    ExtensionApiTest::SetUpOnMainThread();
-    if (!s_test_delegate_)
-      s_test_delegate_ = new TestDelegate(profile());
-
-    SettingsPrivateDelegateFactory::GetInstance()->SetTestingFactory(
-        profile(), &SettingsPrivateApiTest::GetSettingsPrivateDelegate);
-    content::RunAllPendingInMessageLoop();
+#if defined(OS_CHROMEOS)
+    command_line->AppendSwitch(chromeos::switches::kStubCrosSettings);
+#endif
   }
 
  protected:
@@ -92,16 +40,10 @@
                                kFlagLoadAsComponent);
   }
 
-  // Static pointer to the TestDelegate so that it can be accessed in
-  // GetSettingsPrivateDelegate() passed to SetTestingFactory().
-  static TestDelegate* s_test_delegate_;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(SettingsPrivateApiTest);
 };
 
-// static
-TestDelegate* SettingsPrivateApiTest::s_test_delegate_ = NULL;
 
 }  // namespace
 
@@ -121,4 +63,18 @@
   EXPECT_TRUE(RunSettingsSubtest("onPrefsChanged")) << message_;
 }
 
+#if defined(OS_CHROMEOS)
+IN_PROC_BROWSER_TEST_F(SettingsPrivateApiTest, GetPref_CrOSSetting) {
+  EXPECT_TRUE(RunSettingsSubtest("getPref_CrOSSetting")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(SettingsPrivateApiTest, SetPref_CrOSSetting) {
+  EXPECT_TRUE(RunSettingsSubtest("setPref_CrOSSetting")) << message_;
+}
+
+IN_PROC_BROWSER_TEST_F(SettingsPrivateApiTest, OnPrefsChanged_CrOSSetting) {
+  EXPECT_TRUE(RunSettingsSubtest("onPrefsChanged_CrOSSetting")) << message_;
+}
+#endif
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/settings_private/settings_private_delegate.cc b/chrome/browser/extensions/api/settings_private/settings_private_delegate.cc
index c9e5da1..9de6e54 100644
--- a/chrome/browser/extensions/api/settings_private/settings_private_delegate.cc
+++ b/chrome/browser/extensions/api/settings_private/settings_private_delegate.cc
@@ -4,14 +4,13 @@
 
 #include "chrome/browser/extensions/api/settings_private/settings_private_delegate.h"
 
-#include "base/json/json_reader.h"
 #include "base/prefs/pref_service.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/extensions/api/settings_private/prefs_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
-#include "components/url_fixer/url_fixer.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
 #include "url/gurl.h"
@@ -22,6 +21,7 @@
 
 SettingsPrivateDelegate::SettingsPrivateDelegate(Profile* profile)
     : profile_(profile) {
+  prefs_util_.reset(new PrefsUtil(profile));
 }
 
 SettingsPrivateDelegate::~SettingsPrivateDelegate() {
@@ -29,13 +29,13 @@
 
 scoped_ptr<base::Value> SettingsPrivateDelegate::GetPref(
     const std::string& name) {
-  return prefs_util::GetPref(profile_, name)->ToValue();
+  return prefs_util_->GetPref(name)->ToValue();
 }
 
 scoped_ptr<base::Value> SettingsPrivateDelegate::GetAllPrefs() {
   scoped_ptr<base::ListValue> prefs(new base::ListValue());
 
-  const TypedPrefMap& keys = prefs_util::GetWhitelistedKeys();
+  const TypedPrefMap& keys = prefs_util_->GetWhitelistedKeys();
   for (const auto& it : keys) {
     prefs->Append(GetPref(it.first).release());
   }
@@ -45,69 +45,7 @@
 
 bool SettingsPrivateDelegate::SetPref(const std::string& pref_name,
                                       const base::Value* value) {
-  PrefService* pref_service =
-      prefs_util::FindServiceForPref(profile_, pref_name);
-
-  if (!prefs_util::IsPrefUserModifiable(profile_, pref_name))
-    return false;
-
-  const PrefService::Preference* pref =
-      pref_service->FindPreference(pref_name.c_str());
-  if (!pref)
-    return false;
-
-  DCHECK_EQ(pref->GetType(), value->GetType());
-
-  scoped_ptr<base::Value> temp_value;
-
-  switch (pref->GetType()) {
-    case base::Value::TYPE_INTEGER: {
-      // In JS all numbers are doubles.
-      double double_value;
-      if (!value->GetAsDouble(&double_value))
-        return false;
-
-      int int_value = static_cast<int>(double_value);
-      temp_value.reset(new base::FundamentalValue(int_value));
-      value = temp_value.get();
-      break;
-    }
-    case base::Value::TYPE_STRING: {
-      std::string original;
-      if (!value->GetAsString(&original))
-        return false;
-
-      if (prefs_util::IsPrefTypeURL(pref_name)) {
-        GURL fixed = url_fixer::FixupURL(original, std::string());
-        temp_value.reset(new base::StringValue(fixed.spec()));
-        value = temp_value.get();
-      }
-      break;
-    }
-    case base::Value::TYPE_LIST: {
-      // In case we have a List pref we got a JSON string.
-      std::string json_string;
-      if (!value->GetAsString(&json_string))
-        return false;
-
-      temp_value.reset(base::JSONReader::DeprecatedRead(json_string));
-      value = temp_value.get();
-      if (!value->IsType(base::Value::TYPE_LIST))
-        return false;
-
-      break;
-    }
-    case base::Value::TYPE_BOOLEAN:
-    case base::Value::TYPE_DOUBLE:
-      break;
-    default:
-      return false;
-  }
-
-  // TODO(orenb): Process setting metrics here (like "ProcessUserMetric" in
-  // CoreOptionsHandler).
-  pref_service->Set(pref_name.c_str(), *value);
-  return true;
+  return prefs_util_->SetPref(pref_name, value);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/settings_private/settings_private_delegate.h b/chrome/browser/extensions/api/settings_private/settings_private_delegate.h
index 96405f3..b2a1c90 100644
--- a/chrome/browser/extensions/api/settings_private/settings_private_delegate.h
+++ b/chrome/browser/extensions/api/settings_private/settings_private_delegate.h
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
+#include "chrome/browser/extensions/api/settings_private/prefs_util.h"
 #include "chrome/common/extensions/api/settings_private.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "extensions/browser/extension_function.h"
@@ -44,6 +45,7 @@
 
  protected:
   Profile* profile_;  // weak; not owned by us
+  scoped_ptr<PrefsUtil> prefs_util_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SettingsPrivateDelegate);
diff --git a/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc b/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc
index ff2eb5cb0..96ed2349 100644
--- a/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc
+++ b/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc
@@ -10,7 +10,6 @@
 #include "base/bind_helpers.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/api/settings_private/prefs_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/api/settings_private.h"
 #include "content/public/browser/browser_context.h"
@@ -32,6 +31,7 @@
   }
 
   Profile* profile = Profile::FromBrowserContext(context_);
+  prefs_util_.reset(new PrefsUtil(profile));
   user_prefs_registrar_.Init(profile->GetPrefs());
   local_state_registrar_.Init(g_browser_process->local_state());
 }
@@ -49,9 +49,11 @@
     event_router->UnregisterObserver(this);
 
   if (listening_) {
-    const prefs_util::TypedPrefMap& keys = prefs_util::GetWhitelistedKeys();
+    cros_settings_subscription_map_.clear();
+    const PrefsUtil::TypedPrefMap& keys = prefs_util_->GetWhitelistedKeys();
     for (const auto& it : keys) {
-      FindRegistrarForPref(it.first)->Remove(it.first);
+      if (!prefs_util_->IsCrosSetting(it.first))
+        FindRegistrarForPref(it.first)->Remove(it.first);
     }
   }
   listening_ = false;
@@ -73,8 +75,7 @@
 PrefChangeRegistrar* SettingsPrivateEventRouter::FindRegistrarForPref(
     const std::string& pref_name) {
   Profile* profile = Profile::FromBrowserContext(context_);
-  if (prefs_util::FindServiceForPref(profile, pref_name) ==
-      profile->GetPrefs()) {
+  if (prefs_util_->FindServiceForPref(pref_name) == profile->GetPrefs()) {
     return &user_prefs_registrar_;
   }
   return &local_state_registrar_;
@@ -86,24 +87,41 @@
       api::settings_private::OnPrefsChanged::kEventName);
 
   if (should_listen && !listening_) {
-    const prefs_util::TypedPrefMap& keys = prefs_util::GetWhitelistedKeys();
+    const PrefsUtil::TypedPrefMap& keys = prefs_util_->GetWhitelistedKeys();
     for (const auto& it : keys) {
-      FindRegistrarForPref(it.first)->Add(
-          it.first,
-          base::Bind(&SettingsPrivateEventRouter::OnPreferenceChanged,
-                     base::Unretained(this), user_prefs_registrar_.prefs()));
+      std::string pref_name = it.first;
+      if (prefs_util_->IsCrosSetting(pref_name)) {
+#if defined(OS_CHROMEOS)
+        scoped_ptr<chromeos::CrosSettings::ObserverSubscription> observer =
+            chromeos::CrosSettings::Get()->AddSettingsObserver(
+                pref_name.c_str(),
+                base::Bind(&SettingsPrivateEventRouter::OnPreferenceChanged,
+                           base::Unretained(this), pref_name));
+        linked_ptr<chromeos::CrosSettings::ObserverSubscription> subscription(
+            observer.release());
+        cros_settings_subscription_map_.insert(
+            make_pair(pref_name, subscription));
+#endif
+      } else {
+        FindRegistrarForPref(it.first)
+            ->Add(pref_name,
+                  base::Bind(&SettingsPrivateEventRouter::OnPreferenceChanged,
+                             base::Unretained(this)));
+      }
     }
   } else if (!should_listen && listening_) {
-    const prefs_util::TypedPrefMap& keys = prefs_util::GetWhitelistedKeys();
+    const PrefsUtil::TypedPrefMap& keys = prefs_util_->GetWhitelistedKeys();
     for (const auto& it : keys) {
-      FindRegistrarForPref(it.first)->Remove(it.first);
+      if (prefs_util_->IsCrosSetting(it.first))
+        cros_settings_subscription_map_.erase(it.first);
+      else
+        FindRegistrarForPref(it.first)->Remove(it.first);
     }
   }
   listening_ = should_listen;
 }
 
 void SettingsPrivateEventRouter::OnPreferenceChanged(
-    PrefService* service,
     const std::string& pref_name) {
   EventRouter* event_router = EventRouter::Get(context_);
   if (!event_router->HasEventListener(
@@ -111,9 +129,8 @@
     return;
   }
 
-  Profile* profile = Profile::FromBrowserContext(context_);
   api::settings_private::PrefObject* pref_object =
-      prefs_util::GetPref(profile, pref_name).release();
+      prefs_util_->GetPref(pref_name).release();
 
   std::vector<linked_ptr<api::settings_private::PrefObject>> prefs;
   prefs.push_back(linked_ptr<api::settings_private::PrefObject>(pref_object));
diff --git a/chrome/browser/extensions/api/settings_private/settings_private_event_router.h b/chrome/browser/extensions/api/settings_private/settings_private_event_router.h
index db8ea9c..5b07a600 100644
--- a/chrome/browser/extensions/api/settings_private/settings_private_event_router.h
+++ b/chrome/browser/extensions/api/settings_private/settings_private_event_router.h
@@ -6,6 +6,8 @@
 #define CHROME_BROWSER_EXTENSIONS_API_SETTINGS_PRIVATE_SETTINGS_PRIVATE_EVENT_ROUTER_H_
 
 #include "base/prefs/pref_change_registrar.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/extensions/api/settings_private/prefs_util.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "extensions/browser/event_router.h"
 
@@ -28,7 +30,6 @@
   ~SettingsPrivateEventRouter() override;
 
  protected:
-  SettingsPrivateEventRouter() {}
   explicit SettingsPrivateEventRouter(content::BrowserContext* context);
 
   // KeyedService overrides:
@@ -51,13 +52,20 @@
   // Otherwise, we want to unregister and not be listening for pref changes.
   void StartOrStopListeningForPrefsChanges();
 
-  void OnPreferenceChanged(PrefService* service, const std::string& pref_name);
+  void OnPreferenceChanged(const std::string& pref_name);
 
   PrefChangeRegistrar* FindRegistrarForPref(const std::string& pref_name);
 
+  typedef std::map<std::string,
+                   linked_ptr<chromeos::CrosSettings::ObserverSubscription>>
+      SubscriptionMap;
+  SubscriptionMap cros_settings_subscription_map_;
+
   content::BrowserContext* context_;
   bool listening_;
 
+  scoped_ptr<PrefsUtil> prefs_util_;
+
   DISALLOW_COPY_AND_ASSIGN(SettingsPrivateEventRouter);
 };
 
diff --git a/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc b/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc
index ed26073..c58fa82 100644
--- a/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc
+++ b/chrome/browser/extensions/api/system_indicator/system_indicator_apitest.cc
@@ -44,7 +44,7 @@
   }
 }
 
-IN_PROC_BROWSER_TEST_F(SystemIndicatorApiTest, SystemIndicator) {
+IN_PROC_BROWSER_TEST_F(SystemIndicatorApiTest, FLAKY_SystemIndicator) {
   // Only run this test on supported platforms.  SystemIndicatorManagerFactory
   // returns NULL on unsupported platforms.
   extensions::SystemIndicatorManager* manager =
diff --git a/chrome/browser/extensions/api/web_navigation/frame_navigation_state_unittest.cc b/chrome/browser/extensions/api/web_navigation/frame_navigation_state_unittest.cc
index 226018b..649547f 100644
--- a/chrome/browser/extensions/api/web_navigation/frame_navigation_state_unittest.cc
+++ b/chrome/browser/extensions/api/web_navigation/frame_navigation_state_unittest.cc
@@ -12,6 +12,14 @@
 namespace extensions {
 
 class FrameNavigationStateTest : public ChromeRenderViewHostTestHarness {
+ public:
+  void SetUp() override {
+    ChromeRenderViewHostTestHarness::SetUp();
+
+    content::RenderFrameHostTester::For(main_rfh())
+        ->InitializeRenderFrameIfNeeded();
+  }
+
  protected:
   FrameNavigationStateTest() {}
   ~FrameNavigationStateTest() override {}
diff --git a/chrome/browser/extensions/bookmark_app_helper.cc b/chrome/browser/extensions/bookmark_app_helper.cc
index 93afdf6..c15e0de0 100644
--- a/chrome/browser/extensions/bookmark_app_helper.cc
+++ b/chrome/browser/extensions/bookmark_app_helper.cc
@@ -491,6 +491,16 @@
   }
 }
 
+void BookmarkAppHelper::CreateFromAppBanner(
+    const CreateBookmarkAppCallback& callback,
+    const content::Manifest& manifest) {
+  DCHECK(!manifest.short_name.is_null() || !manifest.name.is_null());
+  DCHECK(manifest.start_url.is_valid());
+
+  callback_ = callback;
+  OnDidGetManifest(manifest);
+}
+
 void BookmarkAppHelper::OnDidGetManifest(const content::Manifest& manifest) {
   if (contents_->IsBeingDestroyed())
     return;
diff --git a/chrome/browser/extensions/bookmark_app_helper.h b/chrome/browser/extensions/bookmark_app_helper.h
index cb6a16aa..f4916ee 100644
--- a/chrome/browser/extensions/bookmark_app_helper.h
+++ b/chrome/browser/extensions/bookmark_app_helper.h
@@ -98,6 +98,10 @@
   // Begins the asynchronous bookmark app creation.
   void Create(const CreateBookmarkAppCallback& callback);
 
+  // Begins the asynchronous bookmark app creation from an app banner.
+  void CreateFromAppBanner(const CreateBookmarkAppCallback& callback,
+                           const content::Manifest& manifest);
+
  private:
   friend class TestBookmarkAppHelper;
 
diff --git a/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc b/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc
index 2c2c3f2d..1e0e87a 100644
--- a/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc
+++ b/chrome/browser/extensions/component_extensions_whitelist/whitelist.cc
@@ -32,6 +32,7 @@
     extension_misc::kPdfExtensionId,
 #if defined(OS_CHROMEOS)
     extension_misc::kChromeVoxExtensionId,
+    extension_misc::kSpeechSynthesisExtensionId,
     extension_misc::kZIPUnpackerExtensionId,
 #endif
   };
@@ -107,8 +108,6 @@
     IDR_MOBILE_MANIFEST,
     IDR_NETWORK_CONFIGURATION_MANIFEST,
     IDR_QUICKOFFICE_MANIFEST,
-    IDR_SPEECH_SYNTHESIS_GUEST_MANIFEST,
-    IDR_SPEECH_SYNTHESIS_MANIFEST,
     IDR_VIDEO_PLAYER_MANIFEST,
     IDR_WALLPAPERMANAGER_MANIFEST,
 #endif
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 9f1779a..1d14a83 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -18,17 +18,21 @@
 #include "chrome/browser/extensions/component_extensions_whitelist/whitelist.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/pdf/pdf_extension_util.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/hotword_service.h"
 #include "chrome/browser/search/hotword_service_factory.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/crx_file/id_util.h"
-#include "content/public/browser/browser_context.h"
+#include "components/signin/core/browser/signin_manager.h"
+#include "components/signin/core/browser/signin_manager_base.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/plugin_service.h"
+#include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_l10n_util.h"
 #include "extensions/common/file_util.h"
@@ -87,14 +91,20 @@
 #if defined(OS_CHROMEOS)
 scoped_ptr<base::DictionaryValue>
 LoadManifestOnFileThread(
-    const base::FilePath& chromevox_path, const char* manifest_filename) {
+    const base::FilePath& root_directory,
+    const base::FilePath::CharType* manifest_filename) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
   std::string error;
   scoped_ptr<base::DictionaryValue> manifest(
-      file_util::LoadManifest(chromevox_path, manifest_filename, &error));
-  CHECK(manifest) << error;
+      file_util::LoadManifest(root_directory, manifest_filename, &error));
+  if (!manifest) {
+    LOG(ERROR) << "Can't load "
+               << root_directory.Append(manifest_filename).AsUTF8Unsafe()
+               << ": " << error;
+    return nullptr;
+  }
   bool localized = extension_l10n_util::LocalizeExtension(
-      chromevox_path, manifest.get(), &error);
+      root_directory, manifest.get(), &error);
   CHECK(localized) << error;
   return manifest.Pass();
 }
@@ -123,10 +133,10 @@
 ComponentLoader::ComponentLoader(ExtensionServiceInterface* extension_service,
                                  PrefService* profile_prefs,
                                  PrefService* local_state,
-                                 content::BrowserContext* browser_context)
+                                 Profile* profile)
     : profile_prefs_(profile_prefs),
       local_state_(local_state),
-      browser_context_(browser_context),
+      profile_(profile),
       extension_service_(extension_service),
       ignore_whitelist_for_testing_(false),
       weak_factory_(this) {}
@@ -374,7 +384,7 @@
 }
 
 void ComponentLoader::AddHotwordHelperExtension() {
-  if (HotwordServiceFactory::IsHotwordAllowed(browser_context_)) {
+  if (HotwordServiceFactory::IsHotwordAllowed(profile_)) {
     Add(IDR_HOTWORD_MANIFEST,
         base::FilePath(FILE_PATH_LITERAL("hotword")));
   }
@@ -392,48 +402,72 @@
       base::FilePath(FILE_PATH_LITERAL("network_speech_synthesis")));
 }
 
+void ComponentLoader::AddGoogleNowExtension() {
+#if defined(ENABLE_GOOGLE_NOW)
+  const char kEnablePrefix[] = "Enable";
+  const char kFieldTrialName[] = "GoogleNow";
+  std::string enable_prefix(kEnablePrefix);
+  std::string field_trial_result =
+      base::FieldTrialList::FindFullName(kFieldTrialName);
+
+  bool enabled_via_field_trial =
+      field_trial_result.compare(0, enable_prefix.length(), enable_prefix) == 0;
+
+  // Enable the feature on trybots and trunk builds.
+  bool enabled_via_trunk_build =
+      chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_UNKNOWN;
+
+  bool is_authenticated =
+      SigninManagerFactory::GetForProfile(profile_)->IsAuthenticated();
+
+  bool enabled =
+      (enabled_via_field_trial && is_authenticated) || enabled_via_trunk_build;
+
+#if defined(ENABLE_APP_LIST) && defined(OS_CHROMEOS)
+  // Don't load if newer trial is running (== new extension id is available).
+  std::string ignored_extension_id;
+  if (GetGoogleNowExtensionId(&ignored_extension_id)) {
+    enabled = false;
+  }
+#endif  // defined(ENABLE_APP_LIST) && defined(OS_CHROMEOS)
+
+  if (enabled) {
+    Add(IDR_GOOGLE_NOW_MANIFEST,
+        base::FilePath(FILE_PATH_LITERAL("google_now")));
+  }
+#endif  // defined(ENABLE_GOOGLE_NOW)
+}
+
 #if defined(OS_CHROMEOS)
 void ComponentLoader::AddChromeVoxExtension(
     const base::Closure& done_cb) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   base::FilePath resources_path;
-  PathService::Get(chrome::DIR_RESOURCES, &resources_path);
+  CHECK(PathService::Get(chrome::DIR_RESOURCES, &resources_path));
 
   base::FilePath chromevox_path =
       resources_path.Append(extension_misc::kChromeVoxExtensionPath);
 
-  const char* manifest_filename =
-      IsNormalSession() ? extension_misc::kChromeVoxManifestFilename
-                        : extension_misc::kChromeVoxGuestManifestFilename;
+  const base::FilePath::CharType* manifest_filename =
+      IsNormalSession() ? extensions::kManifestFilename
+                        : extension_misc::kGuestManifestFilename;
+  AddWithManifestFile(
+      manifest_filename,
+      chromevox_path,
+      extension_misc::kChromeVoxExtensionId,
+      done_cb);
+}
 
-  BrowserThread::PostTaskAndReplyWithResult(
-      BrowserThread::FILE,
-      FROM_HERE,
-      base::Bind(&LoadManifestOnFileThread, chromevox_path, manifest_filename),
-      base::Bind(&ComponentLoader::AddChromeVoxExtensionWithManifest,
+void ComponentLoader::AddChromeOsSpeechSynthesisExtension() {
+  const base::FilePath::CharType* manifest_filename =
+      IsNormalSession() ? extensions::kManifestFilename
+                        : extension_misc::kGuestManifestFilename;
+  AddWithManifestFile(
+      manifest_filename,
+      base::FilePath(extension_misc::kSpeechSynthesisExtensionPath),
+      extension_misc::kSpeechSynthesisExtensionId,
+      base::Bind(&ComponentLoader::EnableFileSystemInGuestMode,
                  weak_factory_.GetWeakPtr(),
-                 chromevox_path,
-                 done_cb));
-}
-
-void ComponentLoader::AddChromeVoxExtensionWithManifest(
-    const base::FilePath& chromevox_path,
-    const base::Closure& done_cb,
-    scoped_ptr<base::DictionaryValue> manifest) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  std::string extension_id = Add(manifest.release(), chromevox_path, false);
-  CHECK_EQ(extension_misc::kChromeVoxExtensionId, extension_id);
-  if (!done_cb.is_null())
-    done_cb.Run();
-}
-
-std::string ComponentLoader::AddChromeOsSpeechSynthesisExtension() {
-  int idr = IsNormalSession() ? IDR_SPEECH_SYNTHESIS_MANIFEST
-                              : IDR_SPEECH_SYNTHESIS_GUEST_MANIFEST;
-  std::string id = Add(idr,
-      base::FilePath(extension_misc::kSpeechSynthesisExtensionPath));
-  EnableFileSystemInGuestMode(id);
-  return id;
+                 extension_misc::kChromeVoxExtensionId));
 }
 #endif
 
@@ -597,6 +631,7 @@
     AddHotwordAudioVerificationApp();
     AddHotwordHelperExtension();
     AddImageLoaderExtension();
+    AddGoogleNowExtension();
 
     bool install_feedback = enable_background_extensions_during_testing;
 #if defined(GOOGLE_CHROME_BUILD)
@@ -649,36 +684,6 @@
   }
 #endif  // defined(OS_CHROMEOS)
 
-#if defined(ENABLE_GOOGLE_NOW)
-  const char kEnablePrefix[] = "Enable";
-  const char kFieldTrialName[] = "GoogleNow";
-  std::string enable_prefix(kEnablePrefix);
-  std::string field_trial_result =
-      base::FieldTrialList::FindFullName(kFieldTrialName);
-
-  bool enabled_via_field_trial =
-      field_trial_result.compare(0, enable_prefix.length(), enable_prefix) == 0;
-
-  // Enable the feature on trybots and trunk builds.
-  bool enabled_via_trunk_build =
-      chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_UNKNOWN;
-
-  bool enabled = enabled_via_field_trial || enabled_via_trunk_build;
-
-#if defined(ENABLE_APP_LIST) && defined(OS_CHROMEOS)
-  // Don't load if newer trial is running (== new extension id is available).
-  std::string ignored_extension_id;
-  if (GetGoogleNowExtensionId(&ignored_extension_id)) {
-    enabled = false;
-  }
-#endif
-
-  if (!skip_session_components && enabled) {
-    Add(IDR_GOOGLE_NOW_MANIFEST,
-        base::FilePath(FILE_PATH_LITERAL("google_now")));
-  }
-#endif
-
 #if defined(GOOGLE_CHROME_BUILD)
 #if !defined(OS_CHROMEOS)  // http://crbug.com/314799
   AddNetworkSpeechSynthesisExtension();
@@ -706,8 +711,7 @@
     // file system access. Make sure temporary file system is enabled in the off
     // the record browser context (as that is the one used in guest session).
     content::BrowserContext* off_the_record_context =
-        ExtensionsBrowserClient::Get()->GetOffTheRecordContext(
-            browser_context_);
+        ExtensionsBrowserClient::Get()->GetOffTheRecordContext(profile_);
     GURL site = content::SiteInstance::GetSiteForURL(
         off_the_record_context, Extension::GetBaseURLFromExtensionId(id));
     storage::FileSystemContext* file_system_context =
@@ -718,4 +722,40 @@
 #endif
 }
 
+#if defined(OS_CHROMEOS)
+void ComponentLoader::AddWithManifestFile(
+    const base::FilePath::CharType* manifest_filename,
+    const base::FilePath& root_directory,
+    const char* extension_id,
+    const base::Closure& done_cb) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  BrowserThread::PostTaskAndReplyWithResult(
+      BrowserThread::FILE,
+      FROM_HERE,
+      base::Bind(&LoadManifestOnFileThread, root_directory, manifest_filename),
+      base::Bind(&ComponentLoader::FinishAddWithManifestFile,
+                 weak_factory_.GetWeakPtr(),
+                 root_directory,
+                 extension_id,
+                 done_cb));
+}
+
+void ComponentLoader::FinishAddWithManifestFile(
+    const base::FilePath& root_directory,
+    const char* extension_id,
+    const base::Closure& done_cb,
+    scoped_ptr<base::DictionaryValue> manifest) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (!manifest)
+    return;  // Error already logged.
+  std::string actual_extension_id = Add(
+      manifest.release(),
+      root_directory,
+      false);
+  CHECK_EQ(extension_id, actual_extension_id);
+  if (!done_cb.is_null())
+    done_cb.Run();
+}
+#endif
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/component_loader.h b/chrome/browser/extensions/component_loader.h
index 3eff82c5..2f24323 100644
--- a/chrome/browser/extensions/component_loader.h
+++ b/chrome/browser/extensions/component_loader.h
@@ -16,10 +16,7 @@
 
 class ExtensionServiceInterface;
 class PrefService;
-
-namespace content {
-class BrowserContext;
-}
+class Profile;
 
 namespace extensions {
 
@@ -29,7 +26,7 @@
   ComponentLoader(ExtensionServiceInterface* extension_service,
                   PrefService* prefs,
                   PrefService* local_state,
-                  content::BrowserContext* browser_context);
+                  Profile* browser_context);
   virtual ~ComponentLoader();
 
   size_t registered_extensions_count() const {
@@ -103,7 +100,7 @@
   // NOTE: |done_cb| is not called if the component loader is shut down
   // during loading.
   void AddChromeVoxExtension(const base::Closure& done_cb);
-  std::string AddChromeOsSpeechSynthesisExtension();
+  void AddChromeOsSpeechSynthesisExtension();
 #endif
 
   void set_ignore_whitelist_for_testing(bool value) {
@@ -147,6 +144,7 @@
   void AddHotwordHelperExtension();
   void AddImageLoaderExtension();
   void AddNetworkSpeechSynthesisExtension();
+  void AddGoogleNowExtension();
 
   void AddWithNameAndDescription(int manifest_resource_id,
                                  const base::FilePath& root_directory,
@@ -164,18 +162,27 @@
   void EnableFileSystemInGuestMode(const std::string& id);
 
 #if defined(OS_CHROMEOS)
-  // Used as a reply callback when loading the ChromeVox extension.
-  // Called with a |chromevox_path| and parsed |manifest| and invokes
+  // Adds an extension where the manifest file is stored on the file system.
+  // |manifest_filename| can be relative to the |root_directory|.
+  void AddWithManifestFile(
+      const base::FilePath::CharType* manifest_filename,
+      const base::FilePath& root_directory,
+      const char* extension_id,
+      const base::Closure& done_cb);
+
+  // Used as a reply callback by |AddWithManifestFile|.
+  // Called with a |root_directory| and parsed |manifest| and invokes
   // |done_cb| after adding the extension.
-  void AddChromeVoxExtensionWithManifest(
-      const base::FilePath& chromevox_path,
+  void FinishAddWithManifestFile(
+      const base::FilePath& root_directory,
+      const char* extension_id,
       const base::Closure& done_cb,
       scoped_ptr<base::DictionaryValue> manifest);
 #endif
 
   PrefService* profile_prefs_;
   PrefService* local_state_;
-  content::BrowserContext* browser_context_;
+  Profile* profile_;
 
   ExtensionServiceInterface* extension_service_;
 
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc
index b0fe07d..abdbdf9 100644
--- a/chrome/browser/extensions/crx_installer_browsertest.cc
+++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -543,10 +543,7 @@
 }
 
 #if defined(OS_CHROMEOS)
-// This test is currently failing 25% of the time on the ChromiumOS bots.
-// Disabling until the issue can be resolved. (crbug.com/492162)
-IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
-                       DISABLED_InstallToSharedLocation) {
+IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, InstallToSharedLocation) {
   base::ShadowingAtExitManager at_exit_manager;
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       chromeos::switches::kEnableExtensionAssetsSharing);
diff --git a/chrome/browser/extensions/extension_gcm_app_handler.cc b/chrome/browser/extensions/extension_gcm_app_handler.cc
index c07bd54..2a43d18 100644
--- a/chrome/browser/extensions/extension_gcm_app_handler.cc
+++ b/chrome/browser/extensions/extension_gcm_app_handler.cc
@@ -12,7 +12,10 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/services/gcm/gcm_profile_service.h"
 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
+#include "chrome/browser/services/gcm/instance_id/instance_id_profile_service.h"
+#include "chrome/browser/services/gcm/instance_id/instance_id_profile_service_factory.h"
 #include "components/gcm_driver/gcm_driver.h"
+#include "components/gcm_driver/instance_id/instance_id_driver.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/common/extension.h"
@@ -137,16 +140,11 @@
     extensions::UninstallReason reason) {
   if (IsGCMPermissionEnabled(extension)) {
     // Let's first remove InstanceID data. GCM unregistration will be triggered
-    // after the asynchronous call is returned in OnDeleteTokensCompleted.
-    gcm::InstanceIDHandler* instance_id_handler =
-        GetGCMDriver()->GetInstanceIDHandler();
-    DCHECK(instance_id_handler);
-    instance_id_handler->DeleteAllTokensForApp(
-        extension->id(),
-        base::Bind(&ExtensionGCMAppHandler::OnDeleteTokensCompleted,
+    // after the asynchronous call is returned in OnDeleteIDCompleted.
+    GetInstanceIDDriver()->GetInstanceID(extension->id())->DeleteID(
+        base::Bind(&ExtensionGCMAppHandler::OnDeleteIDCompleted,
                    weak_factory_.GetWeakPtr(),
                    extension->id()));
-    instance_id_handler->RemoveInstanceIDData(extension->id());
   }
 }
 
@@ -162,18 +160,37 @@
   return gcm::GCMProfileServiceFactory::GetForProfile(profile_)->driver();
 }
 
+instance_id::InstanceIDDriver* ExtensionGCMAppHandler::GetInstanceIDDriver()
+    const {
+  return instance_id::InstanceIDProfileServiceFactory::GetForProfile(profile_)->
+      driver();
+}
+
 void ExtensionGCMAppHandler::OnUnregisterCompleted(
     const std::string& app_id, gcm::GCMClient::Result result) {
   RemoveAppHandler(app_id);
 }
 
-void ExtensionGCMAppHandler::OnDeleteTokensCompleted(
-    const std::string& app_id, gcm::GCMClient::Result result) {
+void ExtensionGCMAppHandler::OnDeleteIDCompleted(
+    const std::string& app_id, instance_id::InstanceID::Result result) {
   GetGCMDriver()->Unregister(
       app_id,
       base::Bind(&ExtensionGCMAppHandler::OnUnregisterCompleted,
                  weak_factory_.GetWeakPtr(),
-                  app_id));
+                 app_id));
+
+  // InstanceIDDriver::RemoveInstanceID will delete the InstanceID itself.
+  // Postpone to do it outside this calling context to avoid any risk to
+  // the caller.
+  base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&ExtensionGCMAppHandler::RemoveInstanceID,
+                   weak_factory_.GetWeakPtr(),
+                   app_id));
+}
+
+void ExtensionGCMAppHandler::RemoveInstanceID(const std::string& app_id) {
+  GetInstanceIDDriver()->RemoveInstanceID(app_id);
 }
 
 void ExtensionGCMAppHandler::AddAppHandler(const std::string& app_id) {
diff --git a/chrome/browser/extensions/extension_gcm_app_handler.h b/chrome/browser/extensions/extension_gcm_app_handler.h
index 3f361ba..f2a5a6c 100644
--- a/chrome/browser/extensions/extension_gcm_app_handler.h
+++ b/chrome/browser/extensions/extension_gcm_app_handler.h
@@ -14,6 +14,7 @@
 #include "base/scoped_observer.h"
 #include "components/gcm_driver/gcm_app_handler.h"
 #include "components/gcm_driver/gcm_client.h"
+#include "components/gcm_driver/instance_id/instance_id.h"
 #include "extensions/browser/browser_context_keyed_api_factory.h"
 #include "extensions/browser/extension_registry_observer.h"
 
@@ -27,6 +28,9 @@
 class GCMDriver;
 class GCMProfileService;
 }
+namespace instance_id {
+class InstanceIDDriver;
+}
 
 namespace extensions {
 
@@ -60,12 +64,13 @@
   // Could be overridden by testing purpose.
   virtual void OnUnregisterCompleted(const std::string& app_id,
                                      gcm::GCMClient::Result result);
-  virtual void OnDeleteTokensCompleted(const std::string& app_id,
-                                       gcm::GCMClient::Result result);
+  virtual void OnDeleteIDCompleted(const std::string& app_id,
+                                   instance_id::InstanceID::Result result);
   virtual void AddAppHandler(const std::string& app_id);
   virtual void RemoveAppHandler(const std::string& app_id);
 
   gcm::GCMDriver* GetGCMDriver() const;
+  instance_id::InstanceIDDriver* GetInstanceIDDriver() const;
 
  private:
   friend class BrowserContextKeyedAPIFactory<ExtensionGCMAppHandler>;
@@ -80,6 +85,7 @@
                               const Extension* extension,
                               extensions::UninstallReason reason) override;
 
+  void RemoveInstanceID(const std::string& app_id);
   void AddDummyAppHandler();
   void RemoveDummyAppHandler();
 
diff --git a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
index 4669ea3..1daefc7 100644
--- a/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
+++ b/chrome/browser/extensions/extension_gcm_app_handler_unittest.cc
@@ -132,7 +132,7 @@
       : ExtensionGCMAppHandler(profile),
         waiter_(waiter),
         unregistration_result_(gcm::GCMClient::UNKNOWN_ERROR),
-        delete_tokens_result_(gcm::GCMClient::UNKNOWN_ERROR),
+        delete_id_result_(instance_id::InstanceID::UNKNOWN_ERROR),
         app_handler_count_drop_to_zero_(false) {
   }
 
@@ -154,10 +154,10 @@
     waiter_->SignalCompleted();
   }
 
-  void OnDeleteTokensCompleted(const std::string& app_id,
-                               gcm::GCMClient::Result result) override {
-    delete_tokens_result_ = result;
-    ExtensionGCMAppHandler::OnDeleteTokensCompleted(app_id, result);
+  void OnDeleteIDCompleted(const std::string& app_id,
+                           instance_id::InstanceID::Result result) override {
+    delete_id_result_ = result;
+    ExtensionGCMAppHandler::OnDeleteIDCompleted(app_id, result);
   }
 
   void RemoveAppHandler(const std::string& app_id) override {
@@ -169,8 +169,8 @@
   gcm::GCMClient::Result unregistration_result() const {
     return unregistration_result_;
   }
-  gcm::GCMClient::Result delete_tokens_result() const {
-    return delete_tokens_result_;
+  instance_id::InstanceID::Result delete_id_result() const {
+    return delete_id_result_;
   }
   bool app_handler_count_drop_to_zero() const {
     return app_handler_count_drop_to_zero_;
@@ -179,7 +179,7 @@
  private:
   Waiter* waiter_;
   gcm::GCMClient::Result unregistration_result_;
-  gcm::GCMClient::Result delete_tokens_result_;
+  instance_id::InstanceID::Result delete_id_result_;
   bool app_handler_count_drop_to_zero_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeExtensionGCMAppHandler);
@@ -433,7 +433,8 @@
   // extension is uninstalled.
   UninstallExtension(extension.get());
   waiter()->WaitUntilCompleted();
-  EXPECT_EQ(gcm::GCMClient::SUCCESS, gcm_app_handler()->delete_tokens_result());
+  EXPECT_EQ(instance_id::InstanceID::SUCCESS,
+            gcm_app_handler()->delete_id_result());
   EXPECT_EQ(gcm::GCMClient::SUCCESS,
             gcm_app_handler()->unregistration_result());
 }
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index a59eeb9..687b340e 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -2118,16 +2118,24 @@
               profile_->GetOriginalProfile() != profile_)));
 }
 
-void ExtensionService::TrackTerminatedExtension(const Extension* extension) {
+void ExtensionService::TrackTerminatedExtension(
+    const std::string& extension_id) {
+  extensions_being_terminated_.erase(extension_id);
+
+  const Extension* extension = GetInstalledExtension(extension_id);
+  if (!extension) {
+    LOG(WARNING) << "Terminated extension is already removed.";
+    return;
+  }
+
   // No need to check for duplicates; inserting a duplicate is a no-op.
   registry_->AddTerminated(make_scoped_refptr(extension));
-  extensions_being_terminated_.erase(extension->id());
   UnloadExtension(extension->id(), UnloadedExtensionInfo::REASON_TERMINATE);
 }
 
 void ExtensionService::TerminateExtension(const std::string& extension_id) {
   const Extension* extension = GetInstalledExtension(extension_id);
-  TrackTerminatedExtension(extension);
+  TrackTerminatedExtension(extension->id());
 }
 
 void ExtensionService::UntrackTerminatedExtension(const std::string& id) {
@@ -2268,7 +2276,7 @@
           base::Bind(
               &ExtensionService::TrackTerminatedExtension,
               AsWeakPtr(),
-              host->extension()));
+              host->extension()->id()));
       break;
     }
     case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 3bd767ad..01efc615 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -115,7 +115,7 @@
   // Looks up an extension by ID, regardless of whether it's enabled,
   // disabled, blacklisted, or terminated. Use instead:
   //
-  //   ExtensionRegistry::GetExtensionById(id, ExtensionRegistry::EVERYTHING).
+  // ExtensionRegistry::GetInstalledExtension(id).
   virtual const extensions::Extension* GetInstalledExtension(
       const std::string& id) const = 0;
 
@@ -449,7 +449,7 @@
 
 #if defined(UNIT_TEST)
   void TrackTerminatedExtensionForTest(const extensions::Extension* extension) {
-    TrackTerminatedExtension(extension);
+    TrackTerminatedExtension(extension->id());
   }
 
   void FinishInstallationForTest(const extensions::Extension* extension) {
@@ -523,9 +523,9 @@
   // external extensions.
   void OnAllExternalProvidersReady();
 
-  // Adds the given extension to the list of terminated extensions if
+  // Adds the given extension id to the list of terminated extensions if
   // it is not already there and unloads it.
-  void TrackTerminatedExtension(const extensions::Extension* extension);
+  void TrackTerminatedExtension(const std::string& extension_id);
 
   // Removes the extension with the given id from the list of
   // terminated extensions if it is there.
diff --git a/chrome/browser/extensions/tab_helper.cc b/chrome/browser/extensions/tab_helper.cc
index e3c8c445..53c7127 100644
--- a/chrome/browser/extensions/tab_helper.cc
+++ b/chrome/browser/extensions/tab_helper.cc
@@ -40,6 +40,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
@@ -65,7 +66,6 @@
 
 using content::NavigationController;
 using content::NavigationEntry;
-using content::RenderViewHost;
 using content::WebContents;
 
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::TabHelper);
@@ -91,8 +91,9 @@
   // The ActiveTabPermissionManager requires a session ID; ensure this
   // WebContents has one.
   SessionTabHelper::CreateForWebContents(web_contents);
-  if (web_contents->GetRenderViewHost())
-    SetTabId(web_contents->GetRenderViewHost());
+  // The Unretained() is safe because ForEachFrame is synchronous.
+  web_contents->ForEachFrame(
+      base::Bind(&TabHelper::SetTabId, base::Unretained(this)));
   active_tab_permission_granter_.reset(new ActiveTabPermissionGranter(
       web_contents,
       SessionTabHelper::IdForTab(web_contents),
@@ -197,8 +198,8 @@
   pending_web_app_action_ = NONE;
 }
 
-void TabHelper::RenderViewCreated(RenderViewHost* render_view_host) {
-  SetTabId(render_view_host);
+void TabHelper::RenderFrameCreated(content::RenderFrameHost* host) {
+  SetTabId(host);
 }
 
 void TabHelper::DidNavigateMainFrame(
@@ -261,8 +262,6 @@
     IPC_MESSAGE_HANDLER(ExtensionHostMsg_GetAppInstallState,
                         OnGetAppInstallState);
     IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
-    IPC_MESSAGE_HANDLER(ExtensionHostMsg_ContentScriptsExecuting,
-                        OnContentScriptsExecuting)
     IPC_MESSAGE_HANDLER(ExtensionHostMsg_OnWatchedPageChange,
                         OnWatchedPageChange)
     IPC_MESSAGE_UNHANDLED(handled = false)
@@ -276,6 +275,8 @@
   IPC_BEGIN_MESSAGE_MAP(TabHelper, message)
     IPC_MESSAGE_HANDLER(ExtensionHostMsg_DetailedConsoleMessageAdded,
                         OnDetailedConsoleMessageAdded)
+    IPC_MESSAGE_HANDLER(ExtensionHostMsg_ContentScriptsExecuting,
+                        OnContentScriptsExecuting)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -594,9 +595,9 @@
   }
 }
 
-void TabHelper::SetTabId(RenderViewHost* render_view_host) {
-  render_view_host->Send(
-      new ExtensionMsg_SetTabId(render_view_host->GetRoutingID(),
+void TabHelper::SetTabId(content::RenderFrameHost* render_frame_host) {
+  render_frame_host->Send(
+      new ExtensionMsg_SetTabId(render_frame_host->GetRoutingID(),
                                 SessionTabHelper::IdForTab(web_contents())));
 }
 
diff --git a/chrome/browser/extensions/tab_helper.h b/chrome/browser/extensions/tab_helper.h
index 4608a06..5564f914 100644
--- a/chrome/browser/extensions/tab_helper.h
+++ b/chrome/browser/extensions/tab_helper.h
@@ -142,7 +142,7 @@
                                const WebApplicationInfo& web_app_info);
 
   // content::WebContentsObserver overrides.
-  void RenderViewCreated(content::RenderViewHost* render_view_host) override;
+  void RenderFrameCreated(content::RenderFrameHost* host) override;
   void DidNavigateMainFrame(
       const content::LoadCommittedDetails& details,
       const content::FrameNavigateParams& params) override;
@@ -209,8 +209,8 @@
   // the data is available.
   void GetApplicationInfo(WebAppAction action);
 
-  // Sends our tab ID to |render_view_host|.
-  void SetTabId(content::RenderViewHost* render_view_host);
+  // Sends our tab ID to |render_frame_host|.
+  void SetTabId(content::RenderFrameHost* render_frame_host);
 
   // Data for app extensions ---------------------------------------------------
 
diff --git a/chrome/browser/geolocation/geolocation_permission_context.cc b/chrome/browser/geolocation/geolocation_permission_context.cc
index 2a58fc8..df90856 100644
--- a/chrome/browser/geolocation/geolocation_permission_context.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context.cc
@@ -6,8 +6,8 @@
 
 #include "base/bind.h"
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/browser/profiles/profile.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/geolocation_provider.h"
 #include "content/public/browser/render_frame_host.h"
@@ -34,7 +34,7 @@
   bool permission_set;
   bool new_permission;
   if (extensions_context_.RequestPermission(
-      web_contents, id, id.bridge_id(), requesting_frame_origin, user_gesture,
+      web_contents, id, id.request_id(), requesting_frame_origin, user_gesture,
       callback, &permission_set, &new_permission)) {
     if (permission_set) {
       ContentSetting content_setting =
@@ -43,7 +43,7 @@
                           requesting_frame_origin,
                           web_contents->GetLastCommittedURL().GetOrigin(),
                           callback,
-                          true,
+                          false /* persist */,
                           content_setting);
     }
     return;
@@ -60,7 +60,7 @@
     const PermissionRequestID& id) {
 
     if (extensions_context_.CancelPermissionRequest(
-        web_contents, id.bridge_id()))
+        web_contents, id.request_id()))
       return;
     PermissionContextBase::CancelPermissionRequest(web_contents, id);
 }
diff --git a/chrome/browser/geolocation/geolocation_permission_context_android.cc b/chrome/browser/geolocation/geolocation_permission_context_android.cc
index 3a38c25..6b339835 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_android.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context_android.cc
@@ -6,7 +6,7 @@
 
 #include "chrome/browser/android/location_settings.h"
 #include "chrome/browser/android/location_settings_impl.h"
-#include "components/content_settings/core/common/permission_request_id.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "content/public/browser/web_contents.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/geolocation/geolocation_permission_context_extensions.cc b/chrome/browser/geolocation/geolocation_permission_context_extensions.cc
index 15a32092a..3b10998 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_extensions.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context_extensions.cc
@@ -7,8 +7,8 @@
 #include "base/callback.h"
 
 #if defined(ENABLE_EXTENSIONS)
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/browser/profiles/profile.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/guest_view/web_view/web_view_permission_helper.h"
 #include "extensions/browser/process_map.h"
diff --git a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
index 70d13d5d..3017c8a 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/geolocation/geolocation_permission_context_factory.h"
 #include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/browser/ui/website_settings/mock_permission_bubble_view.h"
 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
 #include "chrome/browser/ui/website_settings/permission_bubble_request.h"
@@ -27,7 +28,6 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "components/infobars/core/confirm_infobar_delegate.h"
 #include "components/infobars/core/infobar.h"
 #include "content/public/browser/browser_thread.h"
@@ -116,8 +116,8 @@
   void SetUp() override;
   void TearDown() override;
 
-  PermissionRequestID RequestID(int bridge_id);
-  PermissionRequestID RequestIDForTab(int tab, int bridge_id);
+  PermissionRequestID RequestID(int request_id);
+  PermissionRequestID RequestIDForTab(int tab, int request_id);
   InfoBarService* infobar_service() {
     return InfoBarService::FromWebContents(web_contents());
   }
@@ -132,10 +132,10 @@
 
   void PermissionResponse(const PermissionRequestID& id,
                           ContentSetting content_setting);
-  void CheckPermissionMessageSent(int bridge_id, bool allowed);
-  void CheckPermissionMessageSentForTab(int tab, int bridge_id, bool allowed);
+  void CheckPermissionMessageSent(int request_id, bool allowed);
+  void CheckPermissionMessageSentForTab(int tab, int request_id, bool allowed);
   void CheckPermissionMessageSentInternal(MockRenderProcessHost* process,
-                                          int bridge_id,
+                                          int request_id,
                                           bool allowed);
   void AddNewTab(const GURL& url);
   void CheckTabContentsState(const GURL& requesting_frame,
@@ -160,21 +160,21 @@
 };
 
 PermissionRequestID GeolocationPermissionContextTests::RequestID(
-    int bridge_id) {
+    int request_id) {
   return PermissionRequestID(
       web_contents()->GetRenderProcessHost()->GetID(),
       web_contents()->GetMainFrame()->GetRoutingID(),
-      bridge_id,
+      request_id,
       GURL());
 }
 
 PermissionRequestID GeolocationPermissionContextTests::RequestIDForTab(
     int tab,
-    int bridge_id) {
+    int request_id) {
   return PermissionRequestID(
       extra_tabs_[tab]->GetRenderProcessHost()->GetID(),
       extra_tabs_[tab]->GetMainFrame()->GetRoutingID(),
-      bridge_id,
+      request_id,
       GURL());
 }
 
@@ -194,30 +194,30 @@
     const PermissionRequestID& id,
     ContentSetting content_setting) {
   responses_[id.render_process_id()] =
-      std::make_pair(id.bridge_id(), content_setting == CONTENT_SETTING_ALLOW);
+      std::make_pair(id.request_id(), content_setting == CONTENT_SETTING_ALLOW);
 }
 
 void GeolocationPermissionContextTests::CheckPermissionMessageSent(
-    int bridge_id,
+    int request_id,
     bool allowed) {
-  CheckPermissionMessageSentInternal(process(), bridge_id, allowed);
+  CheckPermissionMessageSentInternal(process(), request_id, allowed);
 }
 
 void GeolocationPermissionContextTests::CheckPermissionMessageSentForTab(
     int tab,
-    int bridge_id,
+    int request_id,
     bool allowed) {
   CheckPermissionMessageSentInternal(static_cast<MockRenderProcessHost*>(
       extra_tabs_[tab]->GetRenderProcessHost()),
-      bridge_id, allowed);
+      request_id, allowed);
 }
 
 void GeolocationPermissionContextTests::CheckPermissionMessageSentInternal(
     MockRenderProcessHost* process,
-    int bridge_id,
+    int request_id,
     bool allowed) {
   ASSERT_EQ(responses_.count(process->GetID()), 1U);
-  EXPECT_EQ(bridge_id, responses_[process->GetID()].first);
+  EXPECT_EQ(request_id, responses_[process->GetID()].first);
   EXPECT_EQ(allowed, responses_[process->GetID()].second);
   responses_.erase(process->GetID());
 }
diff --git a/chrome/browser/google/google_url_tracker_factory.cc b/chrome/browser/google/google_url_tracker_factory.cc
index 81538e8..7830d54 100644
--- a/chrome/browser/google/google_url_tracker_factory.cc
+++ b/chrome/browser/google/google_url_tracker_factory.cc
@@ -11,14 +11,6 @@
 #include "components/google/core/browser/google_pref_names.h"
 #include "components/google/core/browser/google_url_tracker.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "components/pref_registry/pref_registry_syncable.h"
-
-namespace {
-
-const char kLastPromptedGoogleURL[] = "browser.last_prompted_google_url";
-
-}  // namespace
-
 
 // static
 GoogleURLTracker* GoogleURLTrackerFactory::GetForProfile(Profile* profile) {
@@ -45,7 +37,7 @@
   // Delete this now-unused pref.
   // At some point in the future, this code can be removed entirely.
   static_cast<Profile*>(context)->GetOriginalProfile()->GetPrefs()->ClearPref(
-      kLastPromptedGoogleURL);
+      prefs::kLastPromptedGoogleURL);
 
   scoped_ptr<GoogleURLTrackerClient> client(
       new ChromeGoogleURLTrackerClient(Profile::FromBrowserContext(context)));
@@ -54,9 +46,7 @@
 
 void GoogleURLTrackerFactory::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* user_prefs) {
-  user_prefs->RegisterStringPref(prefs::kLastKnownGoogleURL,
-                                 GoogleURLTracker::kDefaultGoogleHomepage);
-  user_prefs->RegisterStringPref(kLastPromptedGoogleURL, std::string());
+  GoogleURLTracker::RegisterProfilePrefs(user_prefs);
 }
 
 content::BrowserContext* GoogleURLTrackerFactory::GetBrowserContextToUse(
diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc b/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc
index 94a8ae6..b48c13f 100644
--- a/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc
+++ b/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc
@@ -7,11 +7,11 @@
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/geolocation/geolocation_permission_context.h"
 #include "chrome/browser/geolocation/geolocation_permission_context_factory.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/render_messages.h"
 #include "components/content_settings/content/common/content_settings_messages.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
diff --git a/chrome/browser/infobars/infobar_service.cc b/chrome/browser/infobars/infobar_service.cc
index 3bc0e4e..556086b 100644
--- a/chrome/browser/infobars/infobar_service.cc
+++ b/chrome/browser/infobars/infobar_service.cc
@@ -14,44 +14,28 @@
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents.h"
+#include "ui/base/page_transition_types.h"
+
 
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(InfoBarService);
 
-using infobars::InfoBar;
-using infobars::InfoBarDelegate;
-using infobars::InfoBarManager;
-
-namespace {
-
-bool IsReload(const content::LoadCommittedDetails& details) {
-  return ui::PageTransitionStripQualifier(
-      details.entry->GetTransitionType()) == ui::PAGE_TRANSITION_RELOAD;
-
-}
-
-}  // namespace
-
 // static
-InfoBarDelegate::NavigationDetails
+infobars::InfoBarDelegate::NavigationDetails
     InfoBarService::NavigationDetailsFromLoadCommittedDetails(
         const content::LoadCommittedDetails& details) {
-  InfoBarDelegate::NavigationDetails navigation_details;
+  infobars::InfoBarDelegate::NavigationDetails navigation_details;
   navigation_details.entry_id = details.entry->GetUniqueID();
   navigation_details.is_navigation_to_different_page =
       details.is_navigation_to_different_page();
   navigation_details.did_replace_entry = details.did_replace_entry;
-  navigation_details.is_main_frame = details.is_main_frame;
-
-  const ui::PageTransition transition = details.entry->GetTransitionType();
-  navigation_details.is_reload = IsReload(details);
   navigation_details.is_redirect =
-      (transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK) != 0;
-
+      ui::PageTransitionIsRedirect(details.entry->GetTransitionType());
   return navigation_details;
 }
 
 // static
-content::WebContents* InfoBarService::WebContentsFromInfoBar(InfoBar* infobar) {
+content::WebContents* InfoBarService::WebContentsFromInfoBar(
+    infobars::InfoBar* infobar) {
   if (!infobar || !infobar->owner())
     return NULL;
   InfoBarService* infobar_service =
@@ -75,25 +59,26 @@
   return active_entry ? active_entry->GetUniqueID() : 0;
 }
 
-void InfoBarService::NotifyInfoBarAdded(InfoBar* infobar) {
-  InfoBarManager::NotifyInfoBarAdded(infobar);
+void InfoBarService::NotifyInfoBarAdded(infobars::InfoBar* infobar) {
+  infobars::InfoBarManager::NotifyInfoBarAdded(infobar);
   // TODO(droger): Remove the notifications and have listeners change to be
   // InfoBarManager::Observers instead. See http://crbug.com/354380
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
       content::Source<InfoBarService>(this),
-      content::Details<InfoBar::AddedDetails>(infobar));
+      content::Details<infobars::InfoBar::AddedDetails>(infobar));
 }
 
-void InfoBarService::NotifyInfoBarRemoved(InfoBar* infobar, bool animate) {
-  InfoBarManager::NotifyInfoBarRemoved(infobar, animate);
+void InfoBarService::NotifyInfoBarRemoved(infobars::InfoBar* infobar,
+                                          bool animate) {
+  infobars::InfoBarManager::NotifyInfoBarRemoved(infobar, animate);
   // TODO(droger): Remove the notifications and have listeners change to be
   // InfoBarManager::Observers instead. See http://crbug.com/354380
-  InfoBar::RemovedDetails removed_details(infobar, animate);
+  infobars::InfoBar::RemovedDetails removed_details(infobar, animate);
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
       content::Source<InfoBarService>(this),
-      content::Details<InfoBar::RemovedDetails>(&removed_details));
+      content::Details<infobars::InfoBar::RemovedDetails>(&removed_details));
 }
 
 // InfoBarService::CreateConfirmInfoBar() is implemented in platform-specific
@@ -111,7 +96,10 @@
 
 void InfoBarService::NavigationEntryCommitted(
     const content::LoadCommittedDetails& load_details) {
-  const bool ignore = ignore_next_reload_ && IsReload(load_details);
+  const bool ignore = ignore_next_reload_ &&
+      (ui::PageTransitionStripQualifier(
+          load_details.entry->GetTransitionType()) ==
+          ui::PAGE_TRANSITION_RELOAD);
   ignore_next_reload_ = false;
   if (!ignore)
     OnNavigation(NavigationDetailsFromLoadCommittedDetails(load_details));
diff --git a/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc b/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
index e23cefd..059db34 100644
--- a/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
+++ b/chrome/browser/media/chrome_media_stream_infobar_browsertest.cc
@@ -114,29 +114,32 @@
 
 // Actual tests ---------------------------------------------------------------
 
-IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest, TestAllowingUserMedia) {
+IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
+                       DISABLED_TestAllowingUserMedia) {
   content::WebContents* tab_contents = LoadTestPageInTab();
   EXPECT_TRUE(GetUserMediaAndAccept(tab_contents));
 }
 
-IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest, TestDenyingUserMedia) {
+IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
+                       DISABLED_TestDenyingUserMedia) {
   content::WebContents* tab_contents = LoadTestPageInTab();
   GetUserMediaAndDeny(tab_contents);
 }
 
-IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest, TestDismissingInfobar) {
+IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
+                       DISABLED_TestDismissingInfobar) {
   content::WebContents* tab_contents = LoadTestPageInTab();
   GetUserMediaAndDismiss(tab_contents);
 }
 
 IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
-                       TestDenyingUserMediaIncognito) {
+                       DISABLED_TestDenyingUserMediaIncognito) {
   content::WebContents* tab_contents = LoadTestPageInIncognitoTab();
   GetUserMediaAndDeny(tab_contents);
 }
 
 IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
-                       TestAcceptThenDenyWhichShouldBeSticky) {
+                       DISABLED_TestAcceptThenDenyWhichShouldBeSticky) {
 #if defined(OS_WIN) && defined(USE_ASH)
   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -159,7 +162,8 @@
   EXPECT_EQ(0u, infobar_service->infobar_count());
 }
 
-IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest, TestAcceptIsNotSticky) {
+IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
+                       DISABLED_TestAcceptIsNotSticky) {
   content::WebContents* tab_contents = LoadTestPageInTab();
 
   // If accept were sticky the second call would hang because it hangs if an
@@ -168,7 +172,8 @@
   EXPECT_TRUE(GetUserMediaAndAccept(tab_contents));
 }
 
-IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest, TestDismissIsNotSticky) {
+IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
+                       DISABLED_TestDismissIsNotSticky) {
   content::WebContents* tab_contents = LoadTestPageInTab();
 
   // If dismiss were sticky the second call would hang because it hangs if an
@@ -178,7 +183,7 @@
 }
 
 IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
-                       TestDenyingThenClearingStickyException) {
+                       DISABLED_TestDenyingThenClearingStickyException) {
   content::WebContents* tab_contents = LoadTestPageInTab();
 
   GetUserMediaAndDeny(tab_contents);
@@ -214,7 +219,7 @@
 }
 
 IN_PROC_BROWSER_TEST_P(MediaStreamPermissionTest,
-                       DenyingCameraDoesNotCauseStickyDenyForMics) {
+                       DISABLED_DenyingCameraDoesNotCauseStickyDenyForMics) {
   content::WebContents* tab_contents = LoadTestPageInTab();
 
   // If camera blocking also blocked mics, the second call here would hang.
diff --git a/chrome/browser/media/midi_permission_context.cc b/chrome/browser/media/midi_permission_context.cc
index 7d2b2e01..d2162e7 100644
--- a/chrome/browser/media/midi_permission_context.cc
+++ b/chrome/browser/media/midi_permission_context.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/media/midi_permission_context.h"
 
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
-#include "components/content_settings/core/common/permission_request_id.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/media/midi_permission_context_unittest.cc b/chrome/browser/media/midi_permission_context_unittest.cc
index c908198..3a33b35 100644
--- a/chrome/browser/media/midi_permission_context_unittest.cc
+++ b/chrome/browser/media/midi_permission_context_unittest.cc
@@ -7,13 +7,13 @@
 #include "base/bind.h"
 #include "chrome/browser/content_settings/permission_queue_controller.h"
 #include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/browser/ui/website_settings/permission_bubble_manager.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/web_contents_tester.h"
diff --git a/chrome/browser/media/protected_media_identifier_infobar_delegate.cc b/chrome/browser/media/protected_media_identifier_infobar_delegate.cc
index c1559688..ae1637d 100644
--- a/chrome/browser/media/protected_media_identifier_infobar_delegate.cc
+++ b/chrome/browser/media/protected_media_identifier_infobar_delegate.cc
@@ -6,6 +6,7 @@
 
 #include "chrome/browser/content_settings/permission_queue_controller.h"
 #include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/infobars/core/infobar.h"
diff --git a/chrome/browser/media/protected_media_identifier_infobar_delegate.h b/chrome/browser/media/protected_media_identifier_infobar_delegate.h
index 1681da8d..4d1459dc9 100644
--- a/chrome/browser/media/protected_media_identifier_infobar_delegate.h
+++ b/chrome/browser/media/protected_media_identifier_infobar_delegate.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "components/content_settings/core/common/permission_request_id.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "components/infobars/core/confirm_infobar_delegate.h"
 #include "url/gurl.h"
 
diff --git a/chrome/browser/media/protected_media_identifier_permission_context.cc b/chrome/browser/media/protected_media_identifier_permission_context.cc
index ba3b064..b419eb9 100644
--- a/chrome/browser/media/protected_media_identifier_permission_context.cc
+++ b/chrome/browser/media/protected_media_identifier_permission_context.cc
@@ -9,7 +9,6 @@
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/browser/web_contents.h"
@@ -139,7 +138,7 @@
 
 #if defined(OS_CHROMEOS)
   PendingRequestMap::iterator request = pending_requests_.find(web_contents);
-  if (request == pending_requests_.end() || !request->second.second.Equals(id))
+  if (request == pending_requests_.end() || (request->second.second != id))
     return;
 
   views::Widget* widget = request->second.first;
@@ -227,7 +226,7 @@
   if (request == pending_requests_.end())
     return;
 
-  DCHECK(request->second.second.Equals(id));
+  DCHECK(request->second.second == id);
   pending_requests_.erase(request);
 
   ContentSetting content_setting = CONTENT_SETTING_ASK;
diff --git a/chrome/browser/media/protected_media_identifier_permission_context.h b/chrome/browser/media/protected_media_identifier_permission_context.h
index f18f521..42d4004 100644
--- a/chrome/browser/media/protected_media_identifier_permission_context.h
+++ b/chrome/browser/media/protected_media_identifier_permission_context.h
@@ -6,7 +6,7 @@
 #define CHROME_BROWSER_MEDIA_PROTECTED_MEDIA_IDENTIFIER_PERMISSION_CONTEXT_H_
 
 #include "chrome/browser/content_settings/permission_context_base.h"
-#include "components/content_settings/core/common/permission_request_id.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 
 #if defined(OS_CHROMEOS)
 #include <map>
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl.cc b/chrome/browser/media/router/presentation_service_delegate_impl.cc
index ebe434d4..30b1c8a 100644
--- a/chrome/browser/media/router/presentation_service_delegate_impl.cc
+++ b/chrome/browser/media/router/presentation_service_delegate_impl.cc
@@ -327,6 +327,15 @@
   router_ = router;
 }
 
+PresentationServiceDelegateImpl*
+PresentationServiceDelegateImpl::GetOrCreateForWebContents(
+    content::WebContents* web_contents) {
+  DCHECK(web_contents);
+  // CreateForWebContents does nothing if the delegate instance already exists.
+  PresentationServiceDelegateImpl::CreateForWebContents(web_contents);
+  return PresentationServiceDelegateImpl::FromWebContents(web_contents);
+}
+
 PresentationServiceDelegateImpl::PresentationServiceDelegateImpl(
     content::WebContents* web_contents)
     : web_contents_(web_contents),
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl.h b/chrome/browser/media/router/presentation_service_delegate_impl.h
index 212e25c..43d34c00 100644
--- a/chrome/browser/media/router/presentation_service_delegate_impl.h
+++ b/chrome/browser/media/router/presentation_service_delegate_impl.h
@@ -46,6 +46,12 @@
     : public content::WebContentsUserData<PresentationServiceDelegateImpl>,
       public content::PresentationServiceDelegate {
  public:
+  // Retrieves the instance of PresentationServiceDelegateImpl that was attached
+  // to the specified WebContents.  If no instance was attached, creates one,
+  // and attaches it to the specified WebContents.
+  static PresentationServiceDelegateImpl* GetOrCreateForWebContents(
+      content::WebContents* web_contents);
+
   ~PresentationServiceDelegateImpl() override;
 
   // content::PresentationServiceDelegate implementation.
diff --git a/chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.cc b/chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.cc
index f9dafa9..a4389b7 100644
--- a/chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.cc
+++ b/chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.cc
@@ -64,10 +64,10 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK_EQ(INITIAL_STATE, parser_state_);
 
-  scoped_refptr<base::MessageLoopProxy> message_loop_proxy =
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
   utility_process_host_ =
-      UtilityProcessHost::Create(this, message_loop_proxy.get())->AsWeakPtr();
+      UtilityProcessHost::Create(this, task_runner.get())->AsWeakPtr();
   utility_process_host_->SetName(l10n_util::GetStringUTF16(
       IDS_UTILITY_PROCESS_MEDIA_LIBRARY_FILE_CHECKER_NAME));
   // Wait for the startup notification before sending the main IPC to the
diff --git a/chrome/browser/metrics/chrome_stability_metrics_provider.cc b/chrome/browser/metrics/chrome_stability_metrics_provider.cc
index 9b6b126b1..6968d40 100644
--- a/chrome/browser/metrics/chrome_stability_metrics_provider.cc
+++ b/chrome/browser/metrics/chrome_stability_metrics_provider.cc
@@ -36,6 +36,10 @@
 #include "components/browser_watcher/crash_reporting_metrics_win.h"
 #endif
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/memory/system_memory_stats_recorder.h"
+#endif
+
 namespace {
 
 void IncrementPrefValue(const char* path) {
@@ -109,6 +113,11 @@
 }
 #endif  // defined(OS_WIN)
 
+void RecordChildKills(bool was_extension_process) {
+  UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills",
+                           was_extension_process ? 2 : 1);
+}
+
 }  // namespace
 
 ChromeStabilityMetricsProvider::ChromeStabilityMetricsProvider() {
@@ -286,8 +295,18 @@
     UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes",
                              was_extension_process ? 2 : 1);
   } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
-    UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills",
-                             was_extension_process ? 2 : 1);
+    RecordChildKills(was_extension_process);
+#if defined(OS_CHROMEOS)
+  } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM) {
+    RecordChildKills(was_extension_process);
+    UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills.OOM",
+                              was_extension_process ? 2 : 1,
+                              3);
+    chromeos::RecordMemoryStats(
+        was_extension_process ?
+        chromeos::RECORD_MEMORY_STATS_EXTENSIONS_OOM_KILLED :
+        chromeos::RECORD_MEMORY_STATS_CONTENTS_OOM_KILLED);
+#endif
   } else if (status == base::TERMINATION_STATUS_STILL_RUNNING) {
     UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.DisconnectedAlive",
                              was_extension_process ? 2 : 1);
diff --git a/chrome/browser/net/net_error_tab_helper_unittest.cc b/chrome/browser/net/net_error_tab_helper_unittest.cc
index d225104e..e099754b 100644
--- a/chrome/browser/net/net_error_tab_helper_unittest.cc
+++ b/chrome/browser/net/net_error_tab_helper_unittest.cc
@@ -7,6 +7,7 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/error_page/common/net_error_info.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_renderer_host.h"
 #include "net/base/net_errors.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/page_transition_types.h"
@@ -56,6 +57,13 @@
 
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
+
+    // This will simulate the initialization of the RenderFrame in the renderer
+    // process. This is needed because WebContents does not initialize a
+    // RenderFrame on construction, and the tests expect one to exist.
+    content::RenderFrameHostTester::For(main_rfh())
+        ->InitializeRenderFrameIfNeeded();
+
     subframe_ = content::RenderFrameHostTester::For(main_rfh())
                     ->AppendChild("subframe");
 
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
index f01181a7..80404d9 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "base/base64.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/prefs/pref_service.h"
@@ -59,6 +60,17 @@
              proxy_rules.proxies_for_https);
 }
 
+// Extract the embedded PAC script from the given |pac_url|, and store the
+// extracted script in |pac_script|. Returns true if extraction was successful,
+// otherwise returns false. |pac_script| must not be NULL.
+bool GetEmbeddedPacScript(const std::string& pac_url, std::string* pac_script) {
+  DCHECK(pac_script);
+  const std::string kPacURLPrefix =
+      "data:application/x-ns-proxy-autoconfig;base64,";
+  return StartsWithASCII(pac_url, kPacURLPrefix, true) &&
+         base::Base64Decode(pac_url.substr(kPacURLPrefix.size()), pac_script);
+}
+
 }  // namespace
 
 // The Data Reduction Proxy has been turned into a "best effort" proxy,
@@ -98,27 +110,54 @@
     prefs->ClearPref(prefs::kProxy);
     return PROXY_PREF_CLEARED_MODE_SYSTEM;
   }
-  if (ProxyModeToString(ProxyPrefs::MODE_FIXED_SERVERS) != mode)
-    return PROXY_PREF_NOT_CLEARED;
-  std::string proxy_server;
-  if (!dict->GetString("server", &proxy_server))
-    return PROXY_PREF_NOT_CLEARED;
-  net::ProxyConfig::ProxyRules proxy_rules;
-  proxy_rules.ParseFromString(proxy_server);
-  // Clear the proxy pref if it matches a currently configured Data Reduction
-  // Proxy, or if the proxy host ends with ".googlezip.net", in order to ensure
-  // that any DRP in the pref is cleared even if the DRP configuration was
-  // changed. See http://crbug.com/476610.
-  ProxyPrefMigrationResult rv;
-  if (Config()->ContainsDataReductionProxy(proxy_rules))
-    rv = PROXY_PREF_CLEARED_DRP;
-  else if (ContainsDataReductionProxyDefaultHostSuffix(proxy_rules))
-    rv = PROXY_PREF_CLEARED_GOOGLEZIP;
-  else
-    return PROXY_PREF_NOT_CLEARED;
 
-  prefs->ClearPref(prefs::kProxy);
-  return rv;
+  // From M36 to M40, the DRP was configured using MODE_FIXED_SERVERS in the
+  // proxy pref.
+  if (ProxyModeToString(ProxyPrefs::MODE_FIXED_SERVERS) == mode) {
+    std::string proxy_server;
+    if (!dict->GetString("server", &proxy_server))
+      return PROXY_PREF_NOT_CLEARED;
+    net::ProxyConfig::ProxyRules proxy_rules;
+    proxy_rules.ParseFromString(proxy_server);
+    // Clear the proxy pref if it matches a currently configured Data Reduction
+    // Proxy, or if the proxy host ends with ".googlezip.net", in order to
+    // ensure that any DRP in the pref is cleared even if the DRP configuration
+    // was changed. See http://crbug.com/476610.
+    ProxyPrefMigrationResult rv;
+    if (Config()->ContainsDataReductionProxy(proxy_rules))
+      rv = PROXY_PREF_CLEARED_DRP;
+    else if (ContainsDataReductionProxyDefaultHostSuffix(proxy_rules))
+      rv = PROXY_PREF_CLEARED_GOOGLEZIP;
+    else
+      return PROXY_PREF_NOT_CLEARED;
+
+    prefs->ClearPref(prefs::kProxy);
+    return rv;
+  }
+
+  // Before M35, the DRP was configured using a PAC script base64 encoded into a
+  // PAC url.
+  if (ProxyModeToString(ProxyPrefs::MODE_PAC_SCRIPT) == mode) {
+    std::string pac_url;
+    std::string pac_script;
+    if (!dict->GetString("pac_url", &pac_url) ||
+        !GetEmbeddedPacScript(pac_url, &pac_script)) {
+      return PROXY_PREF_NOT_CLEARED;
+    }
+
+    // In M35 and earlier, the way of specifying the DRP in a PAC script would
+    // always include the port number after the host even if the port number
+    // could be implied, so searching for ".googlezip.net:" in the PAC script
+    // indicates whether there's a proxy in that PAC script with a host of the
+    // form "*.googlezip.net".
+    if (pac_script.find(".googlezip.net:") == std::string::npos)
+      return PROXY_PREF_NOT_CLEARED;
+
+    prefs->ClearPref(prefs::kProxy);
+    return PROXY_PREF_CLEARED_PAC_GOOGLEZIP;
+  }
+
+  return PROXY_PREF_NOT_CLEARED;
 }
 
 DataReductionProxyChromeSettings::DataReductionProxyChromeSettings()
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h
index c5cf8f1..350992c 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h
@@ -41,6 +41,7 @@
     PROXY_PREF_CLEARED_MODE_SYSTEM,
     PROXY_PREF_CLEARED_DRP,
     PROXY_PREF_CLEARED_GOOGLEZIP,
+    PROXY_PREF_CLEARED_PAC_GOOGLEZIP,
     PROXY_PREF_MAX
   };
 
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_unittest.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_unittest.cc
index a445898d..7bba517d 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_unittest.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_unittest.cc
@@ -65,8 +65,9 @@
   } test_cases[] = {
       // The pref should not be cleared if mode is unset.
       {nullptr, "http=compress.googlezip.net"},
-      // The pref should not be cleared for modes other than "fixed_servers".
-      {"pac_script", "http=compress.googlezip.net"},
+      // The pref should not be cleared for modes other than "fixed_servers" and
+      // "pac_script".
+      {"auto_detect", "http=compress.googlezip.net"},
       // The pref should not be cleared when the server field is unset.
       {"fixed_servers", nullptr},
   };
@@ -179,6 +180,115 @@
   }
 }
 
+TEST_F(DataReductionProxyChromeSettingsTest,
+       MigratePacGooglezipDataReductionProxy) {
+  const struct {
+    const char* pac_url;
+    bool expect_pref_cleared;
+  } test_cases[] = {
+      // PAC with bypass rules that returns 'HTTPS proxy.googlezip.net:443;
+      // PROXY compress.googlezip.net:80; DIRECT'.
+      {"data:application/"
+       "x-ns-proxy-autoconfig;base64,"
+       "ZnVuY3Rpb24gRmluZFByb3h5Rm9yVVJMKHVybCwgaG9zdCkgeyAgaWYgKChzaEV4cE1hdGN"
+       "oKHVybCwgJ2h0dHA6Ly93d3cuZ29vZ2xlLmNvbS9wb2xpY2llcy9wcml2YWN5KicpKSkgey"
+       "AgICByZXR1cm4gJ0RJUkVDVCc7ICB9ICAgaWYgKHVybC5zdWJzdHJpbmcoMCwgNSkgPT0gJ"
+       "2h0dHA6JykgeyAgICByZXR1cm4gJ0hUVFBTIHByb3h5Lmdvb2dsZXppcC5uZXQ6NDQzOyBQ"
+       "Uk9YWSBjb21wcmVzcy5nb29nbGV6aXAubmV0OjgwOyBESVJFQ1QnOyAgfSAgcmV0dXJuICd"
+       "ESVJFQ1QnO30=",
+       true},
+      // PAC with bypass rules that returns 'PROXY compress.googlezip.net:80;
+      // DIRECT'.
+      {"data:application/"
+       "x-ns-proxy-autoconfig;base64,"
+       "ZnVuY3Rpb24gRmluZFByb3h5Rm9yVVJMKHVybCwgaG9zdCkgeyAgaWYgKChzaEV4cE1hdGN"
+       "oKHVybCwgJ2h0dHA6Ly93d3cuZ29vZ2xlLmNvbS9wb2xpY2llcy9wcml2YWN5KicpKSkgey"
+       "AgICByZXR1cm4gJ0RJUkVDVCc7ICB9ICAgaWYgKHVybC5zdWJzdHJpbmcoMCwgNSkgPT0gJ"
+       "2h0dHA6JykgeyAgICByZXR1cm4gJ1BST1hZIGNvbXByZXNzLmdvb2dsZXppcC5uZXQ6ODA7"
+       "IERJUkVDVCc7ICB9ICByZXR1cm4gJ0RJUkVDVCc7fQ==",
+       true},
+      // PAC with bypass rules that returns 'PROXY proxy-dev.googlezip.net:80;
+      // DIRECT'.
+      {"data:application/"
+       "x-ns-proxy-autoconfig;base64,"
+       "ZnVuY3Rpb24gRmluZFByb3h5Rm9yVVJMKHVybCwgaG9zdCkgeyAgaWYgKChzaEV4cE1hdGN"
+       "oKHVybCwgJ2h0dHA6Ly93d3cuZ29vZ2xlLmNvbS9wb2xpY2llcy9wcml2YWN5KicpKSkgey"
+       "AgICByZXR1cm4gJ0RJUkVDVCc7ICB9ICAgaWYgKHVybC5zdWJzdHJpbmcoMCwgNSkgPT0gJ"
+       "2h0dHA6JykgeyAgICByZXR1cm4gJ1BST1hZIHByb3h5LWRldi5nb29nbGV6aXAubmV0Ojgw"
+       "OyBESVJFQ1QnOyAgfSAgcmV0dXJuICdESVJFQ1QnO30=",
+       true},
+      // Simple PAC that returns 'PROXY compress.googlezip.net:80'.
+      {"data:application/"
+       "x-ns-proxy-autoconfig;base64,"
+       "ZnVuY3Rpb24gRmluZFByb3h5Rm9yVVJMKHVybCwgaG9zdCkge3JldHVybiAnUFJPWFkgY29"
+       "tcHJlc3MuZ29vZ2xlemlwLm5ldDo4MCc7fQo=",
+       true},
+      // Simple PAC that returns 'PROXY compress.googlezip.net'. Note that since
+      // the port is not specified, the pref will not be cleared.
+      {"data:application/"
+       "x-ns-proxy-autoconfig;base64,"
+       "ZnVuY3Rpb24gRmluZFByb3h5Rm9yVVJMKHVybCwgaG9zdCkge3JldHVybiAnUFJPWFkgY29"
+       "tcHJlc3MuZ29vZ2xlemlwLm5ldCc7fQ==",
+       false},
+      // Simple PAC that returns 'PROXY mycustomdrp.net:80'.
+      {"data:application/"
+       "x-ns-proxy-autoconfig;base64,"
+       "ZnVuY3Rpb24gRmluZFByb3h5Rm9yVVJMKHVybCwgaG9zdCkge3JldHVybiAnUFJPWFkgb3J"
+       "pZ2luLm5ldDo4MCc7fQo=",
+       false},
+      // Simple PAC that returns 'PROXY myprefixgooglezip.net:80'.
+      {"data:application/"
+       "x-ns-proxy-autoconfig;base64,"
+       "ZnVuY3Rpb24gRmluZFByb3h5Rm9yVVJMKHVybCwgaG9zdCkge3JldHVybiAnUFJPWFkgbXl"
+       "wcmVmaXhnb29nbGV6aXAubmV0OjgwJzt9Cg==",
+       false},
+      // Simple PAC that returns 'PROXY compress.googlezip.net.mydomain.com:80'.
+      {"data:application/"
+       "x-ns-proxy-autoconfig;base64,"
+       "ZnVuY3Rpb24gRmluZFByb3h5Rm9yVVJMKHVybCwgaG9zdCkge3JldHVybiAnUFJPWFkgY29"
+       "tcHJlc3MuZ29vZ2xlemlwLm5ldC5teWRvbWFpbi5jb206ODAnO30K",
+       false},
+      // PAC URL that doesn't embed a script.
+      {"http://compress.googlezip.net/pac", false},
+  };
+
+  for (const auto& test : test_cases) {
+    base::HistogramTester histogram_tester;
+    dict_.reset(new base::DictionaryValue());
+    dict_->SetString("mode", "pac_script");
+    dict_->SetString("pac_url", test.pac_url);
+    test_context_->pref_service()->Set(prefs::kProxy, *dict_.get());
+    EXPECT_CALL(*config_, ContainsDataReductionProxy(_)).Times(0);
+
+    drp_chrome_settings_->MigrateDataReductionProxyOffProxyPrefs(
+        test_context_->pref_service());
+
+    if (test.expect_pref_cleared) {
+      EXPECT_EQ(NULL,
+                test_context_->pref_service()->GetUserPref(prefs::kProxy));
+      histogram_tester.ExpectUniqueSample(
+          "DataReductionProxy.ProxyPrefMigrationResult",
+          DataReductionProxyChromeSettings::PROXY_PREF_CLEARED_PAC_GOOGLEZIP,
+          1);
+    } else {
+      const base::DictionaryValue* value;
+      EXPECT_TRUE(test_context_->pref_service()
+                      ->GetUserPref(prefs::kProxy)
+                      ->GetAsDictionary(&value));
+      std::string mode;
+      EXPECT_TRUE(value->GetString("mode", &mode));
+      EXPECT_EQ("pac_script", mode);
+      std::string pac_url;
+      EXPECT_TRUE(value->GetString("pac_url", &pac_url));
+      EXPECT_EQ(test.pac_url, pac_url);
+
+      histogram_tester.ExpectUniqueSample(
+          "DataReductionProxy.ProxyPrefMigrationResult",
+          DataReductionProxyChromeSettings::PROXY_PREF_NOT_CLEARED, 1);
+    }
+  }
+}
+
 TEST_F(DataReductionProxyChromeSettingsTest, MigrateIgnoreOtherProxy) {
   const std::string kTestServers[] = {
       "http=https://youtube.com",
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc
index dfe7b00..d3f7461 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.cc
@@ -16,6 +16,7 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
 #include "jni/DataReductionProxySettings_jni.h"
 #include "net/proxy/proxy_server.h"
+#include "url/gurl.h"
 
 
 using base::android::ConvertUTF8ToJavaString;
@@ -49,9 +50,25 @@
   return Settings()->IsDataReductionProxyEnabled();
 }
 
-jboolean DataReductionProxySettingsAndroid::IsLoFiEnabled(
+jboolean DataReductionProxySettingsAndroid::CanUseDataReductionProxy(
+    JNIEnv* env, jobject obj, jstring url) {
+  return Settings()->CanUseDataReductionProxy(
+      GURL(base::android::ConvertJavaStringToUTF16(env, url)));
+}
+
+jboolean DataReductionProxySettingsAndroid::WasLoFiModeActiveOnMainFrame(
     JNIEnv* env, jobject obj) {
-  return Settings()->IsLoFiEnabled();
+  return Settings()->WasLoFiModeActiveOnMainFrame();
+}
+
+jboolean DataReductionProxySettingsAndroid::WasLoFiShowImageRequestedBefore(
+    JNIEnv* env, jobject obj) {
+  return Settings()->WasLoFiShowImageRequestedBefore();
+}
+
+void DataReductionProxySettingsAndroid::SetLoFiShowImageRequested(
+    JNIEnv* env, jobject obj) {
+  Settings()->SetLoFiShowImageRequested();
 }
 
 jboolean DataReductionProxySettingsAndroid::IsDataReductionProxyManaged(
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h
index 9293ac5..439c3a49 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h
@@ -38,7 +38,10 @@
   jboolean IsDataReductionProxyPromoAllowed(JNIEnv* env, jobject obj);
   jboolean IsIncludedInAltFieldTrial(JNIEnv* env, jobject obj);
   jboolean IsDataReductionProxyEnabled(JNIEnv* env, jobject obj);
-  jboolean IsLoFiEnabled(JNIEnv* env, jobject obj);
+  jboolean CanUseDataReductionProxy(JNIEnv* env, jobject obj, jstring url);
+  jboolean WasLoFiModeActiveOnMainFrame(JNIEnv* env, jobject obj);
+  jboolean WasLoFiShowImageRequestedBefore(JNIEnv* env, jobject obj);
+  void SetLoFiShowImageRequested(JNIEnv* env, jobject obj);
   jboolean IsDataReductionProxyManaged(JNIEnv* env, jobject obj);
   void SetDataReductionProxyEnabled(JNIEnv* env, jobject obj, jboolean enabled);
 
diff --git a/chrome/browser/net/ssl_config_service_manager_pref.cc b/chrome/browser/net/ssl_config_service_manager_pref.cc
index 9f15d31..f605079 100644
--- a/chrome/browser/net/ssl_config_service_manager_pref.cc
+++ b/chrome/browser/net/ssl_config_service_manager_pref.cc
@@ -119,6 +119,7 @@
 };
 
 void SSLConfigServicePref::GetSSLConfig(net::SSLConfig* config) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   *config = cached_config_;
 }
 
diff --git a/chrome/browser/notifications/desktop_notification_service.cc b/chrome/browser/notifications/desktop_notification_service.cc
index 8ef6cc9..78e9b9e3 100644
--- a/chrome/browser/notifications/desktop_notification_service.cc
+++ b/chrome/browser/notifications/desktop_notification_service.cc
@@ -14,10 +14,10 @@
 #include "chrome/browser/notifications/notification.h"
 #include "chrome/browser/notifications/notification_object_proxy.h"
 #include "chrome/browser/notifications/notification_ui_manager.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/pref_names.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/base/webui/web_ui_util.h"
diff --git a/chrome/browser/notifications/platform_notification_service_impl.cc b/chrome/browser/notifications/platform_notification_service_impl.cc
index cafd270..d1fb2b2e 100644
--- a/chrome/browser/notifications/platform_notification_service_impl.cc
+++ b/chrome/browser/notifications/platform_notification_service_impl.cc
@@ -392,6 +392,8 @@
 }
 
 // static
+// TODO(palmer): It might be good to replace this with a call to
+// |FormatUrlForSecurityDisplay|. crbug.com/496965
 base::string16 PlatformNotificationServiceImpl::WebOriginDisplayName(
     const GURL& origin,
     const std::string& languages) {
diff --git a/chrome/browser/permissions/permission_manager.cc b/chrome/browser/permissions/permission_manager.cc
index 858f5b2..e96e68e2 100644
--- a/chrome/browser/permissions/permission_manager.cc
+++ b/chrome/browser/permissions/permission_manager.cc
@@ -7,9 +7,9 @@
 #include "base/callback.h"
 #include "chrome/browser/content_settings/permission_context_base.h"
 #include "chrome/browser/permissions/permission_context.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "content/public/browser/permission_type.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
diff --git a/components/content_settings/core/common/permission_request_id.cc b/chrome/browser/permissions/permission_request_id.cc
similarity index 64%
rename from components/content_settings/core/common/permission_request_id.cc
rename to chrome/browser/permissions/permission_request_id.cc
index 7d7eccba..c78bb100 100644
--- a/components/content_settings/core/common/permission_request_id.cc
+++ b/chrome/browser/permissions/permission_request_id.cc
@@ -1,35 +1,39 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// 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/content_settings/core/common/permission_request_id.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 
 #include "base/strings/stringprintf.h"
 
 PermissionRequestID::PermissionRequestID(int render_process_id,
                                          int render_frame_id,
-                                         int bridge_id,
+                                         int request_id,
                                          const GURL& origin)
     : render_process_id_(render_process_id),
       render_frame_id_(render_frame_id),
-      bridge_id_(bridge_id),
+      request_id_(request_id),
       origin_(origin) {
 }
 
 PermissionRequestID::~PermissionRequestID() {
 }
 
-bool PermissionRequestID::Equals(const PermissionRequestID& other) const {
+bool PermissionRequestID::operator==(const PermissionRequestID& other) const {
   return render_process_id_ == other.render_process_id_ &&
          render_frame_id_ == other.render_frame_id_ &&
-         bridge_id_ == other.bridge_id_ &&
+         request_id_ == other.request_id_ &&
          origin_ == other.origin_;
 }
 
+bool PermissionRequestID::operator!=(const PermissionRequestID& other) const {
+  return !operator==(other);
+}
+
 std::string PermissionRequestID::ToString() const {
   return base::StringPrintf("%d,%d,%d,%s",
                             render_process_id_,
                             render_frame_id_,
-                            bridge_id_,
+                            request_id_,
                             origin_.spec().c_str());
 }
diff --git a/chrome/browser/permissions/permission_request_id.h b/chrome/browser/permissions/permission_request_id.h
new file mode 100644
index 0000000..4b567a7
--- /dev/null
+++ b/chrome/browser/permissions/permission_request_id.h
@@ -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.
+
+#ifndef CHROME_BROWSER_PERMISSIONS_PERMISSION_REQUEST_ID_H_
+#define CHROME_BROWSER_PERMISSIONS_PERMISSION_REQUEST_ID_H_
+
+#include <string>
+
+#include "url/gurl.h"
+
+// Uniquely identifies a particular permission request.
+// None of the different attribute (render_process_id, render_frame_id,
+// request_id or origin) is enough to compare two requests. In order to check if
+// a request is the same as another one, consumers of this class should use
+// the operator== or operator!=.
+class PermissionRequestID {
+ public:
+  PermissionRequestID(int render_process_id,
+                      int render_frame_id,
+                      int request_id,
+                      const GURL& origin);
+  ~PermissionRequestID();
+
+  PermissionRequestID(const PermissionRequestID&) = default;
+  PermissionRequestID& operator=(const PermissionRequestID&) = default;
+
+  int render_process_id() const { return render_process_id_; }
+  int render_frame_id() const { return render_frame_id_; }
+  int request_id() const { return request_id_; }
+  GURL origin() const { return origin_; }
+
+  bool operator==(const PermissionRequestID& other) const;
+  bool operator!=(const PermissionRequestID& other) const;
+
+  std::string ToString() const;
+
+ private:
+  int render_process_id_;
+  int render_frame_id_;
+  int request_id_;
+
+  // Needed for permission checks that are based on origin. It can be an empty
+  // GURL is the request isn't checking origin.
+  GURL origin_;
+};
+
+#endif  // CHROME_BROWSER_PERMISSIONS_PERMISSION_REQUEST_ID_H_
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 89acf320..32c83e5 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -2524,6 +2524,45 @@
   }
 }
 
+IN_PROC_BROWSER_TEST_F(PolicyTest, URLBlacklistSubresources) {
+  // Checks that an image with a blacklisted URL is loaded, but an iframe with a
+  // blacklisted URL is not.
+
+  GURL main_url = URLRequestMockHTTPJob::GetMockUrl(
+      base::FilePath(FILE_PATH_LITERAL("policy/blacklist-subresources.html")));
+  GURL image_url = URLRequestMockHTTPJob::GetMockUrl(
+      base::FilePath(FILE_PATH_LITERAL("policy/pixel.png")));
+  GURL subframe_url = URLRequestMockHTTPJob::GetMockUrl(
+      base::FilePath(FILE_PATH_LITERAL("policy/blank.html")));
+
+  // Set a blacklist containing the image and the iframe which are used by the
+  // main document.
+  base::ListValue blacklist;
+  blacklist.Append(new base::StringValue(image_url.spec().c_str()));
+  blacklist.Append(new base::StringValue(subframe_url.spec().c_str()));
+  PolicyMap policies;
+  policies.Set(key::kURLBlacklist, POLICY_LEVEL_MANDATORY,
+               POLICY_SCOPE_USER, blacklist.DeepCopy(), NULL);
+  UpdateProviderPolicy(policies);
+  FlushBlacklistPolicy();
+
+  std::string blacklisted_image_load_result;
+  ui_test_utils::NavigateToURL(browser(), main_url);
+  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
+      browser()->tab_strip_model()->GetActiveWebContents(),
+      "window.domAutomationController.send(imageLoadResult)",
+      &blacklisted_image_load_result));
+  EXPECT_EQ("success", blacklisted_image_load_result);
+
+  std::string blacklisted_iframe_load_result;
+  ui_test_utils::NavigateToURL(browser(), main_url);
+  ASSERT_TRUE(content::ExecuteScriptAndExtractString(
+      browser()->tab_strip_model()->GetActiveWebContents(),
+      "window.domAutomationController.send(iframeLoadResult)",
+      &blacklisted_iframe_load_result));
+  EXPECT_EQ("error", blacklisted_iframe_load_result);
+}
+
 #if defined(OS_MACOSX)
 // http://crbug.com/339240
 #define MAYBE_FileURLBlacklist DISABLED_FileURLBlacklist
@@ -2594,14 +2633,32 @@
   CheckURLIsBlocked(browser(), file_path2.c_str());
 }
 
-static bool IsMinSSLFallbackVersionTLS12(Profile* profile) {
-  scoped_refptr<net::SSLConfigService> config_service(
-      profile->GetSSLConfigService());
+namespace {
+
+void GetSSLVersionFallbackMinOnIOThread(
+    const scoped_refptr<net::SSLConfigService>& config_service,
+    uint16_t* version_fallback_min) {
   net::SSLConfig config;
   config_service->GetSSLConfig(&config);
-  return config.version_fallback_min == net::SSL_PROTOCOL_VERSION_TLS1_2;
+  *version_fallback_min = config.version_fallback_min;
 }
 
+uint16_t GetSSLVersionFallbackMin(Profile* profile) {
+  scoped_refptr<net::SSLConfigService> config_service(
+      profile->GetSSLConfigService());
+  uint16_t version_fallback_min;
+  base::RunLoop loop;
+  BrowserThread::PostTaskAndReply(
+      BrowserThread::IO, FROM_HERE,
+      base::Bind(&GetSSLVersionFallbackMinOnIOThread, config_service,
+                 base::Unretained(&version_fallback_min)),
+      loop.QuitClosure());
+  loop.Run();
+  return version_fallback_min;
+}
+
+}  // namespace
+
 IN_PROC_BROWSER_TEST_F(PolicyTest, SSLVersionFallbackMin) {
   PrefService* prefs = g_browser_process->local_state();
 
@@ -2610,7 +2667,8 @@
       prefs->GetString(prefs::kSSLVersionFallbackMin));
 
   EXPECT_NE(default_value, new_value);
-  EXPECT_FALSE(IsMinSSLFallbackVersionTLS12(browser()->profile()));
+  EXPECT_NE(net::SSL_PROTOCOL_VERSION_TLS1_2,
+            GetSSLVersionFallbackMin(browser()->profile()));
 
   PolicyMap policies;
   policies.Set(key::kSSLVersionFallbackMin,
@@ -2620,7 +2678,8 @@
                NULL);
   UpdateProviderPolicy(policies);
 
-  EXPECT_TRUE(IsMinSSLFallbackVersionTLS12(browser()->profile()));
+  EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_2,
+            GetSSLVersionFallbackMin(browser()->profile()));
 }
 
 #if !defined(OS_MACOSX)
diff --git a/chrome/browser/prefetch/prefetch_browsertest.cc b/chrome/browser/prefetch/prefetch_browsertest.cc
index 1e8c419..71cca09d 100644
--- a/chrome/browser/prefetch/prefetch_browsertest.cc
+++ b/chrome/browser/prefetch/prefetch_browsertest.cc
@@ -17,13 +17,14 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/base/network_change_notifier.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 
 using chrome_browser_net::NetworkPredictionOptions;
 using net::NetworkChangeNotifier;
 
 namespace {
 
-const char kPrefetchPage[] = "files/prerender/simple_prefetch.html";
+const char kPrefetchPage[] = "/prerender/simple_prefetch.html";
 
 class MockNetworkChangeNotifierWIFI : public NetworkChangeNotifier {
  public:
@@ -51,13 +52,18 @@
     }
   }
 
+  void SetUpOnMainThread() override {
+    ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+    InProcessBrowserTest::SetUpOnMainThread();
+  }
+
   void SetPreference(NetworkPredictionOptions value) {
     browser()->profile()->GetPrefs()->SetInteger(
         prefs::kNetworkPredictionOptions, value);
   }
 
   bool RunPrefetchExperiment(bool expect_success, Browser* browser) {
-    GURL url = test_server()->GetURL(kPrefetchPage);
+    GURL url = embedded_test_server()->GetURL(kPrefetchPage);
 
     const base::string16 expected_title =
         expect_success ? base::ASCIIToUTF16("link onload")
@@ -85,7 +91,6 @@
 // Prefetch is disabled via field experiment.  Prefetch should be dropped.
 IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPredictionDisabled,
                        ExperimentDisabled) {
-  CHECK(test_server()->Start());
   EXPECT_TRUE(RunPrefetchExperiment(false, browser()));
   // Should not prefetch even if preference is ALWAYS.
   SetPreference(NetworkPredictionOptions::NETWORK_PREDICTION_ALWAYS);
@@ -94,7 +99,6 @@
 
 // Prefetch should be allowed depending on preference and network type.
 IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPrediction, PreferenceWorks) {
-  CHECK(test_server()->Start());
   // Set real NetworkChangeNotifier singleton aside.
   scoped_ptr<NetworkChangeNotifier::DisableForTest> disable_for_test(
       new NetworkChangeNotifier::DisableForTest);
@@ -143,7 +147,6 @@
   // WebContents for the incognito browser.
   ui_test_utils::OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
 
-  CHECK(test_server()->Start());
   EXPECT_TRUE(RunPrefetchExperiment(true, incognito_browser));
 }
 
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 8053a30a..c81efd44 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -60,6 +60,7 @@
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/task_manager/task_manager.h"
+#include "chrome/browser/tracing/chrome_tracing_delegate.h"
 #include "chrome/browser/ui/app_list/app_list_prefs.h"
 #include "chrome/browser/ui/app_list/app_list_service.h"
 #include "chrome/browser/ui/browser_ui_prefs.h"
@@ -244,6 +245,7 @@
   browser_shutdown::RegisterPrefs(registry);
   BrowserProcessImpl::RegisterPrefs(registry);
   ChromeMetricsServiceClient::RegisterPrefs(registry);
+  ChromeTracingDelegate::RegisterPrefs(registry);
   chrome_prefs::RegisterPrefs(registry);
   chrome_variations::VariationsService::RegisterPrefs(registry);
   component_updater::RegisterPrefsForRecoveryComponent(registry);
diff --git a/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc b/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc
index c9cd628..766693a 100644
--- a/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc
+++ b/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc
@@ -307,7 +307,7 @@
   void SetUp() override;
   void TearDown() override;
 
-  scoped_refptr<base::MessageLoopProxy> IOMessageLoopProxy() {
+  scoped_refptr<base::SingleThreadTaskRunner> IOTaskRunner() {
     return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
   }
   base::Process Launch(const std::string& name);
@@ -442,7 +442,7 @@
   startup_channel_ = IPC::ChannelProxy::Create(startup_channel_id_,
                                                IPC::Channel::MODE_SERVER,
                                                this,
-                                               IOMessageLoopProxy());
+                                               IOTaskRunner());
 
 #if defined(OS_POSIX)
   base::FileHandleMappingVector ipc_file_list;
@@ -467,7 +467,7 @@
       IPC::ChannelProxy::Create(GetServiceProcessChannel(),
                                 IPC::Channel::MODE_NAMED_CLIENT,
                                 ServiceProcessControl::GetInstance(),
-                                IOMessageLoopProxy()));
+                                IOTaskRunner()));
 }
 
 bool CloudPrintProxyPolicyStartupTest::Send(IPC::Message* message) {
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 6c5b708..e6251781 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -456,7 +456,7 @@
       &force_youtube_safety_mode_,
       pref_service);
 
-  scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy =
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
 
   chrome_http_user_agent_settings_.reset(
@@ -467,25 +467,25 @@
   if (!IsOffTheRecord()) {
     google_services_user_account_id_.Init(
         prefs::kGoogleServicesUserAccountId, pref_service);
-    google_services_user_account_id_.MoveToThread(io_message_loop_proxy);
+    google_services_user_account_id_.MoveToThread(io_task_runner);
 
     sync_disabled_.Init(sync_driver::prefs::kSyncManaged, pref_service);
-    sync_disabled_.MoveToThread(io_message_loop_proxy);
+    sync_disabled_.MoveToThread(io_task_runner);
 
     signin_allowed_.Init(prefs::kSigninAllowed, pref_service);
-    signin_allowed_.MoveToThread(io_message_loop_proxy);
+    signin_allowed_.MoveToThread(io_task_runner);
   }
 
   quick_check_enabled_.Init(prefs::kQuickCheckEnabled,
                             local_state_pref_service);
-  quick_check_enabled_.MoveToThread(io_message_loop_proxy);
+  quick_check_enabled_.MoveToThread(io_task_runner);
 
   media_device_id_salt_ = new MediaDeviceIDSalt(pref_service, IsOffTheRecord());
 
   network_prediction_options_.Init(prefs::kNetworkPredictionOptions,
                                    pref_service);
 
-  network_prediction_options_.MoveToThread(io_message_loop_proxy);
+  network_prediction_options_.MoveToThread(io_task_runner);
 
 #if defined(OS_CHROMEOS)
   scoped_ptr<policy::PolicyCertVerifier> verifier =
@@ -505,28 +505,24 @@
   base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
   scoped_refptr<base::SequencedTaskRunner> background_task_runner =
       pool->GetSequencedTaskRunner(pool->GetSequenceToken());
-  url_blacklist_manager_.reset(
-      new policy::URLBlacklistManager(
-          pref_service,
-          background_task_runner,
-          io_message_loop_proxy,
-          callback,
-          base::Bind(policy::OverrideBlacklistForURL)));
+  url_blacklist_manager_.reset(new policy::URLBlacklistManager(
+      pref_service, background_task_runner, io_task_runner, callback,
+      base::Bind(policy::OverrideBlacklistForURL)));
 
   if (!IsOffTheRecord()) {
     // Add policy headers for non-incognito requests.
     policy::PolicyHeaderService* policy_header_service =
         policy::PolicyHeaderServiceFactory::GetForBrowserContext(profile);
     if (policy_header_service) {
-      policy_header_helper_ = policy_header_service->CreatePolicyHeaderIOHelper(
-          io_message_loop_proxy);
+      policy_header_helper_ =
+          policy_header_service->CreatePolicyHeaderIOHelper(io_task_runner);
     }
   }
 #endif
 
   incognito_availibility_pref_.Init(
       prefs::kIncognitoModeAvailability, pref_service);
-  incognito_availibility_pref_.MoveToThread(io_message_loop_proxy);
+  incognito_availibility_pref_.MoveToThread(io_task_runner);
 
   initialized_on_UI_thread_ = true;
 
diff --git a/chrome/browser/push_messaging/push_messaging_browsertest.cc b/chrome/browser/push_messaging/push_messaging_browsertest.cc
index 94afec49..a9acc332 100644
--- a/chrome/browser/push_messaging/push_messaging_browsertest.cc
+++ b/chrome/browser/push_messaging/push_messaging_browsertest.cc
@@ -27,6 +27,8 @@
 #include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/website_settings/permission_bubble_manager.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/content_settings/core/browser/host_content_settings_map.h"
@@ -69,7 +71,8 @@
 
 }  // namespace
 
-class PushMessagingBrowserTest : public InProcessBrowserTest {
+class PushMessagingBrowserTest : public InProcessBrowserTest,
+                                 public testing::WithParamInterface<bool> {
  public:
   PushMessagingBrowserTest() : gcm_service_(nullptr) {}
   ~PushMessagingBrowserTest() override {}
@@ -78,6 +81,14 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitch(switches::kEnablePushMessagePayload);
 
+    if (GetParam()) {
+      command_line->AppendSwitch(switches::kEnablePermissionsBubbles);
+      EXPECT_TRUE(PermissionBubbleManager::Enabled());
+    } else {
+      command_line->AppendSwitch(switches::kDisablePermissionsBubbles);
+      EXPECT_FALSE(PermissionBubbleManager::Enabled());
+    }
+
     InProcessBrowserTest::SetUpCommandLine(command_line);
   }
 
@@ -143,6 +154,14 @@
                                                   result);
   }
 
+  PermissionBubbleManager* GetPermissionBubbleManager() {
+    return PermissionBubbleManager::FromWebContents(
+        GetBrowser()->tab_strip_model()->GetActiveWebContents());
+  }
+
+  void RequestAndAcceptPermission();
+  void RequestAndDenyPermission();
+
   void TryToSubscribeSuccessfully(
       const std::string& expected_push_subscription_id);
 
@@ -216,6 +235,34 @@
   }
 };
 
+void PushMessagingBrowserTest::RequestAndAcceptPermission() {
+  std::string script_result;
+
+  if (PermissionBubbleManager::Enabled()) {
+    GetPermissionBubbleManager()->set_auto_response_for_test(
+        PermissionBubbleManager::ACCEPT_ALL);
+    EXPECT_TRUE(RunScript("requestNotificationPermission();", &script_result));
+  } else {
+    InfoBarResponder infobar_accept_responder(GetInfoBarService(), true);
+    EXPECT_TRUE(RunScript("requestNotificationPermission();", &script_result));
+  }
+  EXPECT_EQ("permission status - granted", script_result);
+}
+
+void PushMessagingBrowserTest::RequestAndDenyPermission() {
+  std::string script_result;
+
+  if (PermissionBubbleManager::Enabled()) {
+    GetPermissionBubbleManager()->set_auto_response_for_test(
+        PermissionBubbleManager::DENY_ALL);
+    EXPECT_TRUE(RunScript("requestNotificationPermission();", &script_result));
+  } else {
+    InfoBarResponder infobar_deny_responder(GetInfoBarService(), false);
+    EXPECT_TRUE(RunScript("requestNotificationPermission();", &script_result));
+  }
+  EXPECT_EQ("permission status - denied", script_result);
+}
+
 void PushMessagingBrowserTest::TryToSubscribeSuccessfully(
     const std::string& expected_push_subscription_id) {
   std::string script_result;
@@ -223,9 +270,7 @@
   EXPECT_TRUE(RunScript("registerServiceWorker()", &script_result));
   EXPECT_EQ("ok - service worker registered", script_result);
 
-  InfoBarResponder accepting_responder(GetInfoBarService(), true);
-  EXPECT_TRUE(RunScript("requestNotificationPermission()", &script_result));
-  EXPECT_EQ("permission status - granted", script_result);
+  RequestAndAcceptPermission();
 
   EXPECT_TRUE(RunScript("subscribePush()", &script_result));
   EXPECT_EQ(GetEndpointForSubscriptionId(expected_push_subscription_id),
@@ -252,7 +297,7 @@
   run_loop.Run();
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest,
                        SubscribeSuccessNotificationsGranted) {
   TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
 
@@ -262,17 +307,22 @@
   EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest,
                        SubscribeSuccessNotificationsPrompt) {
   std::string script_result;
 
   ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
   ASSERT_EQ("ok - service worker registered", script_result);
 
-  InfoBarResponder accepting_responder(GetInfoBarService(), true);
-  ASSERT_TRUE(RunScript("subscribePush()", &script_result));
-  EXPECT_EQ(GetEndpointForSubscriptionId("1-0"),
-            script_result);
+  if (PermissionBubbleManager::Enabled()) {
+    GetPermissionBubbleManager()->set_auto_response_for_test(
+        PermissionBubbleManager::ACCEPT_ALL);
+    ASSERT_TRUE(RunScript("subscribePush()", &script_result));
+  } else {
+    InfoBarResponder infobar_accept_responder(GetInfoBarService(), true);
+    ASSERT_TRUE(RunScript("subscribePush()", &script_result));
+  }
+  EXPECT_EQ(GetEndpointForSubscriptionId("1-0"), script_result);
 
   PushMessagingAppIdentifier app_identifier =
       GetAppIdentifierForServiceWorkerRegistration(0LL);
@@ -280,31 +330,27 @@
   EXPECT_EQ("1234567890", gcm_service()->last_registered_sender_ids()[0]);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest,
                        SubscribeFailureNotificationsBlocked) {
   std::string script_result;
 
   ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
   ASSERT_EQ("ok - service worker registered", script_result);
 
-  InfoBarResponder cancelling_responder(GetInfoBarService(), false);
-  ASSERT_TRUE(RunScript("requestNotificationPermission();", &script_result));
-  ASSERT_EQ("permission status - denied", script_result);
+  RequestAndDenyPermission();
 
   ASSERT_TRUE(RunScript("subscribePush()", &script_result));
   EXPECT_EQ("AbortError - Registration failed - permission denied",
             script_result);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, SubscribeFailureNoManifest) {
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest, SubscribeFailureNoManifest) {
   std::string script_result;
 
   ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
   ASSERT_EQ("ok - service worker registered", script_result);
 
-  InfoBarResponder accepting_responder(GetInfoBarService(), true);
-  ASSERT_TRUE(RunScript("requestNotificationPermission();", &script_result));
-  ASSERT_EQ("permission status - granted", script_result);
+  RequestAndAcceptPermission();
 
   ASSERT_TRUE(RunScript("removeManifest()", &script_result));
   ASSERT_EQ("manifest removed", script_result);
@@ -316,23 +362,21 @@
 
 // TODO(johnme): Test subscribing from a worker - see https://crbug.com/437298.
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTestEmptySubscriptionOptions,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTestEmptySubscriptionOptions,
                        RegisterFailureEmptyPushSubscriptionOptions) {
   std::string script_result;
 
   ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
   ASSERT_EQ("ok - service worker registered", script_result);
 
-  InfoBarResponder accepting_responder(GetInfoBarService(), true);
-  ASSERT_TRUE(RunScript("requestNotificationPermission();", &script_result));
-  ASSERT_EQ("permission status - granted", script_result);
+  RequestAndAcceptPermission();
 
   ASSERT_TRUE(RunScript("subscribePush()", &script_result));
   EXPECT_EQ("AbortError - Registration failed - permission denied",
             script_result);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, SubscribePersisted) {
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest, SubscribePersisted) {
   std::string script_result;
 
   // First, test that Service Worker registration IDs are assigned in order of
@@ -389,7 +433,7 @@
   EXPECT_EQ(sw1_identifier.app_id(), gcm_service()->last_registered_app_id());
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushEventSuccess) {
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest, PushEventSuccess) {
   std::string script_result;
 
   TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
@@ -415,7 +459,7 @@
   EXPECT_EQ("testdata", script_result);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PushEventNoServiceWorker) {
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest, PushEventNoServiceWorker) {
   std::string script_result;
 
   TryToSubscribeSuccessfully("1-0" /* expected_push_subscription_id */);
@@ -457,7 +501,7 @@
 }
 
 #if defined(ENABLE_NOTIFICATIONS)
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest,
                        PushEventEnforcesUserVisibleNotification) {
   std::string script_result;
 
@@ -563,7 +607,7 @@
   EXPECT_EQ(0u, notification_manager()->GetNotificationCount());
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest,
                        PushEventEnforcesUserVisibleNotificationAfterQueue) {
   std::string script_result;
 
@@ -615,7 +659,7 @@
   EXPECT_EQ(1u, number_of_notifications_shown[1]);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest,
                        PushEventNotificationWithoutEventWaitUntil) {
   std::string script_result;
   content::WebContents* web_contents =
@@ -660,7 +704,7 @@
 }
 #endif
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PermissionStateSaysPrompt) {
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest, PermissionStateSaysPrompt) {
   std::string script_result;
 
   ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
@@ -670,15 +714,13 @@
   ASSERT_EQ("permission status - prompt", script_result);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PermissionStateSaysGranted) {
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest, PermissionStateSaysGranted) {
   std::string script_result;
 
   ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
   ASSERT_EQ("ok - service worker registered", script_result);
 
-  InfoBarResponder accepting_responder(GetInfoBarService(), true);
-  ASSERT_TRUE(RunScript("requestNotificationPermission();", &script_result));
-  EXPECT_EQ("permission status - granted", script_result);
+  RequestAndAcceptPermission();
 
   ASSERT_TRUE(RunScript("subscribePush()", &script_result));
   EXPECT_EQ(GetEndpointForSubscriptionId("1-0"),
@@ -688,15 +730,13 @@
   EXPECT_EQ("permission status - granted", script_result);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, PermissionStateSaysDenied) {
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest, PermissionStateSaysDenied) {
   std::string script_result;
 
   ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
   ASSERT_EQ("ok - service worker registered", script_result);
 
-  InfoBarResponder cancelling_responder(GetInfoBarService(), false);
-  ASSERT_TRUE(RunScript("requestNotificationPermission();", &script_result));
-  EXPECT_EQ("permission status - denied", script_result);
+  RequestAndDenyPermission();
 
   ASSERT_TRUE(RunScript("subscribePush()", &script_result));
   EXPECT_EQ("AbortError - Registration failed - permission denied",
@@ -706,7 +746,7 @@
   EXPECT_EQ("permission status - denied", script_result);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest, UnsubscribeSuccess) {
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest, UnsubscribeSuccess) {
   std::string script_result;
 
   EXPECT_TRUE(RunScript("registerServiceWorker()", &script_result));
@@ -748,7 +788,7 @@
   EXPECT_EQ("unsubscribe result: false", script_result);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest,
                        GlobalResetPushPermissionUnsubscribes) {
   std::string script_result;
 
@@ -777,7 +817,7 @@
   EXPECT_EQ("false - not subscribed", script_result);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest,
                        LocalResetPushPermissionUnsubscribes) {
   std::string script_result;
 
@@ -811,7 +851,7 @@
   EXPECT_EQ("false - not subscribed", script_result);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest,
                        DenyPushPermissionUnsubscribes) {
   std::string script_result;
 
@@ -845,7 +885,7 @@
   EXPECT_EQ("false - not subscribed", script_result);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest,
                        GlobalResetNotificationsPermissionUnsubscribes) {
   std::string script_result;
 
@@ -874,7 +914,7 @@
   EXPECT_EQ("false - not subscribed", script_result);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest,
                        LocalResetNotificationsPermissionUnsubscribes) {
   std::string script_result;
 
@@ -908,7 +948,7 @@
   EXPECT_EQ("false - not subscribed", script_result);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest,
                        DenyNotificationsPermissionUnsubscribes) {
   std::string script_result;
 
@@ -942,7 +982,7 @@
   EXPECT_EQ("false - not subscribed", script_result);
 }
 
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest,
                        GrantAlreadyGrantedPermissionDoesNotUnsubscribe) {
   std::string script_result;
 
@@ -986,7 +1026,7 @@
 // that they are respected with regards to automatic unsubscription. In other
 // words, it checks that the push service does not end up unsubscribing origins
 // that have push permission with some non-common rules.
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest,
                        AutomaticUnsubscriptionFollowsContentSettingRules) {
   std::string script_result;
 
@@ -1045,7 +1085,7 @@
 
 // Checks that automatically unsubscribing due to a revoked permission is
 // handled well if the sender ID needed to unsubscribe was already deleted.
-IN_PROC_BROWSER_TEST_F(PushMessagingBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingBrowserTest,
                        ResetPushPermissionAfterClearingSiteData) {
   std::string script_result;
 
@@ -1104,7 +1144,7 @@
 };
 
 // Regression test for https://crbug.com/476474
-IN_PROC_BROWSER_TEST_F(PushMessagingIncognitoBrowserTest,
+IN_PROC_BROWSER_TEST_P(PushMessagingIncognitoBrowserTest,
                        IncognitoGetSubscriptionDoesNotHang) {
   ASSERT_TRUE(GetBrowser()->profile()->IsOffTheRecord());
 
@@ -1118,3 +1158,10 @@
   ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
   ASSERT_EQ("false - not subscribed", script_result);
 }
+
+INSTANTIATE_TEST_CASE_P(PushMessagingBrowserTestWithParams,
+                        PushMessagingBrowserTest,
+                        testing::Values(true, false));
+INSTANTIATE_TEST_CASE_P(PushMessagingIncognitoBrowserTestWithParams,
+                        PushMessagingIncognitoBrowserTest,
+                        testing::Values(true, false));
diff --git a/chrome/browser/push_messaging/push_messaging_permission_context.cc b/chrome/browser/push_messaging/push_messaging_permission_context.cc
index 9a7530f..d29f5c3 100644
--- a/chrome/browser/push_messaging/push_messaging_permission_context.cc
+++ b/chrome/browser/push_messaging/push_messaging_permission_context.cc
@@ -7,9 +7,9 @@
 #include "chrome/browser/content_settings/permission_context_uma_util.h"
 #include "chrome/browser/notifications/desktop_notification_service.h"
 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
diff --git a/chrome/browser/push_messaging/push_messaging_permission_context_unittest.cc b/chrome/browser/push_messaging/push_messaging_permission_context_unittest.cc
index 57e9372..8c351c28 100644
--- a/chrome/browser/push_messaging/push_messaging_permission_context_unittest.cc
+++ b/chrome/browser/push_messaging/push_messaging_permission_context_unittest.cc
@@ -3,11 +3,12 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/push_messaging/push_messaging_permission_context.h"
+
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/push_messaging/push_messaging_service_impl.cc b/chrome/browser/push_messaging/push_messaging_service_impl.cc
index bf03560..2844864 100644
--- a/chrome/browser/push_messaging/push_messaging_service_impl.cc
+++ b/chrome/browser/push_messaging/push_messaging_service_impl.cc
@@ -14,6 +14,7 @@
 #include "base/metrics/histogram.h"
 #include "base/prefs/pref_service.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/permissions/permission_request_id.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
 #include "chrome/browser/push_messaging/push_messaging_constants.h"
@@ -25,7 +26,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
-#include "components/content_settings/core/common/permission_request_id.h"
 #include "components/gcm_driver/gcm_driver.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/rappor/rappor_utils.h"
@@ -349,9 +349,10 @@
 
   // TODO(miguelg) need to send this over IPC when bubble support is
   // implemented.
-  int bridge_id = -1;
+  int request_id = -1;
 
-  const PermissionRequestID id(renderer_id, render_frame_id, bridge_id, GURL());
+  const PermissionRequestID id(
+      renderer_id, render_frame_id, request_id, GURL());
 
   PushMessagingPermissionContext* permission_context =
       PushMessagingPermissionContextFactory::GetForProfile(profile_);
diff --git a/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js b/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js
index 70ba10a..4506a107 100644
--- a/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js
+++ b/chrome/browser/resources/chromeos/chromevox/common/chrome_extension_externs.js
@@ -404,17 +404,45 @@
 
 
 /**
- * @type {{
- *     name: string,
- *     url: string,
- *     value: string,
- *     textSelStart: number,
- *     textSelEnd: number,
- *     wordStarts: Array<number>,
- *     wordEnds: Array<number>
- * }}
+ * @type {string}
  */
-chrome.automation.AutomationNode.prototype.attributes;
+chrome.automation.AutomationNode.prototype.name;
+
+
+/**
+ * @type {string}
+ */
+chrome.automation.AutomationNode.prototype.url;
+
+
+/**
+ * @type {string}
+ */
+chrome.automation.AutomationNode.prototype.value;
+
+
+/**
+ * @type {number}
+ */
+chrome.automation.AutomationNode.prototype.textSelStart;
+
+
+/**
+ * @type {number}
+ */
+chrome.automation.AutomationNode.prototype.textSelEnd;
+
+
+/**
+ * @type {Array<number>}
+ */
+chrome.automation.AutomationNode.prototype.wordStarts;
+
+
+/**
+ * @type {Array<number>}
+ */
+chrome.automation.AutomationNode.prototype.wordEnds;
 
 
 /**
@@ -516,6 +544,10 @@
 
 chrome.automation.AutomationNode.prototype.focus = function() {};
 
+
+chrome.automation.AutomationNode.prototype.showContextMenu = function() {};
+
+
 /** @type {string} */
 chrome.automation.AutomationNode.prototype.containerLiveStatus;
 
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
index 9dedefa..5e8aace 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
@@ -143,7 +143,7 @@
  */
 AutomationPredicate.leafWithText = function(node) {
   return AutomationPredicate.leaf(node) &&
-      !!(node.attributes.name || node.attributes.value);
+      !!(node.name || node.value);
 };
 
 /**
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
index b1982b1..8d988b5 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
@@ -302,6 +302,15 @@
 
         continueReading(null);
         return;
+      case 'showContextMenu':
+        if (this.currentRange_) {
+          var actionNode = this.currentRange_.getStart().getNode();
+          if (actionNode.role == chrome.automation.RoleType.inlineTextBox)
+            actionNode = actionNode.parent;
+          actionNode.showContextMenu();
+          return;
+        }
+        break;
     }
 
     if (pred) {
@@ -347,7 +356,7 @@
     if (!prevRange ||
         (prevRange.getStart().getNode().root != node.root &&
          node.root.focused))
-      this.setupChromeVoxVariants_(node.root.attributes.url || '');
+      this.setupChromeVoxVariants_(node.root.docUrl || '');
 
     // Don't process nodes inside of web content if ChromeVox Next is inactive.
     if (node.root.role != chrome.automation.RoleType.desktop &&
@@ -366,7 +375,7 @@
    * @param {Object} evt
    */
   onLoadComplete: function(evt) {
-    this.setupChromeVoxVariants_(evt.target.attributes.url);
+    this.setupChromeVoxVariants_(evt.target.docUrl);
 
     // Don't process nodes inside of web content if ChromeVox Next is inactive.
     if (evt.target.root.role != chrome.automation.RoleType.desktop &&
@@ -416,9 +425,9 @@
     }
 
     var textChangeEvent = new cvox.TextChangeEvent(
-        evt.target.attributes.value,
-        evt.target.attributes.textSelStart,
-        evt.target.attributes.textSelEnd,
+        evt.target.value,
+        evt.target.textSelStart,
+        evt.target.textSelEnd,
         true);  // triggered by user
     if (!this.editableTextHandler ||
         evt.target != this.currentRange_.getStart().getNode()) {
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
index 1afd0a2..867cf14 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
@@ -200,7 +200,21 @@
     function(rootNode) {
       var go = rootNode.find({ role: chrome.automation.RoleType.button });
       go.doDefault();
-      cvox.ChromeVox.tts.expectSpeech('removed: Hello, world', testDone);
+      cvox.ChromeVox.tts.expectSpeech('removed:');
+      cvox.ChromeVox.tts.expectSpeech('Hello, world', testDone);
       cvox.ChromeVox.tts.finishExpectations();
     }.bind(this));
 });
+
+TEST_F('BackgroundTest', 'ShowContextMenu', function() {
+  this.runWithLoadedTree('<a href="a">a</a>',
+    function(rootNode) {
+      cvox.ChromeVox.tts.expectSpeech(' menu opened', testDone);
+
+      var go = rootNode.find({ role: chrome.automation.RoleType.link });
+      go.addEventListener('focus', function(e) {
+        this.doCmd('showContextMenu')();
+      }.bind(this), true);
+      go.focus();
+    }.bind(this));
+});
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
index 82c0d5d..ac43bd70 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
@@ -119,7 +119,7 @@
    */
   getText: function(opt_node) {
     var node = opt_node || this.node_;
-    return node.attributes.name || node.attributes.value || '';
+    return node.name || node.value || '';
   },
 
   /**
@@ -158,11 +158,11 @@
           case Movement.BOUND:
             if (newNode.role == Role.inlineTextBox) {
               var start, end;
-              for (var i = 0; i < newNode.attributes.wordStarts.length; i++) {
-                if (newIndex >= newNode.attributes.wordStarts[i] &&
-                    newIndex <= newNode.attributes.wordEnds[i]) {
-                  start = newNode.attributes.wordStarts[i];
-                  end = newNode.attributes.wordEnds[i];
+              for (var i = 0; i < newNode.wordStarts.length; i++) {
+                if (newIndex >= newNode.wordStarts[i] &&
+                    newIndex <= newNode.wordEnds[i]) {
+                  start = newNode.wordStarts[i];
+                  end = newNode.wordEnds[i];
                   break;
                 }
               }
@@ -175,12 +175,12 @@
           case Movement.DIRECTIONAL:
             if (newNode.role == Role.inlineTextBox) {
               var start, end;
-              for (var i = 0; i < newNode.attributes.wordStarts.length; i++) {
-                if (newIndex >= newNode.attributes.wordStarts[i] &&
-                    newIndex <= newNode.attributes.wordEnds[i]) {
+              for (var i = 0; i < newNode.wordStarts.length; i++) {
+                if (newIndex >= newNode.wordStarts[i] &&
+                    newIndex <= newNode.wordEnds[i]) {
                   var nextIndex = dir == Dir.FORWARD ? i + 1 : i - 1;
-                  start = newNode.attributes.wordStarts[nextIndex];
-                  end = newNode.attributes.wordEnds[nextIndex];
+                  start = newNode.wordStarts[nextIndex];
+                  end = newNode.wordEnds[nextIndex];
                   break;
                 }
               }
@@ -197,7 +197,7 @@
                     newIndex = 0;
                     if (dir == Dir.BACKWARD &&
                         newNode.role == Role.inlineTextBox) {
-                      var starts = newNode.attributes.wordStarts;
+                      var starts = newNode.wordStarts;
                       newIndex = starts[starts.length - 1] || 0;
                     } else {
                       // TODO(dtseng): Figure out what to do for general nodes.
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
index 6577fdc..6a0affb6 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
@@ -87,7 +87,7 @@
     if (goog.isDef(expected.index))
       assertEquals(expected.index, cursor.getIndex());
     if (goog.isDef(expected.value))
-      assertEquals(expected.value, cursor.getNode().attributes.value);
+      assertEquals(expected.value, cursor.getNode().value);
   },
 
   /**
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
index 00114bcf..b34e176 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
@@ -32,9 +32,7 @@
  * The format of these rules is as follows.
  *
  * $ prefix: used to substitute either an attribute or a specialized value from
- *     an AutomationNode. Specialized values include role and state. Attributes
- *     available for substitution are AutomationNode.prototype.attributes and
- *     AutomationNode.prototype.state.
+ *     an AutomationNode. Specialized values include role and state.
  *     For example, $value $role $enabled
  * @ prefix: used to substitute a message. Note the ability to specify params to
  *     the message.  For example, '@tag_html' '@selected_index($text_sel_start,
@@ -764,12 +762,12 @@
       // All possible tokens based on prefix.
       if (prefix == '$') {
         if (token == 'value') {
-          var text = node.attributes.value;
+          var text = node.value;
           if (text !== undefined) {
-            if (node.attributes.textSelStart !== undefined) {
+            if (node.textSelStart !== undefined) {
               options.annotation.push(new Output.SelectionSpan(
-                  node.attributes.textSelStart,
-                  node.attributes.textSelEnd));
+                  node.textSelStart,
+                  node.textSelEnd));
             }
           }
           // Annotate this as a name so we don't duplicate names from ancestors.
@@ -789,7 +787,7 @@
             }
             earconFinder = earconFinder.parent;
           }
-          this.append_(buff, node.attributes.name, options);
+          this.append_(buff, node.name, options);
         } else if (token == 'nameOrDescendants') {
           options.annotation.push(token);
           if (node.name)
@@ -852,15 +850,15 @@
           this.append_(buff, msg, options);
         } else if (token == 'tableRowIndex' ||
             token == 'tableCellColumnIndex') {
-          var value = node.attributes[token];
+          var value = node[token];
           if (!value)
             return;
           value = String(value + 1);
           options.annotation.push(token);
           this.append_(buff, value, options);
-        } else if (node.attributes[token] !== undefined) {
+        } else if (node[token] !== undefined) {
           options.annotation.push(token);
-          var value = node.attributes[token];
+          var value = node[token];
           if (typeof value == 'number')
             value = String(value);
           this.append_(buff, value, options);
@@ -888,7 +886,7 @@
           if (token == 'if') {
             var cond = tree.firstChild;
             var attrib = cond.value.slice(1);
-            if (node.attributes[attrib] || node.state[attrib])
+            if (node[attrib] || node.state[attrib])
               this.format_(node, cond.nextSibling, buff);
             else
               this.format_(node, cond.nextSibling.nextSibling, buff);
@@ -914,7 +912,7 @@
         token = pieces.reduce(function(prev, cur) {
           var lookup = cur;
           if (cur[0] == '$')
-            lookup = node.attributes[cur.slice(1)];
+            lookup = node[cur.slice(1)];
           return prev + lookup;
         }.bind(this), '');
         var msgId = token;
diff --git a/chrome/browser/resources/chromeos/chromevox/host/chrome/mathjax.js b/chrome/browser/resources/chromeos/chromevox/host/chrome/mathjax.js
index 79b84820..a9f4156 100644
--- a/chrome/browser/resources/chromeos/chromevox/host/chrome/mathjax.js
+++ b/chrome/browser/resources/chromeos/chromevox/host/chrome/mathjax.js
@@ -24,6 +24,13 @@
   goog.base(this);
 
   /**
+   * Set to when the bridge is initialized.
+   * @type {boolean}
+   * @private
+   */
+  this.initialized_ = false;
+
+  /**
    * The port to communicate with the content script.
    * @type {Port}
    */
@@ -95,7 +102,7 @@
       'chromevox/injected/mathjax_external_util.js'));
   scripts.push(cvox.ChromeVox.host.getFileSrc('chromevox/injected/mathjax.js'));
   scripts.push(cvox.ApiImplementation.siteSpecificScriptLoader);
-  cvox.ScriptInstaller.installScript(
+  this.initialized_ = cvox.ScriptInstaller.installScript(
       scripts, 'mathjax', undefined,
       cvox.ApiImplementation.siteSpecificScriptBase);
 };
@@ -181,6 +188,11 @@
  * @override
  */
 cvox.ChromeMathJax.prototype.isMathjaxActive = function(callback) {
+  if (!this.initialized_) {
+    callback(false);
+    return;
+  }
+
   var retries = 0;
 
   var fetch = goog.bind(function() {
diff --git a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2 b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
index 56b4216b..31861f7 100644
--- a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
+++ b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
@@ -277,6 +277,12 @@
       "suggested_key": {
         "chromeos": "Search+Shift+R"
       }
+    },
+    "showContextMenu": {
+      "description": "__MSG_CHROMEVOX_SHOW_CONTEXT_MENU__",
+      "suggested_key": {
+        "chromeos": "Search+Ctrl+Space"
+      }
     }
 {% endif %}
   },
diff --git a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
index 5ca3676..3a0578e 100644
--- a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
+++ b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
@@ -2461,6 +2461,9 @@
       <message desc="Describes the pass through key command. Shown in options page." name="IDS_CHROMEVOX_PASS_THROUGH_KEY_DESCRIPTION">
         Pass through key
       </message>
+      <message desc="Describes the show context menu command. Shown in options page." name="IDS_CHROMEVOX_SHOW_CONTEXT_MENU">
+        Show context menu
+      </message>
       <message desc="Describes the braille caption feature. Braille captioning provides an overlay showing both text and braille of what ChromeVox would show on a refreshable braille display. Shown in the options page as a label." name="IDS_CHROMEVOX_BRAILLE_CAPTIONS">
         Toggle braille captions
       </message>
diff --git a/chrome/browser/resources/chromeos/chromevox/testing/chromevox_next_e2e_test_base.js b/chrome/browser/resources/chromeos/chromevox/testing/chromevox_next_e2e_test_base.js
index 4493cec5..feddbd5d 100644
--- a/chrome/browser/resources/chromeos/chromevox/testing/chromevox_next_e2e_test_base.js
+++ b/chrome/browser/resources/chromeos/chromevox/testing/chromevox_next_e2e_test_base.js
@@ -31,8 +31,8 @@
     callback = this.newCallback(callback);
     chrome.automation.getDesktop(function(r) {
       var listener = function(evt) {
-        if (!evt.target.attributes.url ||
-            evt.target.attributes.url.indexOf('test') == -1)
+        if (!evt.target.docUrl ||
+            evt.target.docUrl.indexOf('test') == -1)
           return;
 
         r.removeEventListener(listener);
diff --git a/chrome/browser/resources/chromeos/speech_synthesis/manifest.json b/chrome/browser/resources/chromeos/speech_synthesis/manifest.json
deleted file mode 100644
index 0edded7..0000000
--- a/chrome/browser/resources/chromeos/speech_synthesis/manifest.json
+++ /dev/null
@@ -1,93 +0,0 @@
-{
-  // NOTE: Keep two json files in this directory in sync. The only difference
-  // should be incognito:split in Guest mode version.
-  "name": "Chrome OS built-in text-to-speech extension",
-  "version": "2.1.1",
-  "description": "This is a high-quality text-to-speech (TTS) voice extension that runs in your browser using Native Client technology.",
-  "manifest_version": 2,
-  "background": {
-    "scripts": [
-      "voice_data_hmm_de-DE_2.js",
-      "voice_data_hmm_en-GB_2.js",
-      "voice_data_hmm_en-IN_2.js",
-      "voice_data_hmm_en-US_2.js",
-      "voice_data_hmm_es-ES_2.js",
-      "voice_data_hmm_es-US_2.js",
-      "voice_data_hmm_fr-FR_2.js",
-      "voice_data_hmm_it-IT_2.js",
-      "voice_data_hmm_ko-KR_2.js",
-      "voice_data_hmm_pt-BR_2.js",
-      "tts_controller.js",
-      "tts_main.js"
-    ]
-  },
-  "permissions": [
-    "ttsEngine",
-    "unlimitedStorage"
-  ],
-  "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlKEJseIIbKFyX0BCWNYOWlPEUt1IxBvIoW1PI7DTmipbwyVr3s2EprewYdtr9hCO5Yzs5w/ai1Xnhet5PLAsMje6ZP0Kvq0tlVfaYF8oQHBPF+ifx31RBT7Cn+ZVKLq1fxrwzY063GVhW+CAr06Ar8YRFXtFoC4FHlUNDIoSb4wIDAQAB",
-  "tts_engine": {
-    "voices": [
-      {
-        "voice_name": "Chrome OS German",
-        "lang": "de-DE",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS British English",
-        "lang": "en-GB",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS Indian English",
-        "lang": "en-IN",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS US English",
-        "lang": "en-US",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS Spanish",
-        "lang": "es-ES",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS US Spanish",
-        "lang": "es-US",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS French",
-        "lang": "fr-FR",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS Italian",
-        "lang": "it-IT",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS Korean",
-        "lang": "ko-KR",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS Brazilian Portuguese",
-        "lang": "pt-BR",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      }
-    ]
-  }
-}
diff --git a/chrome/browser/resources/chromeos/speech_synthesis/manifest_guest.json b/chrome/browser/resources/chromeos/speech_synthesis/manifest_guest.json
deleted file mode 100644
index c7efa02a..0000000
--- a/chrome/browser/resources/chromeos/speech_synthesis/manifest_guest.json
+++ /dev/null
@@ -1,94 +0,0 @@
-{
-  // NOTE: Keep two json files in this directory in sync. The only difference
-  // should be incognito:split in Guest mode version.
-  "name": "Chrome OS built-in text-to-speech extension",
-  "version": "2.1.1",
-  "description": "This is a high-quality text-to-speech (TTS) voice extension that runs in your browser using Native Client technology.",
-  "manifest_version": 2,
-  "incognito": "split",
-  "background": {
-    "scripts": [
-      "voice_data_hmm_de-DE_2.js",
-      "voice_data_hmm_en-GB_2.js",
-      "voice_data_hmm_en-IN_2.js",
-      "voice_data_hmm_en-US_2.js",
-      "voice_data_hmm_es-ES_2.js",
-      "voice_data_hmm_es-US_2.js",
-      "voice_data_hmm_fr-FR_2.js",
-      "voice_data_hmm_it-IT_2.js",
-      "voice_data_hmm_ko-KR_2.js",
-      "voice_data_hmm_pt-BR_2.js",
-      "tts_controller.js",
-      "tts_main.js"
-    ]
-  },
-  "permissions": [
-    "ttsEngine",
-    "unlimitedStorage"
-  ],
-  "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlKEJseIIbKFyX0BCWNYOWlPEUt1IxBvIoW1PI7DTmipbwyVr3s2EprewYdtr9hCO5Yzs5w/ai1Xnhet5PLAsMje6ZP0Kvq0tlVfaYF8oQHBPF+ifx31RBT7Cn+ZVKLq1fxrwzY063GVhW+CAr06Ar8YRFXtFoC4FHlUNDIoSb4wIDAQAB",
-  "tts_engine": {
-    "voices": [
-      {
-        "voice_name": "Chrome OS German",
-        "lang": "de-DE",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS British English",
-        "lang": "en-GB",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS Indian English",
-        "lang": "en-IN",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS US English",
-        "lang": "en-US",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS Spanish",
-        "lang": "es-ES",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS US Spanish",
-        "lang": "es-US",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS French",
-        "lang": "fr-FR",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS Italian",
-        "lang": "it-IT",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS Korean",
-        "lang": "ko-KR",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      },
-      {
-        "voice_name": "Chrome OS Brazilian Portuguese",
-        "lang": "pt-BR",
-        "gender": "female",
-        "event_types": [ "start", "word", "end", "error" ]
-      }
-    ]
-  }
-}
diff --git a/chrome/browser/resources/extensions/extension_command_list.js b/chrome/browser/resources/extensions/extension_command_list.js
index 0e2bc8e..d6150698 100644
--- a/chrome/browser/resources/extensions/extension_command_list.js
+++ b/chrome/browser/resources/extensions/extension_command_list.js
@@ -418,7 +418,12 @@
     handleKeyDown_: function(event) {
       event = /** @type {KeyboardEvent} */(event);
       if (event.keyCode == keyEscape) {
-        // Escape cancels capturing.
+        if (!this.capturingElement_) {
+          // If we're not currently capturing, allow escape to propagate (so it
+          // can close the overflow).
+          return;
+        }
+        // Otherwise, escape cancels capturing.
         this.endCapture_(event);
         var parsed = this.parseElementId_('clear',
             event.target.parentElement.querySelector('.command-clear').id);
@@ -449,8 +454,9 @@
      */
     handleKeyUp_: function(event) {
       event = /** @type {KeyboardEvent} */(event);
-      if (event.keyCode == keyTab) {
-        // Allow tab propagation for keyboard navigation.
+      if (event.keyCode == keyTab || event.keyCode == keyEscape) {
+        // We need to allow tab propagation for keyboard navigation, and escapes
+        // are fully handled in handleKeyDown.
         return;
       }
 
diff --git a/chrome/browser/resources/extensions/extension_commands_overlay.js b/chrome/browser/resources/extensions/extension_commands_overlay.js
index ab56eb4e..9b51f34 100644
--- a/chrome/browser/resources/extensions/extension_commands_overlay.js
+++ b/chrome/browser/resources/extensions/extension_commands_overlay.js
@@ -34,8 +34,9 @@
       this.extensionCommandList_ = new ExtensionCommandList(
           /**@type {HTMLDivElement} */($('extension-command-list')));
 
-      $('extension-commands-dismiss').addEventListener('click',
-          this.handleDismiss_.bind(this));
+      $('extension-commands-dismiss').addEventListener('click', function() {
+        cr.dispatchSimpleEvent(overlay, 'cancelOverlay');
+      });
 
       // The ExtensionList will update us with its data, so we don't need to
       // handle that here.
diff --git a/chrome/browser/resources/extensions/extension_error_overlay.js b/chrome/browser/resources/extensions/extension_error_overlay.js
index 84e32a9..1f7975e 100644
--- a/chrome/browser/resources/extensions/extension_error_overlay.js
+++ b/chrome/browser/resources/extensions/extension_error_overlay.js
@@ -292,8 +292,10 @@
       cr.ui.overlay.globalInitialization();
       overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this));
 
-      $('extension-error-overlay-dismiss').addEventListener(
-          'click', this.handleDismiss_.bind(this));
+      $('extension-error-overlay-dismiss').addEventListener('click',
+          function() {
+        cr.dispatchSimpleEvent(overlay, 'cancelOverlay');
+      });
 
       /**
        * The element of the full overlay.
diff --git a/chrome/browser/resources/extensions/extensions.js b/chrome/browser/resources/extensions/extensions.js
index 3dc9635..d50ceb3 100644
--- a/chrome/browser/resources/extensions/extensions.js
+++ b/chrome/browser/resources/extensions/extensions.js
@@ -386,9 +386,19 @@
     }
 
     if (node) {
-      var lastFocused = document.activeElement;
+      var lastFocused;
+
+      var focusOutlineManager = cr.ui.FocusOutlineManager.forDocument(document);
+      if (focusOutlineManager.visible)
+        lastFocused = document.activeElement;
+
       $('overlay').addEventListener('cancelOverlay', function f() {
-        lastFocused.focus();
+        console.log('cancelOverlay');
+        console.log('lastFocused', lastFocused);
+        console.log('focusOutlineManager.visible', focusOutlineManager.visible);
+        if (lastFocused && focusOutlineManager.visible)
+          lastFocused.focus();
+
         $('overlay').removeEventListener('cancelOverlay', f);
       });
       node.classList.add('showing');
diff --git a/chrome/browser/resources/extensions/pack_extension_overlay.js b/chrome/browser/resources/extensions/pack_extension_overlay.js
index 03e6180..05d23d1 100644
--- a/chrome/browser/resources/extensions/pack_extension_overlay.js
+++ b/chrome/browser/resources/extensions/pack_extension_overlay.js
@@ -23,8 +23,9 @@
       cr.ui.overlay.globalInitialization();
       overlay.addEventListener('cancelOverlay', this.handleDismiss_.bind(this));
 
-      $('pack-extension-dismiss').addEventListener('click',
-          this.handleDismiss_.bind(this));
+      $('pack-extension-dismiss').addEventListener('click', function() {
+        cr.dispatchSimpleEvent(overlay, 'cancelOverlay');
+      });
       $('pack-extension-commit').addEventListener('click',
           this.handleCommit_.bind(this));
       $('browse-extension-dir').addEventListener('click',
diff --git a/chrome/browser/resources/options/chromeos/display_options.js b/chrome/browser/resources/options/chromeos/display_options.js
index bf40eccc..40e7d4e8 100644
--- a/chrome/browser/resources/options/chromeos/display_options.js
+++ b/chrome/browser/resources/options/chromeos/display_options.js
@@ -223,7 +223,9 @@
         chrome.send('setDisplayMode', [display.id, resolution]);
       }).bind(this);
       $('display-options-orientation-selection').onchange = (function(ev) {
-        chrome.send('setOrientation', [this.displays_[this.focusedIndex_].id,
+        var displayIndex =
+          (this.focusedIndex_ === null) ? 0 : this.focusedIndex_;
+        chrome.send('setOrientation', [this.displays_[displayIndex].id,
                                        ev.target.value]);
       }).bind(this);
       $('display-options-color-profile-selection').onchange = (function(ev) {
@@ -636,8 +638,11 @@
       $('display-options-set-primary').disabled = true;
       $('display-options-toggle-mirroring').disabled = false;
       $('selected-display-start-calibrating-overscan').disabled = true;
-      $('display-options-orientation-selection').disabled = true;
       var display = this.displays_[0];
+      var orientation = $('display-options-orientation-selection');
+      orientation.disabled = false;
+      var orientationOptions = orientation.getElementsByTagName('option');
+      orientationOptions[display.orientation].selected = true;
       $('selected-display-name').textContent =
           loadTimeData.getString('mirroringDisplay');
       var resolution = $('display-options-resolution-selection');
diff --git a/chrome/browser/resources/options/chromeos/internet_detail.js b/chrome/browser/resources/options/chromeos/internet_detail.js
index f184016..fa636df9 100644
--- a/chrome/browser/resources/options/chromeos/internet_detail.js
+++ b/chrome/browser/resources/options/chromeos/internet_detail.js
@@ -755,10 +755,12 @@
       }
 
       var showConfigure = false;
-      if (this.type_ == 'WiMAX' || this.type_ == 'VPN') {
+      if (this.type_ == 'VPN') {
+        showConfigure = true;
+      } else if (this.type_ == 'WiMAX' && connectState == 'NotConnected') {
         showConfigure = true;
       } else if (this.type_ == 'WiFi') {
-        showConfigure = (connectState != 'Connected' &&
+        showConfigure = (connectState == 'NotConnected' &&
                          (!connectable || onc.getWiFiSecurity() != 'None'));
       }
       $('details-internet-configure').hidden = !showConfigure;
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.html b/chrome/browser/resources/settings/a11y_page/a11y_page.html
index 87b0cbe6e..7ebb033 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.html
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.html
@@ -10,69 +10,56 @@
     <paper-material>
       <div class="more-a11y-link">
         <a href="https://chrome.google.com/webstore/category/collection/accessibility"
-            target="_blank" i18n-content="accessibilityMoreFeaturesLink"></a>
+            target="_blank" i18n-content="moreFeaturesLink"></a>
       </div>
 
 <if expr="chromeos">
-      <cr-settings-checkbox
-          pref="{{prefs.settings.a11y.enable_menu}}"
-          i18n-values="label:accessibilityOptionsInMenuLabel">
+      <cr-settings-checkbox i18n-values="label:optionsInMenuLabel"
+          pref="{{prefs.settings.a11y.enable_menu}}">
       </cr-settings-checkbox>
-      <cr-settings-checkbox
-          pref="{{prefs.settings.a11y.large_cursor_enabled}}"
-          i18n-values="label:accessibilityLargeMouseCursorLabel">
+      <cr-settings-checkbox i18n-values="label:largeMouseCursorLabel"
+          pref="{{prefs.settings.a11y.large_cursor_enabled}}">
       </cr-settings-checkbox>
-      <cr-settings-checkbox
-          pref="{{prefs.settings.a11y.high_contrast_enabled}}"
-          i18n-values="label:accessibilityHighContrastLabel">
+      <cr-settings-checkbox i18n-values="label:highContrastLabel"
+          pref="{{prefs.settings.a11y.high_contrast_enabled}}">
       </cr-settings-checkbox>
       <cr-settings-checkbox
           pref="{{prefs.settings.a11y.sticky_keys_enabled}}"
-          i18n-values="label:accessibilityStickyKeysLabel;
-                       subLabel:accessibilityStickyKeysSublabel">
+          i18n-values="label:stickyKeysLabel; subLabel:stickyKeysSublabel">
       </cr-settings-checkbox>
       <cr-settings-checkbox pref="{{prefs.settings.accessibility}}"
-          i18n-values="label:accessibilityChromeVoxLabel;
-                       subLabel:accessibilityChromeVoxSublabel">
+          i18n-values="label:chromeVoxLabel; subLabel:chromeVoxSublabel">
       </cr-settings-checkbox>
-      <cr-settings-checkbox
-          pref="{{prefs.settings.a11y.screen_magnifier}}"
-          i18n-values="label:accessibilityScreenMagnifierLabel">
+      <cr-settings-checkbox i18n-values="label:screenMagnifierLabel"
+          pref="{{prefs.settings.a11y.screen_magnifier}}">
       </cr-settings-checkbox>
-      <cr-settings-checkbox
-          pref="{{prefs.settings.touchpad.enable_tap_dragging}}"
-          i18n-values="label:accessibilityTapDraggingLabel">
+      <cr-settings-checkbox i18n-values="label:tapDraggingLabel"
+          pref="{{prefs.settings.touchpad.enable_tap_dragging}}">
       </cr-settings-checkbox>
-      <cr-settings-checkbox pref="{{prefs.settings.a11y.autoclick}}"
-          i18n-values="label:accessibilityClickOnStopLabel">
+      <cr-settings-checkbox i18n-values="label:clickOnStopLabel"
+          pref="{{prefs.settings.a11y.autoclick}}">
       </cr-settings-checkbox>
 
       <div class="autoclick-delay-label"
           hidden$="{{!prefs.settings.a11y.autoclick}}">
-        <span i18n-content="accessibilityDelayBeforeClickLabel"></span>
+        <span i18n-content="delayBeforeClickLabel"></span>
         <select id="autoclickDropdown"
             value="{{prefs.settings.a11y.autoclick_delay_ms::change}}">
-          <option value="200"
-              i18n-content="accessibilityDelayBeforeClickExtremelyShort">
+          <option value="200" i18n-content="delayBeforeClickExtremelyShort">
           </option>
-          <option value="400"
-              i18n-content="accessibilityDelayBeforeClickVeryShort">
+          <option value="400" i18n-content="delayBeforeClickVeryShort">
           </option>
-          <option value="600"
-              i18n-content="accessibilityDelayBeforeClickShort">
+          <option value="600" i18n-content="delayBeforeClickShort">
           </option>
-          <option value="800"
-              i18n-content="accessibilityDelayBeforeClickLong">
+          <option value="800" i18n-content="delayBeforeClickLong">
           </option>
-          <option value="1000"
-              i18n-content="accessibilityDelayBeforeClickVeryLong">
+          <option value="1000" i18n-content="delayBeforeClickVeryLong">
           </option>
         </select>
       </div>
 
-      <cr-settings-checkbox
-          pref="{{prefs.settings.a11y.virtual_keyboard}}"
-          i18n-values="label:accessibilityOnScreenKeyboardLabel">
+      <cr-settings-checkbox pref="{{prefs.settings.a11y.virtual_keyboard}}"
+          i18n-values="label:onScreenKeyboardLabel">
       </cr-settings-checkbox>
 </if>
 
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_page.css b/chrome/browser/resources/settings/appearance_page/appearance_page.css
new file mode 100644
index 0000000..b22440b
--- /dev/null
+++ b/chrome/browser/resources/settings/appearance_page/appearance_page.css
@@ -0,0 +1,30 @@
+/* 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. */
+
+ #change-home-page-section {
+  -webkit-margin-start: 40px;
+  font-size: 90%;
+}
+
+/* TODO(jhawkins): This does not span the width of the entire paper-material
+ * element because our styling of all paper-material includes a fixed margin.
+ * This can be fixed by creating a generic content container inside of each
+ * paper-material which would have this margin instead.
+ *
+ * TODO(jhawkins): Share this rule set at a higher level, e.g., to share with
+ * the device page.
+ */
+hr {
+  width: 100%;
+}
+
+#action-container {
+  display: flex;
+  flex-direction: row;
+  justify-content: flex-end;
+}
+
+#action-container > paper-button {
+  text-transform: upper-case;
+}
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_page.html b/chrome/browser/resources/settings/appearance_page/appearance_page.html
index 2f3c05f..19c746c2 100644
--- a/chrome/browser/resources/settings/appearance_page/appearance_page.html
+++ b/chrome/browser/resources/settings/appearance_page/appearance_page.html
@@ -5,15 +5,35 @@
 <dom-module id="cr-settings-appearance-page">
   <link rel="import" type="css"
       href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css"
+      href="chrome://md-settings/appearance_page/appearance_page.css">
+  <link rel="import" type="css" href="chrome://resources/css/widgets.css">
+  <link rel="import" href="chrome://resources/html/action_link.html">
   <template>
     <paper-material>
-      <cr-settings-checkbox
-          pref="{{prefs.browser.show_home_button}}"
-          i18n-values="label:appearanceShowHomeButtonLabel">
+      <div id="action-container">
+        <cr-button i18n-content="setWallpaper"></cr-button>
+        <cr-button id="get-themes" i18n-content="getThemes"
+            on-click="openThemesGallery_">
+        </cr-button>
+        <cr-button i18n-content="resetToDefaultTheme" disabled></cr-button>
+      </div>
+      <hr>
+      <cr-settings-checkbox pref="{{prefs.browser.show_home_button}}"
+          i18n-values="label:showHomeButton">
       </cr-settings-checkbox>
-      <cr-settings-checkbox
-          pref="{{prefs.bookmark_bar.show_on_all_tabs}}"
-          i18n-values="label:appearanceShowBookmarksBarLabel">
+      <div id="change-home-page-section"
+          hidden$="[[!prefs.browser.show_home_button.value]]">
+        <div id="change-home-page-section-container">
+          <span id="home-page-ntp" i18n-content="homePageNtp"></span>
+          <span id="home-page-url"></span>
+          <a is="action-link" id="change-home-page"
+              i18n-content="changeHomePage">
+          </a>
+      </div>
+    </div>
+      <cr-settings-checkbox pref="{{prefs.bookmark_bar.show_on_all_tabs}}"
+          i18n-values="label:showBookmarksBar">
       </cr-settings-checkbox>
     </paper-material>
   </template>
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_page.js b/chrome/browser/resources/settings/appearance_page/appearance_page.js
index d3f36a1e..612c999c 100644
--- a/chrome/browser/resources/settings/appearance_page/appearance_page.js
+++ b/chrome/browser/resources/settings/appearance_page/appearance_page.js
@@ -72,4 +72,9 @@
       readOnly: true,
     },
   },
+
+  /** @private */
+  openThemesGallery_: function() {
+    window.open(loadTimeData.getString('themesGalleryUrl'));
+  },
 });
diff --git a/chrome/browser/resources/settings/checkbox/checkbox.css b/chrome/browser/resources/settings/checkbox/checkbox.css
index 5288327..ad35bc5 100644
--- a/chrome/browser/resources/settings/checkbox/checkbox.css
+++ b/chrome/browser/resources/settings/checkbox/checkbox.css
@@ -3,6 +3,7 @@
  * found in the LICENSE file. */
 
 :host {
+  display: block;
   margin-bottom: 10px;
   margin-top: 10px;
 }
diff --git a/chrome/browser/resources/settings/checkbox/checkbox.html b/chrome/browser/resources/settings/checkbox/checkbox.html
index 2203eb3..6996f98 100644
--- a/chrome/browser/resources/settings/checkbox/checkbox.html
+++ b/chrome/browser/resources/settings/checkbox/checkbox.html
@@ -9,7 +9,7 @@
     <cr-events id="events"></cr-events>
     <cr-settings-pref-tracker pref="[[pref]]"></cr-settings-pref-tracker>
 
-    <cr-checkbox id="checkbox" checked="{{pref.value}}"
+    <cr-checkbox id="checkbox" checked="{{checked}}"
         disabled="[[pref.disabled]]">
       <span class="main-label">{{label}}</span>
       <span class="sub-label">{{subLabel}}</span>
diff --git a/chrome/browser/resources/settings/checkbox/checkbox.js b/chrome/browser/resources/settings/checkbox/checkbox.js
index 6e0860cf..40d9fde 100644
--- a/chrome/browser/resources/settings/checkbox/checkbox.js
+++ b/chrome/browser/resources/settings/checkbox/checkbox.js
@@ -23,7 +23,18 @@
      */
     pref: {
       type: Object,
-      notify: true,
+      notify: true
+    },
+
+    inverted: {
+      type: Boolean,
+      value: false
+    },
+
+    checked: {
+      type: Boolean,
+      value: false,
+      observer: 'checkedChanged_'
     },
 
     label: {
@@ -37,8 +48,32 @@
     },
   },
 
+  observers: [
+    'prefValueChanged_(pref.value)'
+  ],
+
   /** @override */
   ready: function() {
     this.$.events.forward(this.$.checkbox, ['change']);
   },
+
+  /** @private */
+  prefValueChanged_: function(prefValue) {
+    // prefValue is initially undefined when Polymer initializes pref.
+    if (prefValue !== undefined) {
+      this.checked = this.getNewValue_(prefValue);
+    }
+  },
+
+  /** @private */
+  checkedChanged_: function() {
+    if (this.pref) {
+      this.pref.value = this.getNewValue_(this.checked);
+    }
+  },
+
+  /** @private */
+  getNewValue_: function(val) {
+    return this.inverted ? !val : val;
+  }
 });
diff --git a/chrome/browser/resources/settings/date_time_page/date_time_page.html b/chrome/browser/resources/settings/date_time_page/date_time_page.html
index 6f1e567..0fb7597a 100644
--- a/chrome/browser/resources/settings/date_time_page/date_time_page.html
+++ b/chrome/browser/resources/settings/date_time_page/date_time_page.html
@@ -9,13 +9,13 @@
   <template>
     <paper-material class="layout veritcal">
       <div class="horizontal layout center">
-        <span class="time-zone-label" i18n-content="dateTimeTimeZoneLabel"></span>
+        <span class="time-zone-label" i18n-content="timeZone"></span>
       </div>
-      <cr-settings-checkbox
-          pref="{{prefs.settings.clock.use_24hour_clock}}"
-          i18n-values="label:dateTime24HourClockLabel">
+      <cr-settings-checkbox pref="{{prefs.settings.clock.use_24hour_clock}}"
+          i18n-values="label:use24HourClock">
       </cr-settings-checkbox>
-      <span id="setAutomatically" i18n-content="dateTimeAutomaticallySet"></span>
+      <span id="setAutomatically" i18n-content="dateTimeSetAutomatically">
+      </span>
     </paper-material>
   </template>
   <script src="date_time_page.js"></script>
diff --git a/chrome/browser/resources/settings/downloads_page/downloads_page.html b/chrome/browser/resources/settings/downloads_page/downloads_page.html
index acb6f23..dcecd14 100644
--- a/chrome/browser/resources/settings/downloads_page/downloads_page.html
+++ b/chrome/browser/resources/settings/downloads_page/downloads_page.html
@@ -13,19 +13,18 @@
     <paper-material>
       <div class="horizontal layout center">
         <div class="layout horizontal center">
-          <div id="locationLabel" i18n-content="downloadsLocationLabel"></div>
+          <div id="locationLabel" i18n-content="downloadLocation"></div>
           <cr-input id="downloadsPath" floating-label="false"
-                value="{{prefs.download.default_directory.value}}"
-                readonly aria-labelledby="locationLabel">
+              value="{{prefs.download.default_directory.value}}"
+              readonly aria-labelledby="locationLabel">
           </cr-input>
         </div>
         <cr-button id="changeDownloadsPath" on-click="selectDownloadLocation_"
-            i18n-content="downloadsChangeLocationButton">
+            i18n-content="changeDownloadLocation">
         </cr-button>
       </div>
-      <cr-settings-checkbox
-          pref="{{prefs.download.prompt_for_download}}"
-          i18n-values="label:downloadsPromptForDownloadLabel">
+      <cr-settings-checkbox pref="{{prefs.download.prompt_for_download}}"
+          i18n-values="label:promptForDownload">
       </cr-settings-checkbox>
     </paper-material>
   </template>
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page_style.html b/chrome/browser/resources/settings/internet_page/internet_detail_page.css
similarity index 64%
rename from chrome/browser/resources/settings/internet_page/internet_detail_page_style.html
rename to chrome/browser/resources/settings/internet_page/internet_detail_page.css
index 19c8c8e..a3760fe0 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page_style.html
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.css
@@ -1,7 +1,6 @@
-<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/core-style/core-style.html">
-
-<core-style id="internetDetailPageStyle">
+/* 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. */
 
 #networkIcon {
   height: 32px;
@@ -34,5 +33,3 @@
 #detailDiv span {
   margin-bottom: 10px;
 }
-
-</core-style>
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.html b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
index dd32da2..2e15737f 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
@@ -1,49 +1,48 @@
-<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_onc/cr_onc_data.html">
-<link rel="import" href="internet_detail_page_style.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_data.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.html">
 
-<polymer-element name="cr-settings-internet-detail-page">
+<dom-module id="cr-settings-internet-detail-page">
+  <link rel="import" type="css" href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="internet_detail_page.css">
   <template>
-    <link rel="stylesheet" href="chrome://md-settings/settings_page/settings_page.css">
-    <core-style ref="internetDetailPageStyle"></core-style>
-    <paper-shadow layout vertical cross-fade>
-      <div vertical layout>
-        <div id="titleDiv" horizontal layout>
-          <div center horizontal layout flex>
-            <cr-network-icon id="networkIcon" networkState="{{networkState}}">
-            </cr-network-icon>
-            <span id="networkName">{{getStateName_(networkState)}}</span>
-            <span id="networkState"
-                  class="{{ {connected: isConnectedState_(networkState)} | tokenList }}">
-              {{getStateText_(networkState)}}
-            </span>
+    <paper-material class="layout vertical">
+      <div class="layout vertical">
+        <div id="titleDiv" class="layout horizontal">
+          <div class="layout center horizontal flex">
+            <cr-network-icon id="networkIcon"></cr-network-icon>
+            <span id="networkName">[[getStateName_(networkState)]]</span>
+            <span id="networkState" class="[[getStateClass_(networkState)]]"
+                >[[getStateText_(networkState)]]</span>
           </div>
-          <div center horizontal layout center-justified
+          <div class="layout center horizontal center-justified"
               id="connectionButtonDiv">
-            <cr-button hidden?="{{!canDisconnect_(networkState)}}"
-                on-click="{{onDisconnectClicked_}}">
+            <cr-button hidden$="[[!canDisconnect_(networkState)]]"
+                on-click="onDisconnectClicked_">
               Disconnect
             </cr-button>
-            <cr-button hidden?="{{!canConnect_(networkState)}}"
-                on-click="{{onConnectClicked_}}">
+            <cr-button hidden$="[[!canConnect_(networkState)]]"
+                on-click="onConnectClicked_">
               Connect
             </cr-button>
           </div>
         </div>
-        <div id="detailDiv" vertical layout>
-          <div vertical layout hidden?="{{!isConnectedState_(networkState)}}">
-            <span>{{getProperty_(networkState, 'MacAddress')}}</span>
+        <div id="detailDiv" class="layout vertical">
+          <div class="layout vertical"
+              hidden$="[[!isConnectedState_(networkState)]]">
+            <span>[[getProperty_(networkState, 'MacAddress')]]</span>
           </div>
-          <div vertical layout hidden?="{{networkState.data.Type != 'WiFi'}}">
-            <span>{{getProperty_(networkState, 'WiFi.Security')}}</span>
-            <span>{{getProperty_(networkState, 'WiFi.SSID')}}</span>
-            <span>{{getProperty_(networkState, 'WiFi.BSSID')}}</span>
-            <span>{{getProperty_(networkState, 'WiFi.SignalStrength')}}</span>
-            <span>{{getProperty_(networkState, 'WiFi.Frequency')}}</span>
+          <div class="layout vertical"
+              hidden$="[[!isType_(networkState, 'WiFi')]]">
+            <span>[[getProperty_(networkState, 'WiFi.Security')]]</span>
+            <span>[[getProperty_(networkState, 'WiFi.SSID')]]</span>
+            <span>[[getProperty_(networkState, 'WiFi.BSSID')]]</span>
+            <span>[[getProperty_(networkState, 'WiFi.SignalStrength')]]</span>
+            <span>[[getProperty_(networkState, 'WiFi.Frequency')]]</span>
           </div>
         </div>
       </div>
     </paper-shadow>
   </template>
   <script src="internet_detail_page.js"></script>
-</polymer-element>
+</dom-module>
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.js b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
index 9e7d359..114cccd 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
@@ -15,69 +15,90 @@
 /** @typedef {chrome.networkingPrivate.NetworkStateProperties} */
 var NetworkStateProperties;
 
-Polymer('cr-settings-internet-detail-page', {
-  publish: {
+Polymer({
+  is: 'cr-settings-internet-detail-page',
+
+  properties: {
     /**
      * ID of the page.
      *
      * @attribute PAGE_ID
      * @const {string}
      */
-    PAGE_ID: 'internet-detail',
+    PAGE_ID: {
+      type: String,
+      value: 'internet-detail',
+      readOnly: true
+    },
 
     /**
      * Route for the page.
-     *
-     * @attribute route
-     * @type {string}
-     * @default ''
      */
-    route: '',
+    route: {
+      type: String,
+      value: ''
+    },
 
     /**
      * Whether the page is a subpage.
-     *
-     * @attribute subpage
-     * @type {boolean}
-     * @default false
      */
-    subpage: false,
+    subpage: {
+      type: Boolean,
+      value: false
+    },
 
     /**
      * Title for the page header and navigation menu.
-     *
-     * @attribute pageTitle
-     * @type {string}
      */
-    pageTitle: loadTimeData.getString('internetDetailPageTitle'),
+    pageTitle: {
+      type: String,
+      value: function() {
+        return loadTimeData.getString('internetDetailPageTitle');
+      }
+    },
+
+    /**
+     * Reflects the selected settings page. We use this to extract guid from
+     * window.location.href when this page is navigated to. This is a
+     * workaround for a bug in the 1.0 version of more-routing where
+     * selected-params="{{params}}" is not correctly setting params in
+     * settings_main.html. TODO(stevenjb): Remove once more-routing is fixed.
+     */
+    selectedPage: {
+      type: String,
+      value: '',
+      observer: 'selectedPageChanged_'
+    },
 
     /**
      * Name of the 'core-icon' to show. TODO(stevenjb): Update this with the
-     * icon for the network.
-     *
-     * @attribute icon
-     * @type {string}
-     * @default 'settings-ethernet'
+     * icon for the active internet connection.
      */
-    icon: 'settings-ethernet',
+    icon: {
+      type: String,
+      value: 'settings-ethernet',
+      readOnly: true
+    },
 
     /**
      * The network GUID to display details for.
-     *
-     * @attribute guid
-     * @type {string}
-     * @default ''
      */
-    guid: '',
+    guid: {
+      type: String,
+      value: '',
+      observer: 'guidChanged_',
+    },
 
     /**
      * The current state for the network matching |guid|.
      *
-     * @attribute networkState
-     * @type {?CrOncDataElement}
-     * @default null
+     * @type {?NetworkStateProperties}
      */
-    networkState: null,
+    networkState: {
+      type: Object,
+      value: null,
+      observer: 'networkStateChanged_'
+    },
   },
 
   /**
@@ -103,11 +124,37 @@
   /**
    * Polymer guid changed method.
    */
-  guidChanged: function() {
+  guidChanged_: function() {
+    if (!this.guid)
+      return;
     this.getNetworkDetails_();
   },
 
   /**
+   * Polymer guid changed method. TODO(stevenjb): Remove, see TODO above.
+   */
+  selectedPageChanged_: function() {
+    if ((this.selectedPage && this.selectedPage.PAGE_ID) != this.PAGE_ID)
+      return;
+    var href = window.location.href;
+    var idx = href.lastIndexOf('/');
+    var guid = href.slice(idx + 1);
+    this.guid = guid;
+  },
+
+  /**
+   * Polymer networkState changed method.
+   */
+  networkStateChanged_: function() {
+    if (!this.networkState)
+      return;
+    // Set networkIcon.networkState explicitly since networkState is an element.
+    // TODO(stevenjb): Remove this function when CrOncDataElement is removed.
+    this.$.networkIcon.networkState =
+        CrOncDataElement.create(this.networkState);
+  },
+
+  /**
    * networkingPrivate.onNetworksChanged event callback.
    * @param {!Array<string>} networkIds The list of changed network GUIDs.
    * @private
@@ -134,30 +181,39 @@
    * @private
    */
   getPropertiesCallback_: function(state) {
-    this.networkState = CrOncDataElement.create(state);
+    this.networkState = state;
   },
 
   /**
-   * @param {?CrOncDataElement} state The network state properties.
+   * @param {?NetworkStateProperties} state The network state properties.
    * @return {string} The text to display for the network name.
    * @private
    */
   getStateName_: function(state) {
-    return state && state.data.Name;
+    return state && state.Name;
   },
 
   /**
-   * @param {?CrOncDataElement} state The network state properties.
+   * @param {?NetworkStateProperties} state The network state properties.
+   * @return {string} The text to display for the network name.
+   * @private
+   */
+  getStateClass_: function(state) {
+    return this.isConnectedState_(state) ? 'connected' : '';
+  },
+
+  /**
+   * @param {?NetworkStateProperties} state The network state properties.
    * @return {string} The text to display for the network connection state.
    * @private
    */
   getStateText_: function(state) {
     // TODO(stevenjb): Localize.
-    return state && state.data.ConnectionState;
+    return state && state.ConnectionState;
   },
 
   /**
-   * @param {?CrOncDataElement} state The network state properties.
+   * @param {?NetworkStateProperties} state The network state properties.
    * @param {string} property The property name.
    * @return {string} The text to display for the property, including the label.
    * @private
@@ -165,36 +221,48 @@
   getProperty_: function(state, property) {
     if (!state)
       return '';
+    var value = this.get(property, state) || '';
     // TODO(stevenjb): Localize.
-    var value = state.getProperty(property) || '';
     return property + ': ' + value;
   },
 
   /**
-   * @param {?CrOncDataElement} state The network state properties.
-   * @return {boolean} Whether or not the state is connected.
+   * @param {?NetworkStateProperties} state The network state properties.
+   * @return {boolean} True if the state is connected.
    * @private
    */
   isConnectedState_: function(state) {
-    return state && state.connected();
+    return state && state.ConnectionState == CrOnc.ConnectionState.CONNECTED;
   },
 
   /**
-   * @param {?CrOncDataElement} state The network state properties.
+   * @param {?NetworkStateProperties} state The network state properties.
    * @return {boolean} Whether or not the network can be connected.
    * @private
    */
   canConnect_: function(state) {
-    return state && state.data.Type != 'Ethernet' && state.disconnected();
+    return state && state.Type != 'Ethernet' &&
+           state.ConnectionState == CrOnc.ConnectionState.NOT_CONNECTED;
   },
 
   /**
-   * @param {?CrOncDataElement} state The network state properties.
+   * @param {?NetworkStateProperties} state The network state properties.
    * @return {boolean} Whether or not the network can be disconnected.
    * @private
    */
   canDisconnect_: function(state) {
-    return state && state.data.Type != 'Ethernet' && !state.disconnected();
+    return state && state.Type != 'Ethernet' &&
+           state.ConnectionState != CrOnc.ConnectionState.NOT_CONNECTED;
+  },
+
+  /**
+   * @param {?NetworkStateProperties} state The network state properties.
+   * @param {string} type The network type to match.
+   * @return {boolean} Whether or not the type of 'state' matches 'type'.
+   * @private
+   */
+  isType_: function(state, type) {
+    return state && state.Type == type;
   },
 
   /**
diff --git a/chrome/browser/resources/settings/internet_page/internet_page.html b/chrome/browser/resources/settings/internet_page/internet_page.html
index 0b1b285..2a41b69 100644
--- a/chrome/browser/resources/settings/internet_page/internet_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_page.html
@@ -1,12 +1,12 @@
-<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="network_summary.html">
 
-<polymer-element name="cr-settings-internet-page">
+<dom-module id="cr-settings-internet-page">
+  <link rel="import" type="css" href="chrome://md-settings/settings_page/settings_page.css">
   <template>
-    <link rel="stylesheet" href="chrome://md-settings/settings_page/settings_page.css">
-    <paper-shadow layout vertical cross-fade>
+    <paper-material class="layout vertical">
       <cr-network-summary></cr-network-summary>
-    </paper-shadow>
+    </paper-material>
   </template>
   <script src="internet_page.js"></script>
-</polymer-element>
+</dom-module>
diff --git a/chrome/browser/resources/settings/internet_page/internet_page.js b/chrome/browser/resources/settings/internet_page/internet_page.js
index 6c3c872..57cea81 100644
--- a/chrome/browser/resources/settings/internet_page/internet_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_page.js
@@ -18,50 +18,52 @@
  * @group Chrome Settings Elements
  * @element cr-settings-internet-page
  */
-Polymer('cr-settings-internet-page', {
-  publish: {
+Polymer({
+  is: 'cr-settings-internet-page',
+
+  properties: {
     /**
      * ID of the page.
-     *
-     * @attribute PAGE_ID
-     * @const {string}
      */
-    PAGE_ID: 'internet',
+    PAGE_ID: {
+      type: String,
+      value: 'internet',
+      readOnly: true
+    },
 
     /**
      * Route for the page.
-     *
-     * @attribute route
-     * @type {string}
-     * @default ''
      */
-    route: '',
+    route: {
+      type: String,
+      value: ''
+    },
 
     /**
      * Whether the page is a subpage.
-     *
-     * @attribute subpage
-     * @type {boolean}
-     * @default false
      */
-    subpage: false,
+    subpage: {
+      type: Boolean,
+      value: false,
+      readOnly: true
+    },
 
     /**
      * Title for the page header and navigation menu.
-     *
-     * @attribute pageTitle
-     * @type {string}
      */
-    pageTitle: loadTimeData.getString('internetPageTitle'),
+    pageTitle: {
+      type: String,
+      value: function() { return loadTimeData.getString('internetPageTitle'); }
+    },
 
     /**
      * Name of the 'core-icon' to show. TODO(stevenjb): Update this with the
      * icon for the active internet connection.
-     *
-     * @attribute icon
-     * @type {string}
-     * @default 'settings-ethernet'
      */
-    icon: 'settings-ethernet',
+    icon: {
+      type: String,
+      value: 'settings-ethernet',
+      readOnly: true
+    },
   },
 });
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.css b/chrome/browser/resources/settings/internet_page/network_summary.css
new file mode 100644
index 0000000..8ef2212
--- /dev/null
+++ b/chrome/browser/resources/settings/internet_page/network_summary.css
@@ -0,0 +1,7 @@
+/* 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. */
+
+#summary {
+  padding-right: 40px;
+}
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.html b/chrome/browser/resources/settings/internet_page/network_summary.html
index 54b52097..dacdc19 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary.html
+++ b/chrome/browser/resources/settings/internet_page/network_summary.html
@@ -1,49 +1,47 @@
-<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/core-style/core-style.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_onc/cr_onc_data.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/more-routing/more-routing.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_data.html">
 <link rel="import" href="network_summary_item.html">
-<link rel="import" href="network_summary_style.html">
 
-<polymer-element name="cr-network-summary">
+<dom-module id="cr-network-summary">
+  <link rel="import" type="css" href="network_summary.css">
   <template>
-    <core-style ref="networkSummaryStyle"></core-style>
-    <div id="summary" vertical layout>
-      <cr-network-summary-item
-          deviceState="{{deviceStates.Ethernet}}"
-          networkState="{{networkStates.Ethernet}}"
-          networkStateList="{{networkStateLists.Ethernet}}"
-          on-selected="{{onSelected_}}">
+    <div id="summary" class="layout vertical">
+      <cr-network-summary-item id="ethernet"
+          device-state="[[deviceStates.Ethernet]]"
+          network-state="[[networkStates.Ethernet]]"
+          network-state-list="[[networkStateLists.Ethernet]]"
+          on-selected="onSelected_">
       </cr-network-summary-item>
-      <cr-network-summary-item
-          deviceState="{{deviceStates.WiFi}}"
-          networkState="{{networkStates.WiFi}}"
-          networkStateList="{{networkStateLists.WiFi}}"
-          on-expanded="{{onWiFiExpanded_}}"
-          on-selected="{{onSelected_}}"
-          on-device-enabled-toggled="{{onDeviceEnabledToggled_}}">
+      <cr-network-summary-item id="wifi"
+          device-state="[[deviceStates.WiFi]]"
+          network-state="[[networkStates.WiFi]]"
+          network-state-list="[[networkStateLists.WiFi]]"
+          on-expanded="onWiFiExpanded_"
+          on-selected="onSelected_"
+          on-device-enabled-toggled="onDeviceEnabledToggled_">
       </cr-network-summary-item>
-      <cr-network-summary-item
-          deviceState="{{deviceStates.Cellular}}"
-          networkState="{{networkStates.Cellular}}"
-          networkStateList="{{networkStateLists.Cellular}}"
-          on-selected="{{onSelected_}}"
-          on-device-enabled-toggled="{{onDeviceEnabledToggled_}}">
+      <cr-network-summary-item id="cellular"
+          device-state="[[deviceStates.Cellular]]"
+          network-state="[[networkStates.Cellular]]"
+          network-state-list="[[networkStateLists.Cellular]]"
+          on-selected="onSelected_"
+          on-device-enabled-toggled="onDeviceEnabledToggled_">
       </cr-network-summary-item>
-      <cr-network-summary-item
-          deviceState="{{deviceStates.WiMAX}}"
-          networkState="{{networkStates.WiMAX}}"
-          networkStateList="{{networkStateLists.WiMAX}}"
-          on-selected="{{onSelected_}}"
-          on-device-enabled-toggled="{{onDeviceEnabledToggled_}}">
+      <cr-network-summary-item id="wimax"
+          device-state="[[deviceStates.WiMAX]]"
+          network-state="[[networkStates.WiMAX]]"
+          network-state-list="[[networkStateLists.WiMAX]]"
+          on-selected="onSelected_"
+          on-device-enabled-toggled="onDeviceEnabledToggled_">
       </cr-network-summary-item>
-      <cr-network-summary-item
-          deviceState="{{deviceStates.VPN}}"
-          networkState="{{networkStates.VPN}}"
-          networkStateList="{{networkStateLists.VPN}}"
-          on-selected="{{onSelected_}}">
+      <cr-network-summary-item id="vpn"
+          device-state="[[deviceStates.VPN]]"
+          network-state="[[networkStates.VPN]]"
+          network-state-list="[[networkStateLists.VPN]]"
+          on-selected="onSelected_">
       </cr-network-summary-item>
     </div>
   </template>
   <script src="network_summary.js"></script>
-</polymer-element>
+</dom-module>
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.js b/chrome/browser/resources/settings/internet_page/network_summary.js
index 186b885..2b9e4cc 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary.js
+++ b/chrome/browser/resources/settings/internet_page/network_summary.js
@@ -27,22 +27,22 @@
 
 /**
  * @typedef {{
- *   Ethernet: (CrOncDataElement|undefined),
- *   WiFi: (CrOncDataElement|undefined),
- *   Cellular: (CrOncDataElement|undefined),
- *   WiMAX: (CrOncDataElement|undefined),
- *   VPN: (CrOncDataElement|undefined)
+ *   Ethernet: (?NetworkStateProperties|undefined),
+ *   WiFi: (?NetworkStateProperties|undefined),
+ *   Cellular: (?NetworkStateProperties|undefined),
+ *   WiMAX: (?NetworkStateProperties|undefined),
+ *   VPN: (?NetworkStateProperties|undefined)
  * }}
  */
 var NetworkStateObject;
 
 /**
  * @typedef {{
- *   Ethernet: (Array<CrOncDataElement>|undefined),
- *   WiFi: (Array<CrOncDataElement>|undefined),
- *   Cellular: (Array<CrOncDataElement>|undefined),
- *   WiMAX: (Array<CrOncDataElement>|undefined),
- *   VPN: (Array<CrOncDataElement>|undefined)
+ *   Ethernet: (Array<NetworkStateProperties>|undefined),
+ *   WiFi: (Array<NetworkStateProperties>|undefined),
+ *   Cellular: (Array<NetworkStateProperties>|undefined),
+ *   WiMAX: (Array<NetworkStateProperties>|undefined),
+ *   VPN: (Array<NetworkStateProperties>|undefined)
  * }}
  */
 var NetworkStateListObject;
@@ -50,34 +50,39 @@
 /** @const {!Array<string>} */
 var NETWORK_TYPES = ['Ethernet', 'WiFi', 'Cellular', 'WiMAX', 'VPN'];
 
-Polymer('cr-network-summary', {
-  publish: {
+Polymer({
+  is: 'cr-network-summary',
+
+  properties: {
     /**
      * The device state for each network device type.
      *
-     * @attribute deviceStates
-     * @type {?DeviceStateObject}
-     * @default null
+     * @type {DeviceStateObject}
      */
-    deviceStates: null,
+    deviceStates: {
+      type: Object,
+      value: function() { return {}; },
+    },
 
     /**
      * Network state data for each network type.
      *
-     * @attribute networkStates
-     * @type {?NetworkStateObject}
-     * @default null
+     * @type {NetworkStateObject}
      */
-    networkStates: null,
+    networkStates: {
+      type: Object,
+      value: function() { return {}; },
+    },
 
     /**
      * List of network state data for each network type.
      *
-     * @attribute networkStateLists
-     * @type {?NetworkStateListObject}
-     * @default null
+     * @type {NetworkStateListObject}
      */
-    networkStateLists: null,
+    networkStateLists: {
+      type: Object,
+      value: function() { return {}; },
+    }
   },
 
   /**
@@ -110,15 +115,9 @@
   networkIds_: null,
 
   /** @override */
-  created: function() {
-    this.deviceStates = {};
-    this.networkStates = {};
-    this.networkStateLists = {};
-    this.networkIds_ = {};
-  },
-
-  /** @override */
   attached: function() {
+    this.networkIds_ = {};
+
     this.getNetworkLists_();
 
     this.networkListChangedListener_ =
@@ -160,16 +159,16 @@
 
   /**
    * Event triggered when a cr-network-summary-item is selected.
-   * @param {!{detail: !CrOncDataElement}} event
+   * @param {!{detail: !NetworkStateProperties}} event
    * @private
    */
   onSelected_: function(event) {
-    var onc = event.detail;
-    if (onc.disconnected()) {
-      this.connectToNetwork_(onc);
+    var state = event.detail;
+    if (state.ConnectionState == CrOnc.ConnectionState.NOT_CONNECTED) {
+      this.connectToNetwork_(state);
       return;
     }
-    MoreRouting.navigateTo('internet-detail', {guid: onc.data.GUID});
+    MoreRouting.navigateTo('internet-detail', {guid: state.GUID});
   },
 
   /**
@@ -214,11 +213,11 @@
   /**
    * Handles UI requests to connect to a network.
    * TODO(stevenjb): Handle Cellular activation, etc.
-   * @param {!CrOncDataElement} state The network state.
+   * @param {!NetworkStateProperties} state The network state.
    * @private
    */
   connectToNetwork_: function(state) {
-    chrome.networkingPrivate.startConnect(state.data.GUID);
+    chrome.networkingPrivate.startConnect(state.GUID);
   },
 
   /**
@@ -276,7 +275,7 @@
 
     // Get the first (active) state for each type.
     var foundTypes = {};
-    /** @type {!NetworkStateListObject} */ var oncNetworks = {
+    /** @type {!NetworkStateListObject} */ var networkStateLists = {
       Ethernet: [],
       WiFi: [],
       Cellular: [],
@@ -289,7 +288,7 @@
         foundTypes[type] = true;
         this.updateNetworkState_(type, state);
       }
-      oncNetworks[type].push(CrOncDataElement.create(state));
+      networkStateLists[type].push(state);
     }, this);
 
     // Set any types not found to a default value or null.
@@ -297,19 +296,18 @@
       if (!foundTypes[type]) {
         /** @type {NetworkStateProperties} */ var defaultState = null;
         if (this.deviceStates[type])
-          defaultState = { GUID: '', Type: 'WiFi' };
+          defaultState = { GUID: '', Type: type };
         this.updateNetworkState_(type, defaultState);
       }
     }, this);
 
-    // Set the network list for each type.
-    NETWORK_TYPES.forEach(function(type) {
-      this.networkStateLists[type] = oncNetworks[type];
-    }, this);
+    this.networkStateLists = networkStateLists;
 
     // Create a VPN entry in deviceStates if there are any VPN networks.
-    if (this.networkStateLists.VPN && this.networkStateLists.VPN.length > 0)
-      this.deviceStates.VPN = { Type: 'VPN', State: 'Enabled' };
+    if (networkStateLists.VPN && networkStateLists.VPN.length > 0) {
+      var vpn = { Type: 'VPN', State: 'Enabled' };
+      this.set('deviceStates.VPN', vpn);
+    }
   },
 
   /**
@@ -325,7 +323,6 @@
   },
 
   /**
-   * Creates a CrOncDataElement from the network state (if not null) for 'type'.
    * Sets 'networkStates[type]' which will update the cr-network-list-item
    * associated with 'type'.
    * @param {string} type The network type.
@@ -335,7 +332,7 @@
    * @private
    */
   updateNetworkState_: function(type, state) {
-    this.networkStates[type] = state ? CrOncDataElement.create(state) : null;
+    this.set('networkStates.' + type, state);
     if (state)
       this.networkIds_[state.GUID] = true;
   },
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.css b/chrome/browser/resources/settings/internet_page/network_summary_item.css
new file mode 100644
index 0000000..45b0994e
--- /dev/null
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.css
@@ -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. */
+
+#details.selectable:hover {
+  background-color: lightgrey;
+}
+
+#detailsItem {
+  margin-bottom: 10px;
+}
+
+#buttons {
+  align-items: center;
+}
+
+.invisible {
+  visibility: hidden;
+}
+
+#deviceEnabledButton {
+  margin: 0 10px;
+}
+
+#networkList {
+  margin: 0 70px 10px 40px;
+  max-height: 400px;
+}
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.html b/chrome/browser/resources/settings/internet_page/network_summary_item.html
index ea2dffd..2c8542bd 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.html
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.html
@@ -1,38 +1,36 @@
-<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_network_list/cr_network_list.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_network_list_item/cr_network_list_item.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_onc/cr_onc_data.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_toggle_button/cr_toggle_button.html">
-<link rel="import" href="network_summary_item_style.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_expand_button/cr_expand_button.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_network_list/cr_network_list.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_toggle_button/cr_toggle_button.html">
 
-<polymer-element name="cr-network-summary-item">
+<dom-module name="cr-network-summary-item">
+  <link rel="import" type="css" href="network_summary_item.css">
   <template>
-    <core-style ref="networkSummaryStyle"></core-style>
-    <div vertical layout hidden?="{{!deviceState}}">
-      <div id="details" horizontal layout on-click="{{onDetailsClicked_}}">
-        <cr-network-list-item id="detailsItem" flex
-            networkState="{{networkState}}">
+    <div class="layout vertical" hidden$="[[isHidden]]">
+      <div id="details" class="layout horizontal" on-click="onDetailsClicked_">
+        <cr-network-list-item id="detailsItem" class="flex"
+            network-state="[[networkState]]">
         </cr-network-list-item>
-        <div id="buttons" horizontal layout>
+        <div id="buttons" class="layout horizontal">
           <cr-expand-button id="expandListButton"
-              class="{{ {invisible: !expandIsVisible_(deviceState, networkStateList)} | tokenList }}"
+              class$="[[getExpandButtonClass_(deviceState, networkStateList)]]"
               expanded="{{expanded}}">
           </cr-expand-button>
           <cr-toggle-button id="deviceEnabledButton"
-              checked="{{deviceIsEnabled_(deviceState)}}"
-              class="{{ {invisible: !deviceEnabledIsVisible_(deviceState)} | tokenList }}"
-              on-click="{{onDeviceEnabledToggled_}}">
+              checked="[[deviceIsEnabled_(deviceState)]]"
+              class$="[[getDeviceEnabledButtonClass_(deviceState)]]"
+              on-click="onDeviceEnabledToggled_">
           </cr-toggle-button>
         </div>
       </div>
-      <cr-network-list id="networkList" vertical layout
-          maxHeight="{{maxHeight}}"
-          networks="{{networkStateList}}"
-          on-selected="{{onListItemSelected_}}"
+      <cr-network-list id="networkList" class="layout vertical"
+          max-height="[[maxHeight]]"
+          networks="[[networkStateList]]"
+          on-selected="onListItemSelected_"
           opened="{{expanded}}">
       </cr-network-list>
     </div>
   </template>
   <script src="network_summary_item.js"></script>
-</polymer-element>
+</dom-module>
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.js b/chrome/browser/resources/settings/internet_page/network_summary_item.js
index c81256c..cf8512b 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.js
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.js
@@ -11,58 +11,78 @@
 /** @typedef {chrome.networkingPrivate.DeviceStateProperties} */
 var DeviceStateProperties;
 
-Polymer('cr-network-summary-item', {
-  publish: {
+/** @typedef {chrome.networkingPrivate.NetworkStateProperties} */
+var NetworkStateProperties;
+
+Polymer({
+  is: 'cr-network-summary-item',
+
+  properties: {
     /**
      * True if the list is expanded.
-     *
-     * @attribute expanded
-     * @type {boolean}
-     * @default false
      */
-    expanded: false,
+    expanded: {
+      type: Boolean,
+      value: false,
+      observer: 'expandedChanged_'
+    },
 
     /**
      * The maximum height in pixels for the list of networks.
-     *
-     * @attribute maxHeight
-     * @type {number}
-     * @default 200
      */
-    maxHeight: 200,
+    maxHeight: {
+      type: Number,
+      value: 200
+    },
+
+    /**
+     * True if this item should be hidden. We need this computed property so
+     * that it can default to true, hiding this element, since no changed event
+     * will be fired for deviceState if it is undefined (in CrNetworkSummary).
+     */
+    isHidden: {
+      type: Boolean,
+      value: true,
+      computed: 'noDeviceState_(deviceState)'
+    },
 
     /**
      * Device state for the network type.
      *
-     * @attribute deviceState
      * @type {?DeviceStateProperties}
-     * @default null
      */
-    deviceState: null,
+    deviceState: {
+      type: Object,
+      value: null,
+      observer: 'deviceStateChanged_'
+    },
 
     /**
      * Network state for the active network.
      *
-     * @attribute networkState
-     * @type {?CrOncDataElement}
-     * @default null
+     * @type {?NetworkStateProperties}
      */
-    networkState: null,
+    networkState: {
+      type: Object,
+      value: null
+    },
 
     /**
      * List of all network state data for the network type.
      *
-     * @attribute networkStateList
-     * @type {?Array<!CrOncDataElement>}
-     * @default null
+     * @type {!Array<!NetworkStateProperties>}
      */
-    networkStateList: null,
+    networkStateList: {
+      type: Array,
+      value: function() { return []; },
+      observer: 'networkStateListChanged_'
+    }
   },
 
   /**
    * Polymer expanded changed method.
    */
-  expandedChanged: function() {
+  expandedChanged_: function() {
     var type = this.deviceState ? this.deviceState.Type : '';
     this.fire('expanded', {expanded: this.expanded, type: type});
   },
@@ -70,7 +90,7 @@
   /**
    * Polymer deviceState changed method.
    */
-  deviceStateChanged: function() {
+  deviceStateChanged_: function() {
     this.updateSelectable_();
     if (!this.deviceIsEnabled_(this.deviceState))
       this.expanded = false;
@@ -79,12 +99,21 @@
   /**
    * Polymer networkStateList changed method.
    */
-  networkStateListChanged: function() {
+  networkStateListChanged_: function() {
     this.updateSelectable_();
   },
 
   /**
    * @param {?DeviceStateProperties} deviceState The state of a device.
+   * @return {boolean} True if the device state is not set.
+   * @private
+   */
+  noDeviceState_: function(deviceState) {
+    return !deviceState;
+  },
+
+  /**
+   * @param {?DeviceStateProperties} deviceState The state of a device.
    * @return {boolean} Whether or not the device state is enabled.
    * @private
    */
@@ -94,22 +123,34 @@
 
   /**
    * @param {?DeviceStateProperties} deviceState The device state.
-   * @return {boolean} Whether or not to show the UI to enable the network.
+   * @return {string} The class value for the device enabled button.
    * @private
    */
-  deviceEnabledIsVisible_: function(deviceState) {
-    return deviceState &&
+  getDeviceEnabledButtonClass_: function(deviceState) {
+    var visible = deviceState &&
         deviceState.Type != 'Ethernet' && deviceState.Type != 'VPN';
+    return visible ? '' : 'invisible';
   },
 
   /**
    * @param {?DeviceStateProperties} deviceState The device state.
-   * @param {?Array<!CrOncDataElement>} networkList A list of networks.
+   * @param {!Array<!NetworkStateProperties>} networkList A list of networks.
+   * @return {string} The class value for the expand button.
+   * @private
+   */
+  getExpandButtonClass_: function(deviceState, networkList) {
+    var visible = this.expandIsVisible_(deviceState, networkList);
+    return visible ? '' : 'invisible';
+  },
+
+  /**
+   * @param {?DeviceStateProperties} deviceState The device state.
+   * @param {!Array<!NetworkStateProperties>} networkList A list of networks.
    * @return {boolean} Whether or not to show the UI to expand the list.
    * @private
    */
   expandIsVisible_: function(deviceState, networkList) {
-    if (!this.deviceIsEnabled_(deviceState) || !networkList)
+    if (!this.deviceIsEnabled_(deviceState))
       return false;
     var minLength = (this.type == 'WiFi') ? 1 : 2;
     return networkList.length >= minLength;
@@ -141,8 +182,8 @@
    * @private
    */
   onListItemSelected_: function(event) {
-    var onc = event.detail;
-    this.fire('selected', onc);
+    var state = event.detail;
+    this.fire('selected', state);
   },
 
   /**
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item_style.html b/chrome/browser/resources/settings/internet_page/network_summary_item_style.html
deleted file mode 100644
index 8792048..0000000
--- a/chrome/browser/resources/settings/internet_page/network_summary_item_style.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/core-style/core-style.html">
-
-<core-style id="networkSummaryStyle">
-
-#details.selectable:hover {
-  background-color: lightgrey;
-}
-
-#detailsItem {
-  margin-bottom: 10px;
-}
-
-#buttons {
-  align-items: center;
-}
-
-.invisible {
-  visibility: hidden;
-}
-
-#deviceEnabledButton {
-  margin: 0px 10px;
-}
-
-#networkList {
-  max-height: 400px;
-  margin: 0px 70px 10px 40px;
-}
-
-</core-style>
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_style.html b/chrome/browser/resources/settings/internet_page/network_summary_style.html
deleted file mode 100644
index 5621996..0000000
--- a/chrome/browser/resources/settings/internet_page/network_summary_style.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/core-style/core-style.html">
-
-<core-style id="networkSummaryStyle">
-
-#summary {
-  padding-right: 40px;
-}
-
-</core-style>
diff --git a/chrome/browser/resources/settings/pref_tracker/pref_tracker.js b/chrome/browser/resources/settings/pref_tracker/pref_tracker.js
index b042eca..0e372bea 100644
--- a/chrome/browser/resources/settings/pref_tracker/pref_tracker.js
+++ b/chrome/browser/resources/settings/pref_tracker/pref_tracker.js
@@ -68,14 +68,11 @@
           // HACK ALERT: This is the best clue we have as to the pref key for
           // this tracker. This value should not be relied upon anywhere or
           // actually used besides for this error message.
-          var keyHint = '';
-          var parentPrefString = this.parentNode && this.parentNode.host &&
-              this.parentNode.host.getAttribute('pref');
-          if (parentPrefString) {
-            keyHint = parentPrefString.match(/{{([a-z0-9._]+)}}/)[1];
-          }
+          var parentControlHTML = this.parentNode && this.parentNode.host &&
+              this.parentNode.host.outerHTML;
 
-          throw new Error('Pref not found. Key Hint: ' + keyHint);
+          throw new Error('Pref not found. Parent control:' +
+              (parentControlHTML || 'Unknown'));
         }
       });
     },
diff --git a/chrome/browser/resources/settings/routes.html b/chrome/browser/resources/settings/routes.html
index 5704c1e1..a2c70c48 100644
--- a/chrome/browser/resources/settings/routes.html
+++ b/chrome/browser/resources/settings/routes.html
@@ -16,3 +16,5 @@
 <more-route name="search" path="/search">
   <more-route name="search-engines" path="/engines"></more-route>
 </more-route>
+<more-route name="sync" path="/sync"></more-route>
+<more-route name="users" path="/users"></more-route>
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.html b/chrome/browser/resources/settings/settings_main/settings_main.html
index 3e26cf0..4b814bb0 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.html
+++ b/chrome/browser/resources/settings/settings_main/settings_main.html
@@ -1,5 +1,6 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/more-routing/more-routing.html">
 <link rel="import" href="chrome://md-settings/routes.html">
 <link rel="import" href="chrome://md-settings/settings_page/settings_page_header.html">
 <link rel="import" href="chrome://md-settings/a11y_page/a11y_page.html">
@@ -8,11 +9,10 @@
 <link rel="import" href="chrome://md-settings/downloads_page/downloads_page.html">
 <link rel="import" href="chrome://md-settings/search_engines_page/search_engines_page.html">
 <link rel="import" href="chrome://md-settings/search_page/search_page.html">
-
-<!-- TODO: Uncomment pages as they are upgraded.
+<link rel="import" href="chrome://md-settings/sync_page/sync_page.html">
+<link rel="import" href="chrome://md-settings/users_page/users_page.html">
 <link rel="import" href="chrome://md-settings/internet_page/internet_page.html">
 <link rel="import" href="chrome://md-settings/internet_page/internet_detail_page.html">
--->
 
 <dom-module id="cr-settings-main">
   <link rel="import" type="css" href="settings_main.css">
@@ -24,17 +24,13 @@
       <more-route-selector selected-params="{{params}}">
         <iron-pages id="pageContainer" selected-item="{{selectedPage}}"
             on-iron-select="onIronSelect_" attr-for-selected="PAGE_ID">
-          <!-- TODO: Uncomment pages as they are upgraded. -->
 <if expr="chromeos">
-          <!--
           <cr-settings-internet-page route="internet">
           </cr-settings-internet-page>
-          -->
-          <!--
           <cr-settings-internet-detail-page route="internet-detail"
-              subpage="true" guid="{{params.guid}}">
+              subpage="true" guid="[[params.guid]]"
+              selected-page="[[selectedPage]]">
           </cr-settings-internet-detail-page>
-          -->
 </if>
           <cr-settings-a11y-page prefs="{{prefs}}" route="a11y">
           </cr-settings-a11y-page>
@@ -49,6 +45,8 @@
           <cr-settings-search-page route="search"></cr-settings-search-page>
           <cr-settings-search-engines-page route="search-engines">
           </cr-settings-search-engines-page>
+          <cr-settings-sync-page route="sync"></cr-settings-sync-page>
+          <cr-settings-users-page route="users"></cr-settings-users-page>
         </iron-pages>
       </more-route-selector>
     </div>
diff --git a/chrome/browser/resources/settings/settings_page/settings_page.css b/chrome/browser/resources/settings/settings_page/settings_page.css
index 86a5e93..0dd8579 100644
--- a/chrome/browser/resources/settings/settings_page/settings_page.css
+++ b/chrome/browser/resources/settings/settings_page/settings_page.css
@@ -15,6 +15,15 @@
   padding-top: 40px;
 }
 
+.soft-border {
+  border: 1px solid #c4c4c4;
+  border-radius: 2px;
+}
+
+.page-content {
+  width: 760px;
+}
+
 cr-settings-page-header {
   margin-bottom: 30px;
   min-height: 24px;
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index d872dded..f9003fd 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -23,6 +23,9 @@
       <structure name="IDR_SETTINGS_A11Y_PAGE_CSS"
                  file="a11y_page/a11y_page.css"
                  type="chrome_html" />
+     <structure name="IDR_SETTINGS_APPEARANCE_PAGE_CSS"
+                 file="appearance_page/appearance_page.css"
+                 type="chrome_html" />
       <structure name="IDR_SETTINGS_APPEARANCE_PAGE_HTML"
                  file="appearance_page/appearance_page.html"
                  type="chrome_html"
@@ -184,6 +187,17 @@
       <structure name="IDR_SETTINGS_SEARCH_PAGE_CSS"
                  file="search_page/search_page.css"
                  type="chrome_html" />
+      <structure name="IDR_SETTINGS_SYNC_PAGE_JS"
+                 file="sync_page/sync_page.js"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_SYNC_PAGE_HTML"
+                 file="sync_page/sync_page.html"
+                 type="chrome_html"
+                 flattenhtml="true"
+                 allowexternalscript="true" />
+      <structure name="IDR_SETTINGS_SYNC_PAGE_CSS"
+                 file="sync_page/sync_page.css"
+                 type="chrome_html" />
       <structure name="IDR_SETTINGS_SETTINGS_HTML"
                  file="settings.html"
                  type="chrome_html" />
@@ -191,8 +205,8 @@
                  file="settings.js"
                  type="chrome_html" />
       <if expr="chromeos">
-        <structure name="IDR_SETTINGS_INTERNET_DETAIL_PAGE_STYLE_HTML"
-                   file="internet_page/internet_detail_page_style.html"
+        <structure name="IDR_SETTINGS_INTERNET_DETAIL_PAGE_CSS"
+                   file="internet_page/internet_detail_page.css"
                    type="chrome_html" />
         <structure name="IDR_SETTINGS_INTERNET_DETAIL_PAGE_HTML"
                    file="internet_page/internet_detail_page.html"
@@ -206,8 +220,8 @@
         <structure name="IDR_SETTINGS_INTERNET_PAGE_JS"
                    file="internet_page/internet_page.js"
                    type="chrome_html" />
-        <structure name="IDR_SETTINGS_NETWORK_SUMMARY_STYLE_HTML"
-                   file="internet_page/network_summary_style.html"
+        <structure name="IDR_SETTINGS_NETWORK_SUMMARY_CSS"
+                   file="internet_page/network_summary.css"
                    type="chrome_html" />
         <structure name="IDR_SETTINGS_NETWORK_SUMMARY_HTML"
                    file="internet_page/network_summary.html"
@@ -215,8 +229,8 @@
         <structure name="IDR_SETTINGS_NETWORK_SUMMARY_JS"
                    file="internet_page/network_summary.js"
                    type="chrome_html" />
-        <structure name="IDR_SETTINGS_NETWORK_SUMMARY_ITEM_STYLE_HTML"
-                   file="internet_page/network_summary_item_style.html"
+        <structure name="IDR_SETTINGS_NETWORK_SUMMARY_ITEM_CSS"
+                   file="internet_page/network_summary_item.css"
                    type="chrome_html" />
         <structure name="IDR_SETTINGS_NETWORK_SUMMARY_ITEM_HTML"
                    file="internet_page/network_summary_item.html"
@@ -224,6 +238,28 @@
         <structure name="IDR_SETTINGS_NETWORK_SUMMARY_ITEM_JS"
                    file="internet_page/network_summary_item.js"
                    type="chrome_html" />
+        <structure name="IDR_SETTINGS_USERS_PAGE_USER_LIST_JS"
+                   file="users_page/user_list.js"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_USERS_PAGE_USER_LIST_HTML"
+                   file="users_page/user_list.html"
+                   type="chrome_html"
+                   flattenhtml="true"
+                   allowexternalscript="true" />
+        <structure name="IDR_SETTINGS_USERS_PAGE_USER_LIST_CSS"
+                   file="users_page/user_list.css"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_USERS_PAGE_JS"
+                   file="users_page/users_page.js"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_USERS_PAGE_HTML"
+                   file="users_page/users_page.html"
+                   type="chrome_html"
+                   flattenhtml="true"
+                   allowexternalscript="true" />
+        <structure name="IDR_SETTINGS_USERS_PAGE_CSS"
+                   file="users_page/users_page.css"
+                   type="chrome_html" />
       </if>
     </structures>
   </release>
diff --git a/chrome/browser/resources/settings/sync_page/sync_page.css b/chrome/browser/resources/settings/sync_page/sync_page.css
new file mode 100644
index 0000000..3cf92e79
--- /dev/null
+++ b/chrome/browser/resources/settings/sync_page/sync_page.css
@@ -0,0 +1,22 @@
+/* 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. */
+
+paper-radio-button {
+  display: block;
+}
+
+.checkbox-container {
+  display: flex;
+  flex-flow: column;
+}
+
+.checkbox-container-row {
+  display: flex;
+}
+
+.checkbox-container-row > cr-checkbox {
+  display: flex;
+  flex-basis: 0;
+  flex-grow: 1;
+}
\ No newline at end of file
diff --git a/chrome/browser/resources/settings/sync_page/sync_page.html b/chrome/browser/resources/settings/sync_page/sync_page.html
new file mode 100644
index 0000000..f874331
--- /dev/null
+++ b/chrome/browser/resources/settings/sync_page/sync_page.html
@@ -0,0 +1,79 @@
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-material/paper-material.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-button/paper-radio-button.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-group/paper-radio-group.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_button/cr_button.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_checkbox/cr_checkbox.html">
+<link rel="import" href="chrome://md-settings/checkbox/checkbox.html">
+
+<dom-module id="cr-settings-sync-page">
+  <link rel="import" type="css"
+      href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="sync_page.css">
+  <template>
+    <paper-material>
+      <div i18n-content="syncPageTitle"></div>
+      <select>
+        <option value="sync-everything"
+            i18n-content="syncEverythingMenuOption">
+        </option>
+        <option value="choose-what-to-sync"
+            i18n-content="chooseWhatToSyncMenuOption">
+        </option>
+      </select>
+      <div class="checkbox-container">
+        <div class="checkbox-container-row">
+          <cr-checkbox>
+            <span i18n-content="appCheckboxLabel"></span>
+          </cr-checkbox>
+          <cr-checkbox>
+            <span i18n-content="extensionsCheckboxLabel"></span>
+          </cr-checkbox>
+          <cr-checkbox>
+            <span i18n-content="settingsCheckboxLabel"></span>
+          </cr-checkbox>
+        </div>
+        <div class="checkbox-container-row">
+          <cr-checkbox>
+            <span i18n-content="autofillCheckboxLabel"></span>
+          </cr-checkbox>
+          <cr-checkbox>
+            <span i18n-content="historyCheckboxLabel"></span>
+          </cr-checkbox>
+          <cr-checkbox>
+            <span i18n-content="themesAndWallpapersCheckboxLabel"></span>
+          </cr-checkbox>
+        </div>
+        <div class="checkbox-container-row">
+          <cr-checkbox>
+            <span i18n-content="bookmarksCheckboxLabel"></span>
+          </cr-checkbox>
+          <cr-checkbox>
+            <span i18n-content="passwordsCheckboxLabel"></span>
+          </cr-checkbox>
+          <cr-checkbox>
+            <span i18n-content="openTabsCheckboxLabel"></span>
+          </cr-checkbox>
+        </div>
+      </div>
+    </paper-material>
+    <paper-material>
+      <div i18n-content="encryptionOptionsTitle"></div>
+      <div i18n-content="syncDataEncryptedText"></div>
+      <paper-radio-group selected="encrypt-with-google">
+        <paper-radio-button name="encrypt-with-google"
+            i18n-content="encryptWithGoogleCredentialsLabel">
+        </paper-radio-button>
+        <paper-radio-button name="encrypt-with-passphrase"
+            i18n-content="encryptWithSyncPassphraseLabel">
+        </paper-radio-button>
+      </paper-radio-group>
+      <div>
+        <cr-button i18n-content="useDefaultSettingsButton"></cr-button>
+        <cr-button i18n-content="cancelButton"></cr-button>
+        <cr-button i18n-content="okButton"></cr-button>
+      </div>
+    </paper-material>
+  </template>
+  <script src="sync_page.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/sync_page/sync_page.js b/chrome/browser/resources/settings/sync_page/sync_page.js
new file mode 100644
index 0000000..f671e1f
--- /dev/null
+++ b/chrome/browser/resources/settings/sync_page/sync_page.js
@@ -0,0 +1,69 @@
+// 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
+ * 'cr-settings-sync-page' is the settings page containing sync settings.
+ *
+ * Example:
+ *
+ *    <iron-animated-pages>
+ *      <cr-settings-sync-page></cr-settings-sync-page>
+ *      ... other pages ...
+ *    </iron-animated-pages>
+ *
+ * @group Chrome Settings Elements
+ * @element cr-settings-sync-page
+ */
+Polymer({
+  is: 'cr-settings-sync-page',
+
+  properties: {
+    /**
+     * Route for the page.
+     */
+    route: {
+      type: String,
+      value: ''
+    },
+
+    /**
+     * Whether the page is a subpage.
+     * TODO(khorimoto): Make this a subpage once the "People" full page has
+     * landed, since this is supposed to be that page's subpage.
+     */
+    subpage: {
+      type: Boolean,
+      value: false,
+      readOnly: true,
+    },
+
+    /**
+     * ID of the page.
+     */
+    PAGE_ID: {
+      type: String,
+      value: 'sync',
+      readOnly: true,
+    },
+
+    /**
+     * Title for the page header and navigation menu.
+     */
+    pageTitle: {
+      type: String,
+      value: function() { return loadTimeData.getString('syncPageTitle'); },
+    },
+
+    /**
+     * Name of the 'iron-icon' to show.
+     * TODO(khorimoto): Find the correct icon to show.
+     */
+    icon: {
+      type: String,
+      value: 'accessibility',
+      readOnly: true,
+    },
+  },
+});
diff --git a/chrome/browser/resources/settings/users_page/user_list.css b/chrome/browser/resources/settings/users_page/user_list.css
new file mode 100644
index 0000000..dd10562b
--- /dev/null
+++ b/chrome/browser/resources/settings/users_page/user_list.css
@@ -0,0 +1,29 @@
+/* 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. */
+
+.clear-icon {
+  color: #6e6e6e;
+}
+
+.clear-icon::shadow iron-icon {
+  height: 18px;
+  width: 18px;
+}
+
+.user {
+  -webkit-padding-end: 8px;
+  -webkit-padding-start: 20px;
+  font-size: 0.75em;
+}
+
+.user:hover {
+  background-color: #f0f0f0;
+}
+
+.user-list {
+  border: 1px solid gray;
+  height: 160px;
+  overflow-y: auto;
+  padding: 10px 0;
+}
diff --git a/chrome/browser/resources/settings/users_page/user_list.html b/chrome/browser/resources/settings/users_page/user_list.html
new file mode 100644
index 0000000..e8a5014e
--- /dev/null
+++ b/chrome/browser/resources/settings/users_page/user_list.html
@@ -0,0 +1,23 @@
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
+
+<dom-module id="cr-settings-user-list">
+  <link rel="import" type="css" href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="user_list.css">
+  <template>
+    <div class="user-list soft-border">
+      <template is="dom-repeat" items="[[users]]">
+        <div class="user layout horizontal justified">
+          <div class="layout vertical center-justified">[[item.email]]</div>
+          <div class="close-button">
+            <paper-icon-button icon="clear" class="clear-icon"
+                on-click="removeUser_">
+            </paper-icon-button>
+          </div>
+        </div>
+      </template>
+    </div>
+  </template>
+  <script src="user_list.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/users_page/user_list.js b/chrome/browser/resources/settings/users_page/user_list.js
new file mode 100644
index 0000000..14e46c5
--- /dev/null
+++ b/chrome/browser/resources/settings/users_page/user_list.js
@@ -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.
+
+/**
+ * @fileoverview
+ * 'cr-settings-user-list' shows a list of users whitelisted on this Chrome OS
+ * device.
+ *
+ * Example:
+ *
+ *    <cr-settings-user-list prefs="{{prefs}}">
+ *    </cr-settings-user-list>
+ *
+ * @group Chrome Settings Elements
+ * @element cr-settings-user-list
+ */
+Polymer({
+  is: 'cr-settings-user-list',
+
+  properties: {
+    /**
+     * Current list of whitelisted users.
+     * @type {!Array<!User>}
+     */
+    users: {
+      type: Array,
+      value: function() { return []; },
+      notify: true
+    },
+  },
+
+  /** @override */
+  ready: function() {
+    chrome.settingsPrivate.onPrefsChanged.addListener(function(prefs) {
+      prefs.forEach(function(pref) {
+        if (pref.key == 'cros.accounts.users') {
+          chrome.usersPrivate.getWhitelistedUsers(function(users) {
+            this.users = users;
+          }.bind(this));
+        }
+      }, this);
+    });
+
+    chrome.usersPrivate.getWhitelistedUsers(function(users) {
+      this.users = users;
+    }.bind(this));
+  },
+
+  /** @private */
+  removeUser_: function(e) {
+    chrome.usersPrivate.removeWhitelistedUser(
+        e.model.item.email, /* callback */ function() {});
+  }
+});
+
diff --git a/chrome/browser/resources/settings/users_page/users_page.css b/chrome/browser/resources/settings/users_page/users_page.css
new file mode 100644
index 0000000..de1cfa5
--- /dev/null
+++ b/chrome/browser/resources/settings/users_page/users_page.css
@@ -0,0 +1,23 @@
+/* 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. */
+
+#addUserInput {
+  width: 100%;
+}
+
+.add-user-button {
+  padding-top: 25px;
+}
+
+.page-content > div {
+  margin-top: 30px;
+}
+
+.users {
+  -webkit-margin-start: 50px;
+}
+
+cr-input {
+  width: 300px;
+}
diff --git a/chrome/browser/resources/settings/users_page/users_page.html b/chrome/browser/resources/settings/users_page/users_page.html
new file mode 100644
index 0000000..ee2ec4b8
--- /dev/null
+++ b/chrome/browser/resources/settings/users_page/users_page.html
@@ -0,0 +1,54 @@
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-keys-behavior/iron-a11y-keys-behavior.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/paper-input/paper-input.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-material/paper-material.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_button/cr_button.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_input/cr_input.html">
+<link rel="import" href="chrome://md-settings/checkbox/checkbox.html">
+<link rel="import" href="user_list.html">
+
+<dom-module id="cr-settings-users-page">
+  <link rel="import" type="css" href="chrome://md-settings/settings_page/settings_page.css">
+  <link rel="import" type="css" href="users_page.css">
+  <template>
+    <paper-material>
+      <div class="page-content">
+        <div i18n-content="usersModifiedByOwnerLabel"></div>
+        <div>
+          <cr-settings-checkbox
+              pref="{{prefs.cros.accounts.allowBWSI}}"
+              i18n-values="label:guestBrowsingLabel">
+          </cr-settings-checkbox>
+          <cr-settings-checkbox
+              pref="{{prefs.cros.accounts.supervisedUsersEnabled}}"
+              i18n-values="label:supervisedUsersLabel">
+          </cr-settings-checkbox>
+          <cr-settings-checkbox
+              pref="{{prefs.cros.accounts.showUserNamesOnSignIn}}"
+              i18n-values="label:showOnSigninLabel">
+          </cr-settings-checkbox>
+
+          <!-- TODO(orenb): Invert this pref!!! -->
+          <cr-settings-checkbox
+              pref="{{prefs.cros.accounts.allowGuest}}"
+              i18n-values="label:restrictSigninLabel">
+          </cr-settings-checkbox>
+        </div>
+        <div class="users">
+          <div>
+            <cr-settings-user-list prefs="{{prefs}}"></cr-settings-user-list>
+          </div>
+          <div>
+            <cr-input i18n-values="label:addUsersLabel" id="addUserInput"></cr-input>
+            <div class="add-user-button layout horizontal end-justified">
+              <cr-button i18n-content="addLabel" on-click="addUser_" raised>
+              </cr-button>
+            </div>
+          </div>
+        </div>
+      </div>
+    </paper-material>
+  </template>
+  <script src="users_page.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/users_page/users_page.js b/chrome/browser/resources/settings/users_page/users_page.js
new file mode 100644
index 0000000..0694f073
--- /dev/null
+++ b/chrome/browser/resources/settings/users_page/users_page.js
@@ -0,0 +1,99 @@
+// 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
+ * 'cr-settings-users-page' is the settings page for managing user accounts on
+ * the device.
+ *
+ * Example:
+ *
+ *    <neon-animated-pages>
+ *      <cr-settings-users-page prefs="{{prefs}}">
+ *      </cr-settings-users-page>
+ *      ... other pages ...
+ *    </neon-animated-pages>
+ *
+ * @group Chrome Settings Elements
+ * @element cr-settings-users-page
+ */
+Polymer({
+  is: 'cr-settings-users-page',
+
+  behaviors: [
+    Polymer.IronA11yKeysBehavior
+  ],
+
+  properties: {
+    /**
+     * Preferences state.
+     */
+    prefs: {
+      type: Object,
+      notify: true,
+    },
+
+    /**
+     * Route for the page.
+     */
+    route: String,
+
+    /**
+     * Whether the page is a subpage.
+     */
+    subpage: {
+      type: Boolean,
+      value: false,
+      readOnly: true,
+    },
+
+    /**
+     * ID of the page.
+     */
+    PAGE_ID: {
+      type: String,
+      value: 'users',
+      readOnly: true,
+    },
+
+    /**
+     * Title for the page header and navigation menu.
+     */
+    pageTitle: {
+      type: String,
+      value: function() {
+        return loadTimeData.getString('usersPageTitle');
+      },
+    },
+
+    /**
+     * Name of the 'iron-icon' to show.
+     */
+    icon: {
+      type: String,
+      value: 'person',
+      readOnly: true,
+    },
+
+    /** @override */
+    keyEventTarget: {
+      type: Object,
+      value: function() {
+        return this.$.addUserInput;
+      }
+    }
+  },
+
+  keyBindings: {
+    'enter': 'addUser_'
+  },
+
+  /** @private */
+  addUser_: function() {
+    // TODO(orenb): Validate before adding.
+    chrome.usersPrivate.addWhitelistedUser(
+        this.$.addUserInput.value, /* callback */ function() {});
+    this.$.addUserInput.value = '';
+  }
+});
diff --git a/chrome/browser/resources/signin_internals/signin_index.html b/chrome/browser/resources/signin_internals/signin_index.html
index cca049f..9ab7197 100644
--- a/chrome/browser/resources/signin_internals/signin_index.html
+++ b/chrome/browser/resources/signin_internals/signin_index.html
@@ -58,10 +58,12 @@
       <table class="signin-details">
         <tr class="header">
           <td>Email Address</td>
+          <td>Gaia ID</td>
           <td>Validity</td>
         </tr>
         <tr jsselect="cookie_info">
           <td jscontent="email"></td>
+          <td jscontent="gaia_id"></td>
           <td jscontent="valid"></td>
         </tr>
       </table>
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
index 03e229e..59c36a8 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -14,6 +14,7 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/interstitials/security_interstitial_page_test_utils.h"
+#include "chrome/browser/net/url_request_mock_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/database_manager.h"
 #include "chrome/browser/safe_browsing/local_database_manager.h"
@@ -42,6 +43,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_browser_thread.h"
 #include "content/public/test/test_utils.h"
+#include "net/test/url_request/url_request_mock_http_job.h"
 
 using chrome_browser_interstitials::SecurityInterstitialIDNTest;
 using content::BrowserThread;
@@ -51,9 +53,9 @@
 
 namespace {
 
-const char kEmptyPage[] = "files/empty.html";
-const char kMalwarePage[] = "files/safe_browsing/malware.html";
-const char kMalwareIframe[] = "files/safe_browsing/malware_iframe.html";
+const char kEmptyPage[] = "empty.html";
+const char kMalwarePage[] = "safe_browsing/malware.html";
+const char kMalwareIframe[] = "safe_browsing/malware_iframe.html";
 
 // A SafeBrowsingDatabaseManager class that allows us to inject the malicious
 // URLs.
@@ -381,8 +383,10 @@
     MalwareDetails::RegisterFactory(NULL);
   }
 
-  void SetUpInProcessBrowserTestFixture() override {
-    ASSERT_TRUE(test_server()->Start());
+  void SetUpOnMainThread() override {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true));
   }
 
   void SetURLThreatType(const GURL& url, SBThreatType threat_type) {
@@ -397,7 +401,7 @@
   // Adds a safebrowsing result of the current test threat to the fake
   // safebrowsing service, navigates to that page, and returns the url.
   GURL SetupWarningAndNavigate() {
-    GURL url = test_server()->GetURL(kEmptyPage);
+    GURL url = net::URLRequestMockHTTPJob::GetMockUrl(kEmptyPage);
     SetURLThreatType(url, GetParam());
 
     ui_test_utils::NavigateToURL(browser(), url);
@@ -409,8 +413,8 @@
   // navigates to a page with an iframe containing the threat site, and returns
   // the url of the parent page.
   GURL SetupThreatIframeWarningAndNavigate() {
-    GURL url = test_server()->GetURL(kMalwarePage);
-    GURL iframe_url = test_server()->GetURL(kMalwareIframe);
+    GURL url = net::URLRequestMockHTTPJob::GetMockUrl(kMalwarePage);
+    GURL iframe_url = net::URLRequestMockHTTPJob::GetMockUrl(kMalwareIframe);
     SetURLThreatType(iframe_url, GetParam());
 
     ui_test_utils::NavigateToURL(browser(), url);
@@ -493,9 +497,9 @@
   }
 
   void MalwareRedirectCancelAndProceed(const std::string& open_function) {
-    GURL load_url = test_server()->GetURL(
-        "files/safe_browsing/interstitial_cancel.html");
-    GURL malware_url("http://localhost/files/safe_browsing/malware.html");
+    GURL load_url = net::URLRequestMockHTTPJob::GetMockUrl(
+        "safe_browsing/interstitial_cancel.html");
+    GURL malware_url = net::URLRequestMockHTTPJob::GetMockUrl(kMalwarePage);
     SetURLThreatType(malware_url, GetParam());
 
     // Load the test page.
@@ -791,13 +795,8 @@
   browser()->profile()->GetPrefs()->SetBoolean(
       prefs::kSafeBrowsingExtendedReportingEnabled, true);
 
-  net::SpawnedTestServer https_server(
-      net::SpawnedTestServer::TYPE_HTTPS, net::SpawnedTestServer::kLocalhost,
-      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
-  ASSERT_TRUE(https_server.Start());
-  GURL url = https_server.GetURL(kEmptyPage);
-
-  TestReportingDisabledAndDontProceed(url);
+  TestReportingDisabledAndDontProceed(
+      net::URLRequestMockHTTPJob::GetMockHttpsUrl(kEmptyPage));
 }
 
 // Verifies that the reporting checkbox is hidden when opt-in is
@@ -816,7 +815,8 @@
   browser()->profile()->GetPrefs()->SetBoolean(
       prefs::kSafeBrowsingExtendedReportingOptInAllowed, false);
 
-  TestReportingDisabledAndDontProceed(test_server()->GetURL(kEmptyPage));
+  TestReportingDisabledAndDontProceed(
+      net::URLRequestMockHTTPJob::GetMockUrl(kEmptyPage));
 }
 
 IN_PROC_BROWSER_TEST_P(SafeBrowsingBlockingPageBrowserTest, LearnMore) {
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index 655971b..0d7f7da 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -235,13 +235,13 @@
           make_scoped_refptr(g_browser_process->system_request_context())));
 
 #if defined(FULL_SAFE_BROWSING)
-#if !defined(SAFE_BROWSING_CSD)
+#if defined(SAFE_BROWSING_CSD)
   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableClientSidePhishingDetection)) {
     csd_service_.reset(safe_browsing::ClientSideDetectionService::Create(
         url_request_context_getter_.get()));
   }
-#endif  // !defined(SAFE_BROWSING_CSD)
+#endif  // defined(SAFE_BROWSING_CSD)
 
 // TODO(nparker): Adding SAFE_BROWSING_SERVICE_DOWNLOAD to control this might
 // allow removing FULL_SAFE_BROWSING above.
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index bde9836..4379465 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -17,6 +17,7 @@
 #include "base/path_service.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
 #include "base/test/thread_test_helper.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
@@ -44,9 +45,14 @@
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/web_contents.h"
 #include "net/cookies/cookie_store.h"
+#include "net/cookies/cookie_util.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
 #include "sql/connection.h"
 #include "sql/statement.h"
 #include "testing/gmock/include/gmock/gmock.h"
+#include "url/gurl.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -470,7 +476,10 @@
   }
 
   void SetUpInProcessBrowserTestFixture() override {
-    ASSERT_TRUE(test_server()->Start());
+    base::FilePath test_data_dir;
+    PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
+    embedded_test_server()->ServeFilesFromDirectory(test_data_dir);
+    ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
   }
 
   // This will setup the "url" prefix in database and prepare protocol manager
@@ -524,6 +533,10 @@
         safe_browsing::ClientSideDetectionService::Create(NULL);
     SafeBrowsingService* sb_service =
         g_browser_process->safe_browsing_service();
+
+    // A CSD service should already exist.
+    EXPECT_TRUE(sb_service->csd_service_);
+
     sb_service->csd_service_.reset(csd_service);
     sb_service->RefreshState();
 #endif
@@ -614,15 +627,15 @@
 
 namespace {
 
-const char kEmptyPage[] = "files/empty.html";
-const char kMalwareFile[] = "files/downloads/dangerous/dangerous.exe";
-const char kMalwarePage[] = "files/safe_browsing/malware.html";
-const char kMalwareIFrame[] = "files/safe_browsing/malware_iframe.html";
-const char kMalwareImg[] = "files/safe_browsing/malware_image.png";
+const char kEmptyPage[] = "/empty.html";
+const char kMalwareFile[] = "/downloads/dangerous/dangerous.exe";
+const char kMalwarePage[] = "/safe_browsing/malware.html";
+const char kMalwareIFrame[] = "/safe_browsing/malware_iframe.html";
+const char kMalwareImg[] = "/safe_browsing/malware_image.png";
 
 // This test goes through DownloadResourceHandler.
 IN_PROC_BROWSER_TEST_P(SafeBrowsingServiceMetadataTest, MalwareMainFrame) {
-  GURL url = test_server()->GetURL(kEmptyPage);
+  GURL url = embedded_test_server()->GetURL(kEmptyPage);
 
   // After adding the url to safebrowsing database and getfullhash result,
   // we should see the interstitial page.
@@ -638,8 +651,8 @@
 }
 
 IN_PROC_BROWSER_TEST_P(SafeBrowsingServiceMetadataTest, MalwareIFrame) {
-  GURL main_url = test_server()->GetURL(kMalwarePage);
-  GURL iframe_url = test_server()->GetURL(kMalwareIFrame);
+  GURL main_url = embedded_test_server()->GetURL(kMalwarePage);
+  GURL iframe_url = embedded_test_server()->GetURL(kMalwareIFrame);
 
   // Add the iframe url as malware and then load the parent page.
   SBFullHashResult malware_full_hash;
@@ -655,8 +668,8 @@
 }
 
 IN_PROC_BROWSER_TEST_P(SafeBrowsingServiceMetadataTest, MalwareImg) {
-  GURL main_url = test_server()->GetURL(kMalwarePage);
-  GURL img_url = test_server()->GetURL(kMalwareImg);
+  GURL main_url = embedded_test_server()->GetURL(kMalwarePage);
+  GURL img_url = embedded_test_server()->GetURL(kMalwareImg);
 
   // Add the img url as malware and then load the parent page.
   SBFullHashResult malware_full_hash;
@@ -695,8 +708,8 @@
                                         METADATA_DISTRIBUTION));
 
 IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, UnwantedImgIgnored) {
-  GURL main_url = test_server()->GetURL(kMalwarePage);
-  GURL img_url = test_server()->GetURL(kMalwareImg);
+  GURL main_url = embedded_test_server()->GetURL(kMalwarePage);
+  GURL img_url = embedded_test_server()->GetURL(kMalwareImg);
 
   // Add the img url as coming from a site serving UwS and then load the parent
   // page.
@@ -711,7 +724,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, DISABLED_MalwareWithWhitelist) {
-  GURL url = test_server()->GetURL(kEmptyPage);
+  GURL url = embedded_test_server()->GetURL(kEmptyPage);
 
   // After adding the url to safebrowsing database and getfullhash result,
   // we should see the interstitial page.
@@ -739,13 +752,13 @@
   EXPECT_FALSE(ShowingInterstitialPage());
 }
 
-const char kPrefetchMalwarePage[] = "files/safe_browsing/prefetch_malware.html";
+const char kPrefetchMalwarePage[] = "/safe_browsing/prefetch_malware.html";
 
 // This test confirms that prefetches don't themselves get the
 // interstitial treatment.
 IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, Prefetch) {
-  GURL url = test_server()->GetURL(kPrefetchMalwarePage);
-  GURL malware_url = test_server()->GetURL(kMalwarePage);
+  GURL url = embedded_test_server()->GetURL(kPrefetchMalwarePage);
+  GURL malware_url = embedded_test_server()->GetURL(kMalwarePage);
 
   class SetPrefetchForTest {
    public:
@@ -877,7 +890,7 @@
 namespace {
 
 IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckDownloadUrl) {
-  GURL badbin_url = test_server()->GetURL(kMalwareFile);
+  GURL badbin_url = embedded_test_server()->GetURL(kMalwareFile);
   std::vector<GURL> badbin_urls(1, badbin_url);
 
   scoped_refptr<TestSBClient> client(new TestSBClient);
@@ -898,7 +911,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckUnwantedSoftwareUrl) {
-  const GURL bad_url = test_server()->GetURL(kMalwareFile);
+  const GURL bad_url = embedded_test_server()->GetURL(kMalwareFile);
   {
     scoped_refptr<TestSBClient> client(new TestSBClient);
 
@@ -940,7 +953,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckBrowseUrl) {
-  const GURL bad_url = test_server()->GetURL(kMalwareFile);
+  const GURL bad_url = embedded_test_server()->GetURL(kMalwareFile);
   {
     scoped_refptr<TestSBClient> client(new TestSBClient);
 
@@ -983,9 +996,9 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckDownloadUrlRedirects) {
-  GURL original_url = test_server()->GetURL(kEmptyPage);
-  GURL badbin_url = test_server()->GetURL(kMalwareFile);
-  GURL final_url = test_server()->GetURL(kEmptyPage);
+  GURL original_url = embedded_test_server()->GetURL(kEmptyPage);
+  GURL badbin_url = embedded_test_server()->GetURL(kMalwareFile);
+  GURL final_url = embedded_test_server()->GetURL(kEmptyPage);
   std::vector<GURL> badbin_urls;
   badbin_urls.push_back(original_url);
   badbin_urls.push_back(badbin_url);
@@ -1016,7 +1029,7 @@
 #endif
 IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest,
                        MAYBE_CheckDownloadUrlTimedOut) {
-  GURL badbin_url = test_server()->GetURL(kMalwareFile);
+  GURL badbin_url = embedded_test_server()->GetURL(kMalwareFile);
   std::vector<GURL> badbin_urls(1, badbin_url);
 
   scoped_refptr<TestSBClient> client(new TestSBClient);
@@ -1188,13 +1201,12 @@
 
   void SetUp() override {
     // We need to start the test server to get the host&port in the url.
-    ASSERT_TRUE(test_server()->Start());
+    ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+    embedded_test_server()->RegisterRequestHandler(
+        base::Bind(&SafeBrowsingDatabaseManagerCookieTest::HandleRequest));
 
     // Point to the testing server for all SafeBrowsing requests.
-    GURL url_prefix = test_server()->GetURL(
-        "expect-and-set-cookie?expect=a%3db"
-        "&set=c%3dd%3b%20Expires=Fri,%2001%20Jan%202038%2001:01:01%20GMT"
-        "&data=foo#");
+    GURL url_prefix = embedded_test_server()->GetURL("/testpath");
     sb_factory_.reset(new TestSafeBrowsingServiceFactory(url_prefix.spec()));
     SafeBrowsingService::RegisterFactory(sb_factory_.get());
 
@@ -1241,7 +1253,7 @@
       EXPECT_TRUE(false);
       return false;
     }
-    if (!smt.BindString(0, test_server()->host_port_pair().host())) {
+    if (!smt.BindString(0, embedded_test_server()->base_url().host())) {
       EXPECT_TRUE(false);
       return false;
     }
@@ -1289,6 +1301,42 @@
   scoped_refptr<SafeBrowsingService> sb_service_;
 
  private:
+  static scoped_ptr<net::test_server::HttpResponse> HandleRequest(
+      const net::test_server::HttpRequest& request) {
+    if (!StartsWithASCII(request.relative_url, "/testpath/", true)) {
+      ADD_FAILURE() << "bad path";
+      return nullptr;
+    }
+
+    auto cookie_it = request.headers.find("Cookie");
+    if (cookie_it == request.headers.end()) {
+      ADD_FAILURE() << "no cookie header";
+      return nullptr;
+    }
+
+    net::cookie_util::ParsedRequestCookies req_cookies;
+    net::cookie_util::ParseRequestCookieLine(cookie_it->second, &req_cookies);
+    if (req_cookies.size() != 1) {
+      ADD_FAILURE() << "req_cookies.size() = " << req_cookies.size();
+      return nullptr;
+    }
+    const net::cookie_util::ParsedRequestCookie expected_cookie(
+        std::make_pair("a", "b"));
+    const net::cookie_util::ParsedRequestCookie& cookie = req_cookies.front();
+    if (cookie != expected_cookie) {
+      ADD_FAILURE() << "bad cookie " << cookie.first << "=" << cookie.second;
+      return nullptr;
+    }
+
+    scoped_ptr<net::test_server::BasicHttpResponse> http_response(
+        new net::test_server::BasicHttpResponse());
+    http_response->set_content("foo");
+    http_response->set_content_type("text/plain");
+    http_response->AddCustomHeader(
+        "Set-Cookie", "c=d; Expires=Fri, 01 Jan 2038 01:01:01 GMT");
+    return http_response.Pass();
+  }
+
   scoped_ptr<TestSafeBrowsingServiceFactory> sb_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingDatabaseManagerCookieTest);
diff --git a/chrome/browser/signin/account_reconcilor_unittest.cc b/chrome/browser/signin/account_reconcilor_unittest.cc
index 88a39c5..5ccfb01a 100644
--- a/chrome/browser/signin/account_reconcilor_unittest.cc
+++ b/chrome/browser/signin/account_reconcilor_unittest.cc
@@ -330,10 +330,10 @@
   base::RunLoop().RunUntilIdle();
   ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_RUNNING, reconcilor->GetState());
 
-  std::vector<std::pair<std::string, bool> > accounts;
+  std::vector<gaia::ListedAccount> accounts;
   ASSERT_TRUE(cookie_manager_service()->ListAccounts(&accounts));
   ASSERT_EQ(1u, accounts.size());
-  ASSERT_EQ(account_id, accounts[0].first);
+  ASSERT_EQ(account_id, accounts[0].email);
 }
 
 TEST_F(AccountReconcilorTest, GetAccountsFromCookieFailure) {
@@ -350,7 +350,7 @@
             reconcilor->GetState());
   base::RunLoop().RunUntilIdle();
 
-  std::vector<std::pair<std::string, bool> > accounts;
+  std::vector<gaia::ListedAccount> accounts;
   ASSERT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
   ASSERT_EQ(0u, accounts.size());
 
@@ -397,7 +397,7 @@
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 
   base::RunLoop().RunUntilIdle();
-  std::vector<std::pair<std::string, bool> > accounts;
+  std::vector<gaia::ListedAccount> accounts;
   // This will be the first call to ListAccounts.
   ASSERT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc
index cc4aed9..e30bce3 100644
--- a/chrome/browser/signin/chrome_signin_client.cc
+++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -322,3 +322,10 @@
   }
 #endif
 }
+
+GaiaAuthFetcher* ChromeSigninClient::CreateGaiaAuthFetcher(
+    GaiaAuthConsumer* consumer,
+    const std::string& source,
+    net::URLRequestContextGetter* getter) {
+  return new GaiaAuthFetcher(consumer, source, getter);
+}
diff --git a/chrome/browser/signin/chrome_signin_client.h b/chrome/browser/signin/chrome_signin_client.h
index 34003178..2d57fb9 100644
--- a/chrome/browser/signin/chrome_signin_client.h
+++ b/chrome/browser/signin/chrome_signin_client.h
@@ -53,6 +53,10 @@
   void RemoveContentSettingsObserver(
       content_settings::Observer* observer) override;
   void DelayNetworkCall(const base::Closure& callback) override;
+  GaiaAuthFetcher* CreateGaiaAuthFetcher(
+      GaiaAuthConsumer* consumer,
+      const std::string& source,
+      net::URLRequestContextGetter* getter) override;
 
   // Returns a string describing the chrome version environment. Version format:
   // <Build Info> <OS> <Version number> (<Last change>)<channel or "-devel">
diff --git a/chrome/browser/signin/cross_device_promo.cc b/chrome/browser/signin/cross_device_promo.cc
index 095591d..eebfbc4 100644
--- a/chrome/browser/signin/cross_device_promo.cc
+++ b/chrome/browser/signin/cross_device_promo.cc
@@ -387,7 +387,7 @@
 }
 
 void CrossDevicePromo::OnGaiaAccountsInCookieUpdated(
-    const std::vector<std::pair<std::string, bool>>& accounts,
+    const std::vector<gaia::ListedAccount>& accounts,
     const GoogleServiceAuthError& error) {
   VLOG(1) << "CrossDevicePromo::OnGaiaAccountsInCookieUpdated. "
           << accounts.size() << " accounts with auth error " << error.state();
diff --git a/chrome/browser/signin/cross_device_promo.h b/chrome/browser/signin/cross_device_promo.h
index 50dd479..9913196f9 100644
--- a/chrome/browser/signin/cross_device_promo.h
+++ b/chrome/browser/signin/cross_device_promo.h
@@ -44,7 +44,7 @@
 
   // GaiaCookieManagerService::Observer:
   void OnGaiaAccountsInCookieUpdated(
-      const std::vector<std::pair<std::string, bool>>& accounts,
+      const std::vector<gaia::ListedAccount>& accounts,
       const GoogleServiceAuthError& error) override;
 
   // DeviceActivityFetcher::Observer:
diff --git a/chrome/browser/signin/cross_device_promo_unittest.cc b/chrome/browser/signin/cross_device_promo_unittest.cc
index 604a674..9f224022 100644
--- a/chrome/browser/signin/cross_device_promo_unittest.cc
+++ b/chrome/browser/signin/cross_device_promo_unittest.cc
@@ -286,7 +286,7 @@
 
   ASSERT_FALSE(prefs()->HasPrefPath(
       prefs::kCrossDevicePromoObservedSingleAccountCookie));
-  std::vector<std::pair<std::string, bool>> accounts;
+  std::vector<gaia::ListedAccount> accounts;
 
   // Setting a single cookie sets the time.
   base::Time before_setting_cookies = base::Time::Now();
@@ -356,7 +356,7 @@
   // Notice a single account.
   {
     base::HistogramTester test_single_account;
-    std::vector<std::pair<std::string, bool>> accounts;
+    std::vector<gaia::ListedAccount> accounts;
     cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
     cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
     EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
@@ -386,7 +386,7 @@
   EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
   cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
   cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
-  std::vector<std::pair<std::string, bool>> accounts;
+  std::vector<gaia::ListedAccount> accounts;
   EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
   base::RunLoop().RunUntilIdle();
 
@@ -456,7 +456,7 @@
   EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
   cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
   cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
-  std::vector<std::pair<std::string, bool>> accounts;
+  std::vector<gaia::ListedAccount> accounts;
   EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
   base::RunLoop().RunUntilIdle();
 
@@ -478,7 +478,7 @@
   EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
   cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
   cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
-  std::vector<std::pair<std::string, bool>> accounts;
+  std::vector<gaia::ListedAccount> accounts;
   EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
   base::RunLoop().RunUntilIdle();
   prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime,
@@ -506,7 +506,7 @@
   EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
   cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
   cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
-  std::vector<std::pair<std::string, bool>> accounts;
+  std::vector<gaia::ListedAccount> accounts;
   EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
   base::RunLoop().RunUntilIdle();
   prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime,
diff --git a/chrome/browser/signin/fake_gaia_cookie_manager_service.cc b/chrome/browser/signin/fake_gaia_cookie_manager_service.cc
index 0203d46f..4c767d0 100644
--- a/chrome/browser/signin/fake_gaia_cookie_manager_service.cc
+++ b/chrome/browser/signin/fake_gaia_cookie_manager_service.cc
@@ -61,7 +61,7 @@
       GaiaUrls::GetInstance()->ListAccountsURLWithSource(
           GaiaConstants::kChromeSource),
       base::StringPrintf(
-          "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, 1]]]",
+          "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, 1, \"22\"]]]",
           account),
       net::HTTP_OK,
       net::URLRequestStatus::SUCCESS);
@@ -74,7 +74,7 @@
       GaiaUrls::GetInstance()->ListAccountsURLWithSource(
           GaiaConstants::kChromeSource),
       base::StringPrintf(
-          "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d]]]",
+          "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d, \"22\"]]]",
           account, expired ? 0 : 1),
       net::HTTP_OK,
       net::URLRequestStatus::SUCCESS);
@@ -87,8 +87,8 @@
       GaiaUrls::GetInstance()->ListAccountsURLWithSource(
           GaiaConstants::kChromeSource),
       base::StringPrintf(
-          "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, 1], "
-          "[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, 1]]]",
+          "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, 1, \"22\"], "
+          "[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, 1, \"24\"]]]",
           account1, account2),
       net::HTTP_OK,
       net::URLRequestStatus::SUCCESS);
@@ -102,8 +102,8 @@
       GaiaUrls::GetInstance()->ListAccountsURLWithSource(
           GaiaConstants::kChromeSource),
       base::StringPrintf(
-          "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d], "
-          "[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d]]]",
+          "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d, \"28\"], "
+          "[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d, \"29\"]]]",
           account1, account1_expired ? 0 : 1,
           account2, account2_expired ? 0 : 1),
       net::HTTP_OK,
diff --git a/chrome/browser/sync/glue/typed_url_change_processor.cc b/chrome/browser/sync/glue/typed_url_change_processor.cc
index b00cd3d..28b78a6e 100644
--- a/chrome/browser/sync/glue/typed_url_change_processor.cc
+++ b/chrome/browser/sync/glue/typed_url_change_processor.cc
@@ -157,6 +157,14 @@
     return false;
   }
 
+  if (std::find_if(visit_vector.begin(), visit_vector.end(),
+                   [](const history::VisitRow& visit) {
+                     return ui::PageTransitionCoreTypeIs(
+                         visit.transition, ui::PAGE_TRANSITION_TYPED);
+                   }) == visit_vector.end())
+    // This URL has no TYPED visits, don't sync it.
+    return false;
+
   syncer::ReadNode typed_url_root(trans);
   if (typed_url_root.InitTypeRoot(syncer::TYPED_URLS) !=
           syncer::BaseNode::INIT_OK) {
diff --git a/chrome/browser/sync/profile_sync_components_factory_impl.cc b/chrome/browser/sync/profile_sync_components_factory_impl.cc
index 75db227..3175f55 100644
--- a/chrome/browser/sync/profile_sync_components_factory_impl.cc
+++ b/chrome/browser/sync/profile_sync_components_factory_impl.cc
@@ -45,6 +45,7 @@
 #include "chrome/common/pref_names.h"
 #include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
+#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/autofill_pref_names.h"
@@ -519,7 +520,8 @@
         return autofill::AutofillProfileSyncableService::FromWebDataService(
             web_data_service_.get())->AsWeakPtr();
       } else if (type == syncer::AUTOFILL_WALLET_METADATA) {
-        return base::WeakPtr<syncer::SyncableService>();
+        return autofill::AutofillWalletMetadataSyncableService::
+            FromWebDataService(web_data_service_.get())->AsWeakPtr();
       }
       return autofill::AutofillWalletSyncableService::FromWebDataService(
           web_data_service_.get())->AsWeakPtr();
diff --git a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
index 6de5a89..802bde3f 100644
--- a/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_autofill_unittest.cc
@@ -1088,7 +1088,7 @@
       "91601", "US", "19482937549");
 
   AutofillProfile expected_profile(sync_profile);
-  expected_profile.OverwriteWithOrAddTo(*native_profile, "en-US");
+  expected_profile.OverwriteWith(*native_profile, "en-US");
 
   std::vector<AutofillProfile*> native_profiles;
   native_profiles.push_back(native_profile);
diff --git a/chrome/browser/sync/test/integration/two_client_typed_urls_sync_test.cc b/chrome/browser/sync/test/integration/two_client_typed_urls_sync_test.cc
index dc18a04..b9d1447c 100644
--- a/chrome/browser/sync/test/integration/two_client_typed_urls_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_typed_urls_sync_test.cc
@@ -377,6 +377,44 @@
   ASSERT_EQ(2, GetVisitCountForFirstURL(0));
 }
 
+IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest,
+                       DontSyncUpdatedNonTypedURLs) {
+  // Checks if a non-typed URL that has been updated (modified) doesn't get
+  // synced. This is a regression test after fixing a bug where adding a
+  // non-typed URL was guarded against but later modifying it was not. Since
+  // "update" is "update or create if missing", non-typed URLs were being
+  // created.
+  const GURL kNonTypedURL("http://link.google.com/");
+  const GURL kTypedURL("http://typed.google.com/");
+  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  AddUrlToHistoryWithTransition(0, kNonTypedURL, ui::PAGE_TRANSITION_LINK,
+                                history::SOURCE_BROWSED);
+  AddUrlToHistoryWithTransition(0, kTypedURL, ui::PAGE_TRANSITION_TYPED,
+                                history::SOURCE_BROWSED);
+
+  // Modify the non-typed URL. It should not get synced.
+  typed_urls_helper::SetPageTitle(0, kNonTypedURL, "Welcome to Non-Typed URL");
+  ASSERT_TRUE(AwaitCheckAllProfilesHaveSameURLsAsVerifier());
+
+  history::VisitVector visits;
+  // First client has both visits.
+  visits = typed_urls_helper::GetVisitsForURLFromClient(0, kNonTypedURL);
+  ASSERT_EQ(1U, visits.size());
+  EXPECT_TRUE(ui::PageTransitionCoreTypeIs(visits[0].transition,
+                                           ui::PAGE_TRANSITION_LINK));
+  visits = typed_urls_helper::GetVisitsForURLFromClient(0, kTypedURL);
+  ASSERT_EQ(1U, visits.size());
+  EXPECT_TRUE(ui::PageTransitionCoreTypeIs(visits[0].transition,
+                                           ui::PAGE_TRANSITION_TYPED));
+  // Second client has only the typed visit.
+  visits = typed_urls_helper::GetVisitsForURLFromClient(1, kNonTypedURL);
+  ASSERT_EQ(0U, visits.size());
+  visits = typed_urls_helper::GetVisitsForURLFromClient(1, kTypedURL);
+  ASSERT_EQ(1U, visits.size());
+  EXPECT_TRUE(ui::PageTransitionCoreTypeIs(visits[0].transition,
+                                           ui::PAGE_TRANSITION_TYPED));
+}
+
 IN_PROC_BROWSER_TEST_F(TwoClientTypedUrlsSyncTest, SyncTypedRedirects) {
   const base::string16 kHistoryUrl(ASCIIToUTF16("http://typed.google.com/"));
   const base::string16 kRedirectedHistoryUrl(
diff --git a/chrome/browser/sync/test/integration/typed_urls_helper.cc b/chrome/browser/sync/test/integration/typed_urls_helper.cc
index 3df8d885..8d4fb86 100644
--- a/chrome/browser/sync/test/integration/typed_urls_helper.cc
+++ b/chrome/browser/sync/test/integration/typed_urls_helper.cc
@@ -169,7 +169,6 @@
                    transition,
                    source,
                    false);
-  service->SetPageTitle(url, base::ASCIIToUTF16(url.spec() + " - title"));
 }
 
 history::URLRows GetTypedUrlsFromHistoryService(
@@ -332,6 +331,16 @@
   WaitForHistoryDBThread(index);
 }
 
+void SetPageTitle(int index, const GURL& url, const std::string& title) {
+  HistoryServiceFactory::GetForProfileWithoutCreating(test()->GetProfile(index))
+      ->SetPageTitle(url, base::UTF8ToUTF16(title));
+  if (test()->use_verifier())
+    HistoryServiceFactory::GetForProfile(test()->verifier(),
+                                         ServiceAccessType::IMPLICIT_ACCESS)
+        ->SetPageTitle(url, base::UTF8ToUTF16(title));
+  WaitForHistoryDBThread(index);
+}
+
 bool CheckURLRowVectorsAreEqual(const history::URLRows& left,
                                 const history::URLRows& right) {
   if (left.size() != right.size())
diff --git a/chrome/browser/sync/test/integration/typed_urls_helper.h b/chrome/browser/sync/test/integration/typed_urls_helper.h
index 1a5bbdd..ce3ad2a 100644
--- a/chrome/browser/sync/test/integration/typed_urls_helper.h
+++ b/chrome/browser/sync/test/integration/typed_urls_helper.h
@@ -61,6 +61,9 @@
 // profile.
 void DeleteUrlsFromHistory(int index, const std::vector<GURL>& urls);
 
+// Modifies an URL stored in history by setting a new title.
+void SetPageTitle(int index, const GURL& url, const std::string& title);
+
 // Returns true if all clients match the verifier profile.
 bool CheckAllProfilesHaveSameURLsAsVerifier();
 
diff --git a/chrome/browser/task_management/providers/web_contents/background_contents_tag.cc b/chrome/browser/task_management/providers/web_contents/background_contents_tag.cc
new file mode 100644
index 0000000..fb484263
--- /dev/null
+++ b/chrome/browser/task_management/providers/web_contents/background_contents_tag.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 "chrome/browser/task_management/providers/web_contents/background_contents_tag.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/background/background_contents.h"
+#include "chrome/browser/background/background_contents_service.h"
+#include "chrome/browser/background/background_contents_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/task_management/providers/web_contents/background_contents_task.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_set.h"
+
+namespace task_management {
+
+BackgroundContentsTask* BackgroundContentsTag::CreateTask() const {
+  // Try to lookup the application name from the parent extension (if any).
+  Profile* profile = Profile::FromBrowserContext(
+      web_contents()->GetBrowserContext());
+  BackgroundContentsService* background_contents_service =
+      BackgroundContentsServiceFactory::GetForProfile(profile);
+  const base::string16& application_id =
+      background_contents_service->GetParentApplicationId(background_contents_);
+  const extensions::ExtensionSet& extensions_set =
+      extensions::ExtensionRegistry::Get(profile)->enabled_extensions();
+  const extensions::Extension* extension =
+      extensions_set.GetByID(base::UTF16ToUTF8(application_id));
+  base::string16 application_name;
+  if (extension)
+    application_name = base::UTF8ToUTF16(extension->name());
+
+  return new BackgroundContentsTask(application_name, background_contents_);
+}
+
+BackgroundContentsTag::BackgroundContentsTag(
+    content::WebContents* web_contents,
+    BackgroundContents* background_contents)
+    : WebContentsTag(web_contents),
+      background_contents_(background_contents) {
+  DCHECK(web_contents);
+  DCHECK(background_contents);
+}
+
+BackgroundContentsTag::~BackgroundContentsTag() {
+}
+
+}  // namespace task_management
diff --git a/chrome/browser/task_management/providers/web_contents/background_contents_tag.h b/chrome/browser/task_management/providers/web_contents/background_contents_tag.h
new file mode 100644
index 0000000..01720b5a
--- /dev/null
+++ b/chrome/browser/task_management/providers/web_contents/background_contents_tag.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_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_BACKGROUND_CONTENTS_TAG_H_
+#define CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_BACKGROUND_CONTENTS_TAG_H_
+
+#include "chrome/browser/task_management/providers/web_contents/background_contents_task.h"
+#include "chrome/browser/task_management/providers/web_contents/web_contents_tag.h"
+
+class BackgroundContents;
+
+namespace task_management {
+
+// Defines a concrete UserData type for WebContents owned by BackgroundContents
+// service.
+class BackgroundContentsTag : public WebContentsTag {
+ public:
+  // task_management::WebContentsTag:
+  BackgroundContentsTask* CreateTask() const override;
+
+ private:
+  friend class WebContentsTags;
+
+  BackgroundContentsTag(content::WebContents* web_contents,
+                        BackgroundContents* background_contents);
+  ~BackgroundContentsTag() override;
+
+  // The owning BackgroundContents.
+  BackgroundContents* background_contents_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackgroundContentsTag);
+};
+
+}  // namespace task_management
+
+#endif  // CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_BACKGROUND_CONTENTS_TAG_H_
diff --git a/chrome/browser/task_management/providers/web_contents/background_contents_tag_browsertest.cc b/chrome/browser/task_management/providers/web_contents/background_contents_tag_browsertest.cc
new file mode 100644
index 0000000..c70fa3b
--- /dev/null
+++ b/chrome/browser/task_management/providers/web_contents/background_contents_tag_browsertest.cc
@@ -0,0 +1,145 @@
+// 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/strings/utf_string_conversions.h"
+#include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/task_management/providers/task_provider_observer.h"
+#include "chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.h"
+#include "chrome/browser/task_management/providers/web_contents/web_contents_task_provider.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/grit/generated_resources.h"
+#include "extensions/common/switches.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace task_management {
+
+// Defines a browser test for testing that BackgroundContents are tagged
+// properly and the TagsManager records these tags. It is also used to test that
+// the WebContentsTaskProvider will be able to provide the appropriate
+// BackgroundContentsTask.
+class BackgroundContentsTagTest
+    : public ExtensionBrowserTest,
+      public TaskProviderObserver {
+ public:
+  BackgroundContentsTagTest() {}
+  ~BackgroundContentsTagTest() override {}
+
+  const extensions::Extension* LoadBackgroundExtension() {
+    auto extension = LoadExtension(
+        test_data_dir_.AppendASCII("app_process_background_instances"));
+    return extension;
+  }
+
+  base::string16 GetBackgroundTaskExpectedName(
+      const extensions::Extension* extension) {
+    return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_BACKGROUND_PREFIX,
+                                      base::UTF8ToUTF16(extension->name()));
+  }
+
+  // task_management::Task_providerObserver:
+  void TaskAdded(Task* task) override {
+    CHECK(task);
+    ASSERT_FALSE(provided_tasks_.count(task));
+    provided_tasks_.insert(task);
+  }
+
+  void TaskRemoved(Task* task) override {
+    CHECK(task);
+    ASSERT_TRUE(provided_tasks_.count(task));
+    provided_tasks_.erase(task);
+  }
+
+  WebContentsTagsManager* tags_manager() const {
+    return WebContentsTagsManager::GetInstance();
+  }
+
+  const std::set<Task*>& provided_tasks() const { return provided_tasks_; }
+
+ protected:
+  // ExtensionApiTest:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // Pass flags to make testing apps easier.
+    ExtensionBrowserTest::SetUpCommandLine(command_line);
+    test_data_dir_ = test_data_dir_.AppendASCII("api_test");
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        switches::kDisablePopupBlocking);
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        extensions::switches::kAllowHTTPBackgroundPage);
+  }
+
+ private:
+  std::set<Task*> provided_tasks_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackgroundContentsTagTest);
+};
+
+// Tests that loading an extension that has a background contents will result in
+// the tags manager recording a WebContentsTag.
+IN_PROC_BROWSER_TEST_F(BackgroundContentsTagTest, TagsManagerRecordsATag) {
+  EXPECT_TRUE(provided_tasks().empty());
+  EXPECT_TRUE(tags_manager()->tracked_tags().empty());
+  EXPECT_TRUE(LoadBackgroundExtension());
+  EXPECT_FALSE(tags_manager()->tracked_tags().empty());
+  EXPECT_EQ(1U, tags_manager()->tracked_tags().size());
+  EXPECT_TRUE(provided_tasks().empty());
+}
+
+// Tests that background contents creation while the provider is being observed
+// will also provide tasks.
+IN_PROC_BROWSER_TEST_F(BackgroundContentsTagTest, TasksProvidedWhileObserving) {
+  EXPECT_TRUE(provided_tasks().empty());
+  EXPECT_TRUE(tags_manager()->tracked_tags().empty());
+
+  WebContentsTaskProvider provider;
+  provider.SetObserver(this);
+
+  // Still empty, no pre-existing tasks.
+  EXPECT_TRUE(provided_tasks().empty());
+
+  auto extension = LoadBackgroundExtension();
+  ASSERT_NE(nullptr, extension);
+  EXPECT_FALSE(tags_manager()->tracked_tags().empty());
+  EXPECT_EQ(1U, tags_manager()->tracked_tags().size());
+  EXPECT_FALSE(provided_tasks().empty());
+  EXPECT_EQ(1U, provided_tasks().size());
+
+  // Now check the provided task.
+  const Task* task = *provided_tasks().begin();
+  EXPECT_EQ(Task::RENDERER, task->GetType());
+  EXPECT_EQ(GetBackgroundTaskExpectedName(extension), task->title());
+
+  // Unload the extension.
+  UnloadExtension(extension->id());
+  EXPECT_TRUE(provided_tasks().empty());
+  EXPECT_TRUE(tags_manager()->tracked_tags().empty());
+}
+
+// Tests providing a pre-existing background task to the observing operation.
+IN_PROC_BROWSER_TEST_F(BackgroundContentsTagTest, PreExistingTasksAreProvided) {
+  EXPECT_TRUE(provided_tasks().empty());
+  EXPECT_TRUE(tags_manager()->tracked_tags().empty());
+  auto extension = LoadBackgroundExtension();
+  ASSERT_NE(nullptr, extension);
+  EXPECT_FALSE(tags_manager()->tracked_tags().empty());
+  EXPECT_EQ(1U, tags_manager()->tracked_tags().size());
+
+  WebContentsTaskProvider provider;
+  provider.SetObserver(this);
+
+  // Pre-existing task will be provided to us.
+  EXPECT_FALSE(provided_tasks().empty());
+  EXPECT_EQ(1U, provided_tasks().size());
+
+  // Now check the provided task.
+  const Task* task = *provided_tasks().begin();
+  EXPECT_EQ(Task::RENDERER, task->GetType());
+  EXPECT_EQ(GetBackgroundTaskExpectedName(extension), task->title());
+
+  // Unload the extension.
+  UnloadExtension(extension->id());
+  EXPECT_TRUE(provided_tasks().empty());
+  EXPECT_TRUE(tags_manager()->tracked_tags().empty());
+}
+
+}  // namespace task_management
diff --git a/chrome/browser/task_management/providers/web_contents/background_contents_task.cc b/chrome/browser/task_management/providers/web_contents/background_contents_task.cc
new file mode 100644
index 0000000..9a45d11
--- /dev/null
+++ b/chrome/browser/task_management/providers/web_contents/background_contents_task.cc
@@ -0,0 +1,83 @@
+// 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/task_management/providers/web_contents/background_contents_task.h"
+
+#include "base/i18n/rtl.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/background/background_contents_service.h"
+#include "chrome/browser/background/background_contents_service_factory.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/view_type_utils.h"
+#include "extensions/common/extension_set.h"
+#include "grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace task_management {
+
+namespace {
+
+// The default icon for the background webcontents task.
+gfx::ImageSkia* g_default_icon = nullptr;
+
+gfx::ImageSkia* GetDefaultIcon() {
+  if (!g_default_icon && ResourceBundle::HasSharedInstance()) {
+    g_default_icon = ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+        IDR_PLUGINS_FAVICON);
+  }
+
+  return g_default_icon;
+}
+
+base::string16 AdjustAndLocalizeTitle(const base::string16& title,
+                                      const std::string& url_spec) {
+  base::string16 localized_title(title);
+  if (localized_title.empty()) {
+    // No title (can't locate the parent app for some reason) so just display
+    // the URL (properly forced to be LTR).
+    localized_title = base::i18n::GetDisplayStringInLTRDirectionality(
+        base::UTF8ToUTF16(url_spec));
+  }
+
+  // Ensure that the string has the appropriate direction markers.
+  base::i18n::AdjustStringForLocaleDirection(&localized_title);
+  return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_BACKGROUND_PREFIX,
+                                    localized_title);
+}
+
+}  // namespace
+
+BackgroundContentsTask::BackgroundContentsTask(
+    const base::string16& title,
+    BackgroundContents* background_contents)
+    : RendererTask(AdjustAndLocalizeTitle(title,
+                                          background_contents->GetURL().spec()),
+                   GetDefaultIcon(),
+                   background_contents->web_contents()->GetRenderProcessHost()->
+                   GetHandle(),
+                   background_contents->web_contents()->
+                   GetRenderProcessHost()) {
+}
+
+BackgroundContentsTask::~BackgroundContentsTask() {
+}
+
+void BackgroundContentsTask::OnTitleChanged(content::NavigationEntry* entry) {
+  // TODO(afakhry): At the time of integration testing figure out whether we
+  // need to change the title of the task here.
+}
+
+void BackgroundContentsTask::OnFaviconChanged() {
+  // We don't do anything here. For background contents we always use the
+  // default icon.
+}
+
+}  // namespace task_management
diff --git a/chrome/browser/task_management/providers/web_contents/background_contents_task.h b/chrome/browser/task_management/providers/web_contents/background_contents_task.h
new file mode 100644
index 0000000..eba02d87
--- /dev/null
+++ b/chrome/browser/task_management/providers/web_contents/background_contents_task.h
@@ -0,0 +1,30 @@
+// 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_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_BACKGROUND_CONTENTS_TASK_H_
+#define CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_BACKGROUND_CONTENTS_TASK_H_
+
+#include "chrome/browser/background/background_contents.h"
+#include "chrome/browser/task_management/providers/web_contents/renderer_task.h"
+
+namespace task_management {
+
+// Defines a RendererTask that represents background |WebContents|.
+class BackgroundContentsTask : public RendererTask {
+ public:
+  BackgroundContentsTask(const base::string16& title,
+                         BackgroundContents* background_contents);
+  ~BackgroundContentsTask() override;
+
+  // task_management::RendererTask:
+  void OnTitleChanged(content::NavigationEntry* entry) override;
+  void OnFaviconChanged() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BackgroundContentsTask);
+};
+
+}  // namespace task_management
+
+#endif  // CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_BACKGROUND_CONTENTS_TASK_H_
diff --git a/chrome/browser/task_management/providers/web_contents/web_contents_tag.cc b/chrome/browser/task_management/providers/web_contents/web_contents_tag.cc
new file mode 100644
index 0000000..0ba4731e
--- /dev/null
+++ b/chrome/browser/task_management/providers/web_contents/web_contents_tag.cc
@@ -0,0 +1,33 @@
+// 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/task_management/providers/web_contents/web_contents_tag.h"
+
+#include "chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.h"
+#include "content/public/browser/web_contents.h"
+
+namespace task_management {
+
+// static
+const WebContentsTag* WebContentsTag::FromWebContents(
+    const content::WebContents* contents) {
+  DCHECK(contents);
+  return static_cast<const WebContentsTag*>(contents->GetUserData(kTagKey));
+}
+
+WebContentsTag::WebContentsTag(content::WebContents* contents)
+    : web_contents_(contents) {
+  // You can't tag the |contents| here. The object creation is not complete yet.
+  // This will be done in the factory methods inside
+  // |task_management::WebContentsTags|.
+}
+
+WebContentsTag::~WebContentsTag() {
+  WebContentsTagsManager::GetInstance()->RemoveTag(this);
+}
+
+// static
+void* WebContentsTag::kTagKey = &WebContentsTag::kTagKey;
+
+}  // namespace task_management
diff --git a/chrome/browser/task_management/providers/web_contents/web_contents_tag.h b/chrome/browser/task_management/providers/web_contents/web_contents_tag.h
new file mode 100644
index 0000000..2b45783
--- /dev/null
+++ b/chrome/browser/task_management/providers/web_contents/web_contents_tag.h
@@ -0,0 +1,61 @@
+// 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_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_WEB_CONTENTS_TAG_H_
+#define CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_WEB_CONTENTS_TAG_H_
+
+#include "base/supports_user_data.h"
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+namespace task_management {
+
+class RendererTask;
+
+// Defines a TaskManager-specific UserData type for WebContents. This is an
+// abstract base class for all concrete UserData types. They all share the same
+// key. We have a concrete type for each WebContents owning service that the
+// task manager is interested in tracking.
+//
+// To instantiate a |WebContentsTag|, use the factory functions in
+// |task_management::WebContentsTags|.
+class WebContentsTag : public base::SupportsUserData::Data {
+ public:
+  // Retrieves the instance of the WebContentsTag that was attached to the
+  // specified WebContents and returns it. If no instance was attached, returns
+  // nullptr.
+  static const WebContentsTag* FromWebContents(
+      const content::WebContents* contents);
+
+  // The concrete Tags know how to instantiate a |RendererTask| that corresponds
+  // to the owning WebContents and Service. This will be used by the
+  // WebContentsTaskProvider to create the appropriate Tasks.
+  //
+  // The returned |RendererTask| is owned by the caller (in this case it will be
+  // the provider).
+  virtual RendererTask* CreateTask() const = 0;
+
+  content::WebContents* web_contents() const { return web_contents_; }
+
+ protected:
+  friend class WebContentsTags;
+
+  explicit WebContentsTag(content::WebContents* contents);
+  ~WebContentsTag() override;
+
+ private:
+  // The user data key.
+  static void* kTagKey;
+
+  // The owning WebContents.
+  content::WebContents* web_contents_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebContentsTag);
+};
+
+}  // namespace task_management
+
+#endif  // CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_WEB_CONTENTS_TAG_H_
diff --git a/chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.cc b/chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.cc
new file mode 100644
index 0000000..b61ef1e
--- /dev/null
+++ b/chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.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/task_management/providers/web_contents/web_contents_tags_manager.h"
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/task_management/providers/web_contents/web_contents_task_provider.h"
+
+namespace task_management {
+
+// static
+WebContentsTagsManager* WebContentsTagsManager::GetInstance() {
+  return Singleton<WebContentsTagsManager>::get();
+}
+
+void WebContentsTagsManager::AddTag(WebContentsTag* tag) {
+  DCHECK(tag);
+  tracked_tags_.insert(tag);
+
+  if (provider_)
+    provider_->OnWebContentsTagCreated(tag);
+}
+
+void WebContentsTagsManager::RemoveTag(WebContentsTag* tag) {
+  DCHECK(tag);
+  tracked_tags_.erase(tag);
+
+  // No need to inform the provider here. The provider will create an entry
+  // for each WebContents it's tracking which is a WebContentsObserver and
+  // can be used to track the lifetime of the WebContents.
+
+  // We must however make sure that the provider has already forgotten about the
+  // tag and its associated web_contents.
+  if (provider_)
+    CHECK(!provider_->HasWebContents(tag->web_contents()));
+}
+
+void WebContentsTagsManager::SetProvider(WebContentsTaskProvider* provider) {
+  DCHECK(provider);
+  DCHECK(!provider_);
+  provider_ = provider;
+}
+
+void WebContentsTagsManager::ClearProvider() {
+  DCHECK(provider_);
+  provider_ = nullptr;
+}
+
+WebContentsTagsManager::WebContentsTagsManager()
+    : provider_(nullptr) {
+}
+
+WebContentsTagsManager::~WebContentsTagsManager() {
+}
+
+}  // namespace task_management
diff --git a/chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.h b/chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.h
new file mode 100644
index 0000000..62ac3cf
--- /dev/null
+++ b/chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.h
@@ -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.
+
+#ifndef CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_WEB_CONTENTS_TAGS_MANAGER_H_
+#define CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_WEB_CONTENTS_TAGS_MANAGER_H_
+
+#include <set>
+
+#include "chrome/browser/task_management/providers/web_contents/web_contents_tag.h"
+
+template<typename T>
+struct DefaultSingletonTraits;
+
+namespace task_management {
+
+class WebContentsTaskProvider;
+
+// Defines a manager to track the various TaskManager-specific WebContents
+// UserData (task_management::WebContentsTags). This is used by the
+// WebContentsTaskProvider to get all the pre-existing WebContents once
+// WebContentsTaskProvider::StartUpdating() is called.
+class WebContentsTagsManager {
+ public:
+  static WebContentsTagsManager* GetInstance();
+
+  void AddTag(WebContentsTag* tag);
+  void RemoveTag(WebContentsTag* tag);
+
+  // This is how the WebContentsTaskProvider starts and stops observing the
+  // creation of WebContents.
+  // There must be no or only one given provider at any given time.
+  void SetProvider(WebContentsTaskProvider* provider);
+  void ClearProvider();
+
+  const std::set<WebContentsTag*>& tracked_tags() const {
+    return tracked_tags_;
+  }
+
+ private:
+  friend struct DefaultSingletonTraits<WebContentsTagsManager>;
+
+  WebContentsTagsManager();
+  ~WebContentsTagsManager();
+
+  // The provider that's currently observing the creation of WebContents.
+  WebContentsTaskProvider* provider_;
+
+  // A set of all the WebContentsTags seen so far.
+  std::set<WebContentsTag*> tracked_tags_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebContentsTagsManager);
+};
+
+}  // namespace task_management
+
+
+#endif  // CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_WEB_CONTENTS_TAGS_MANAGER_H_
diff --git a/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.cc b/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.cc
new file mode 100644
index 0000000..57dff66
--- /dev/null
+++ b/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.cc
@@ -0,0 +1,346 @@
+// 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/task_management/providers/web_contents/web_contents_task_provider.h"
+
+#include "base/bind.h"
+#include "base/stl_util.h"
+#include "chrome/browser/task_management/providers/web_contents/subframe_task.h"
+#include "chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+
+using content::RenderFrameHost;
+using content::SiteInstance;
+using content::WebContents;
+
+namespace task_management {
+
+// Defines an entry for each WebContents that will be tracked by the provider.
+// The entry is used to observe certain events in its corresponding WebContents
+// and then it notifies the provider or the render task (representing the
+// WebContents) of these events.
+// The entry owns the created tasks representing the WebContents, and it is
+// itself owned by the provider.
+class WebContentsEntry : public content::WebContentsObserver {
+ public:
+  WebContentsEntry(content::WebContents* web_contents,
+                   WebContentsTaskProvider* provider);
+  ~WebContentsEntry() override;
+
+  // Creates all the tasks associated with each |RenderFrameHost| in this
+  // entry's WebContents.
+  void CreateAllTasks();
+
+  // Returns the |RendererTask| that corresponds to the given
+  // |render_frame_host| or |nullptr| if the given frame is not tracked by this
+  // entry.
+  RendererTask* GetTaskForFrame(RenderFrameHost* render_frame_host) const;
+
+  // content::WebContentsObserver:
+  void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
+  void RenderFrameHostChanged(RenderFrameHost* old_host,
+                              RenderFrameHost* new_host) override;
+  void RenderViewReady() override;
+  void WebContentsDestroyed() override;
+  void RenderProcessGone(base::TerminationStatus status) override;
+  void TitleWasSet(content::NavigationEntry* entry, bool explicit_set) override;
+  void DidUpdateFaviconURL(
+      const std::vector<content::FaviconURL>& candidates) override;
+
+ private:
+  // Defines a callback for WebContents::ForEachFrame() to create a
+  // corresponding task for the given |render_frame_host| and notifying the
+  // provider's observer of the new task.
+  void CreateTaskForFrame(RenderFrameHost* render_frame_host);
+
+  // Clears the task that corresponds to the given |render_frame_host| and
+  // notifies the provider's observer of the tasks removal.
+  void ClearTaskForFrame(RenderFrameHost* render_frame_host);
+
+  // Clears all the tasks in this entry. The provider's observer will be
+  // notified if |notify_observer| is true.
+  void ClearAllTasks(bool notify_observer);
+
+  // The provider that owns this entry.
+  WebContentsTaskProvider* provider_;
+
+  // The RenderFrameHosts associated with this entry's WebContents that we're
+  // tracking mapped by their SiteInstances.
+  typedef std::vector<RenderFrameHost*> FramesList;
+  typedef std::map<SiteInstance*, FramesList> SiteInstanceToFramesMap;
+  SiteInstanceToFramesMap frames_by_site_instance_;
+
+  // The RendererTasks that we create for the task manager, mapped by their
+  // RenderFrameHosts.
+  typedef std::map<RenderFrameHost*, RendererTask*> FramesToTasksMap;
+  FramesToTasksMap tasks_by_frames_;
+
+  // States whether we did record a main frame for this entry.
+  SiteInstance* main_frame_site_instance_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebContentsEntry);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+WebContentsEntry::WebContentsEntry(content::WebContents* web_contents,
+                                   WebContentsTaskProvider* provider)
+    : WebContentsObserver(web_contents),
+      provider_(provider),
+      frames_by_site_instance_(),
+      tasks_by_frames_(),
+      main_frame_site_instance_(nullptr) {
+}
+
+WebContentsEntry::~WebContentsEntry() {
+  ClearAllTasks(false);
+}
+
+void WebContentsEntry::CreateAllTasks() {
+  DCHECK(web_contents()->GetMainFrame());
+  web_contents()->ForEachFrame(base::Bind(&WebContentsEntry::CreateTaskForFrame,
+                                          base::Unretained(this)));
+}
+
+RendererTask* WebContentsEntry::GetTaskForFrame(
+    RenderFrameHost* render_frame_host) const {
+  auto itr = tasks_by_frames_.find(render_frame_host);
+  if (itr == tasks_by_frames_.end())
+    return nullptr;
+
+  return itr->second;
+}
+
+void WebContentsEntry::RenderFrameDeleted(RenderFrameHost* render_frame_host) {
+  ClearTaskForFrame(render_frame_host);
+}
+
+void WebContentsEntry::RenderFrameHostChanged(RenderFrameHost* old_host,
+                                              RenderFrameHost* new_host) {
+  ClearTaskForFrame(old_host);
+  CreateTaskForFrame(new_host);
+}
+
+void WebContentsEntry::RenderViewReady() {
+  ClearAllTasks(true);
+  CreateAllTasks();
+}
+
+void WebContentsEntry::WebContentsDestroyed() {
+  ClearAllTasks(true);
+  provider_->DeleteEntry(web_contents());
+}
+
+void WebContentsEntry::RenderProcessGone(base::TerminationStatus status) {
+  ClearAllTasks(true);
+}
+
+void WebContentsEntry::TitleWasSet(content::NavigationEntry* entry,
+                                   bool explicit_set) {
+  if (!tasks_by_frames_.count(web_contents()->GetMainFrame())) {
+    // TODO(afakhry): Validate whether this actually happens in practice.
+    NOTREACHED();
+    return;
+  }
+
+  tasks_by_frames_[web_contents()->GetMainFrame()]->OnTitleChanged(entry);
+}
+
+void WebContentsEntry::DidUpdateFaviconURL(
+    const std::vector<content::FaviconURL>& candidates) {
+  if (!tasks_by_frames_.count(web_contents()->GetMainFrame())) {
+    // TODO(afakhry): Validate whether this actually happens in practice.
+    NOTREACHED();
+    return;
+  }
+
+  tasks_by_frames_[web_contents()->GetMainFrame()]->OnFaviconChanged();
+}
+
+void WebContentsEntry::CreateTaskForFrame(RenderFrameHost* render_frame_host) {
+  DCHECK_EQ(0U, tasks_by_frames_.count(render_frame_host));
+
+  content::SiteInstance* site_instance = render_frame_host->GetSiteInstance();
+  if (!site_instance->GetProcess()->HasConnection())
+    return;
+
+  bool site_instance_exists =
+      frames_by_site_instance_.count(site_instance) != 0U;
+  bool is_main_frame = (render_frame_host == web_contents()->GetMainFrame());
+  bool site_instance_is_main = (site_instance == main_frame_site_instance_);
+
+  RendererTask* new_task = nullptr;
+  // We don't create a task if there's one for this site_instance AND
+  // if this is not the main frame or we did record a main frame for the entry.
+  if (!site_instance_exists || (is_main_frame && !site_instance_is_main)) {
+    if (is_main_frame) {
+      const WebContentsTag* tag =
+          WebContentsTag::FromWebContents(web_contents());
+      CHECK(tag);
+      new_task = tag->CreateTask();
+      main_frame_site_instance_ = site_instance;
+    } else {
+      new_task = new SubframeTask(render_frame_host);
+    }
+  }
+
+  if (site_instance_exists) {
+    // One of the existing frame hosts for this site instance.
+    FramesList& existing_frames_for_site_instance =
+        frames_by_site_instance_[site_instance];
+    RenderFrameHost* existing_rfh = existing_frames_for_site_instance[0];
+    RendererTask* old_task = tasks_by_frames_[existing_rfh];
+
+    if (!new_task) {
+      // We didn't create any new task, so we keep appending the old one.
+      tasks_by_frames_[render_frame_host] = old_task;
+    } else {
+      // Overwrite all the existing old tasks with the new one, and delete the
+      // old one.
+      for (RenderFrameHost* frame : existing_frames_for_site_instance)
+        tasks_by_frames_[frame] = new_task;
+
+      provider_->NotifyObserverTaskRemoved(old_task);
+      delete old_task;
+    }
+  }
+
+  frames_by_site_instance_[site_instance].push_back(render_frame_host);
+
+  if (new_task) {
+    tasks_by_frames_[render_frame_host] = new_task;
+    provider_->NotifyObserverTaskAdded(new_task);
+  }
+}
+
+void WebContentsEntry::ClearTaskForFrame(RenderFrameHost* render_frame_host) {
+  auto itr = tasks_by_frames_.find(render_frame_host);
+  if (itr == tasks_by_frames_.end())
+    return;
+
+  RendererTask* task = itr->second;
+  tasks_by_frames_.erase(itr);
+  content::SiteInstance* site_instance = render_frame_host->GetSiteInstance();
+  FramesList& frames = frames_by_site_instance_[site_instance];
+  frames.erase(std::find(frames.begin(), frames.end(), render_frame_host));
+
+  if (frames.empty()) {
+    frames_by_site_instance_.erase(site_instance);
+    provider_->NotifyObserverTaskRemoved(task);
+    delete task;
+
+    if (site_instance == main_frame_site_instance_)
+      main_frame_site_instance_ = nullptr;
+  }
+}
+
+void WebContentsEntry::ClearAllTasks(bool notify_observer) {
+  for (auto& pair : frames_by_site_instance_) {
+    FramesList& frames_list = pair.second;
+    DCHECK(!frames_list.empty());
+    RendererTask* task = tasks_by_frames_[frames_list[0]];
+    if (notify_observer)
+      provider_->NotifyObserverTaskRemoved(task);
+    delete task;
+  }
+
+  frames_by_site_instance_.clear();
+  tasks_by_frames_.clear();
+  main_frame_site_instance_ = nullptr;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+WebContentsTaskProvider::WebContentsTaskProvider() : entries_map_() {
+}
+
+WebContentsTaskProvider::~WebContentsTaskProvider() {
+  STLDeleteValues(&entries_map_);
+}
+
+void WebContentsTaskProvider::OnWebContentsTagCreated(WebContentsTag* tag) {
+  DCHECK(tag);
+  content::WebContents* web_contents = tag->web_contents();
+  DCHECK(web_contents);
+
+  // TODO(afakhry): Check if we need this check. It seems that we no longer
+  // need it in the new implementation.
+  if (entries_map_.count(web_contents)) {
+    // This case may happen if we added a WebContents while collecting all the
+    // pre-existing ones at the time |StartUpdating()| was called, but the
+    // notification of its connection hasn't been fired yet. In this case we
+    // ignore it since we're already tracking it.
+    return;
+  }
+
+  WebContentsEntry* entry = new WebContentsEntry(web_contents, this);
+  entries_map_[web_contents] = entry;
+  entry->CreateAllTasks();
+}
+
+Task* WebContentsTaskProvider::GetTaskOfUrlRequest(int origin_pid,
+                                                   int child_id,
+                                                   int route_id) {
+  // If an origin PID was specified then the URL request originated in a plugin
+  // working on the WebContents' behalf, so ignore it.
+  if (origin_pid)
+    return nullptr;
+
+  content::RenderFrameHost* rfh =
+      content::RenderFrameHost::FromID(child_id, route_id);
+  content::WebContents* web_contents =
+      content::WebContents::FromRenderFrameHost(rfh);
+
+  auto itr = entries_map_.find(web_contents);
+  if (itr == entries_map_.end()) {
+    // Can happen if the tab was closed while a network request was being
+    // performed.
+    return nullptr;
+  }
+
+  return itr->second->GetTaskForFrame(rfh);
+}
+
+bool WebContentsTaskProvider::HasWebContents(
+    content::WebContents* web_contents) const {
+  return entries_map_.count(web_contents) != 0;
+}
+
+void WebContentsTaskProvider::StartUpdating() {
+  // 1- Collect all pre-existing WebContents from the WebContentsTagsManager.
+  WebContentsTagsManager* tags_manager = WebContentsTagsManager::GetInstance();
+  for (auto& tag : tags_manager->tracked_tags())
+    OnWebContentsTagCreated(tag);
+
+  // 2- Start observing newly connected ones.
+  tags_manager->SetProvider(this);
+}
+
+void WebContentsTaskProvider::StopUpdating() {
+  // 1- Stop observing.
+  WebContentsTagsManager::GetInstance()->ClearProvider();
+
+  // 2- Clear storage.
+  STLDeleteValues(&entries_map_);
+}
+
+void WebContentsTaskProvider::DeleteEntry(content::WebContents* web_contents) {
+  auto itr = entries_map_.find(web_contents);
+  if (itr == entries_map_.end()) {
+    NOTREACHED();
+    return;
+  }
+
+  WebContentsEntry* entry = itr->second;
+  entries_map_.erase(itr);
+
+  // The entry we're about to delete is our caller, however its' still fine to
+  // delete it.
+  delete entry;
+}
+
+}  // namespace task_management
diff --git a/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.h b/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.h
new file mode 100644
index 0000000..0104cac
--- /dev/null
+++ b/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.h
@@ -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.
+
+#ifndef CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_WEB_CONTENTS_TASK_PROVIDER_H_
+#define CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_WEB_CONTENTS_TASK_PROVIDER_H_
+
+#include <map>
+
+#include "chrome/browser/task_management/providers/task_provider.h"
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+
+namespace task_management {
+
+class WebContentsEntry;
+class WebContentsTag;
+
+// Defines a provider to provide the renderer tasks that are associated with
+// various |WebContents| from various services.
+// There should be no or only one instance of this class at any time.
+class WebContentsTaskProvider : public TaskProvider {
+ public:
+  WebContentsTaskProvider();
+  ~WebContentsTaskProvider() override;
+
+  // This will be called every time we're notified that a new |WebContentsTag|
+  // has been created.
+  void OnWebContentsTagCreated(WebContentsTag* tag);
+
+  // task_management::TaskProvider:
+  Task* GetTaskOfUrlRequest(int origin_pid,
+                            int child_id,
+                            int route_id) override;
+
+  // Checks if the given |web_contents| is tracked by the provider.
+  bool HasWebContents(content::WebContents* web_contents) const;
+
+ private:
+  friend class WebContentsEntry;
+
+  // task_management::TaskProvider:
+  void StartUpdating() override;
+  void StopUpdating() override;
+
+  // Called when the given |web_contents| are destroyed so that we can delete
+  // its associated entry.
+  void DeleteEntry(content::WebContents* web_contents);
+
+  // A map to associate a |WebContents| with its corresponding entry that we
+  // create for it to be able to track it.
+  typedef std::map<content::WebContents*, WebContentsEntry*> EntryMap;
+  EntryMap entries_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebContentsTaskProvider);
+};
+
+}  // namespace task_management
+
+#endif  // CHROME_BROWSER_TASK_MANAGEMENT_PROVIDERS_WEB_CONTENTS_WEB_CONTENTS_TASK_PROVIDER_H_
diff --git a/chrome/browser/task_management/web_contents_tags.cc b/chrome/browser/task_management/web_contents_tags.cc
new file mode 100644
index 0000000..fe984868
--- /dev/null
+++ b/chrome/browser/task_management/web_contents_tags.cc
@@ -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.
+
+#include "chrome/browser/task_management/web_contents_tags.h"
+
+#include "chrome/browser/task_management/providers/web_contents/background_contents_tag.h"
+#include "chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.h"
+#include "content/public/browser/web_contents.h"
+
+namespace task_management {
+
+namespace {
+
+// Adds the |tag| to |contents|. It also adds the |tag| to the
+// |WebContentsTagsManager|.
+// Note: This will fail if |contents| is already tagged by |tag|.
+void TagWebContents(content::WebContents* contents,
+                    WebContentsTag* tag,
+                    void* tag_key) {
+  DCHECK(contents);
+  DCHECK(tag);
+  CHECK(WebContentsTag::FromWebContents(contents) == nullptr);
+  contents->SetUserData(tag_key, tag);
+  WebContentsTagsManager::GetInstance()->AddTag(tag);
+}
+
+}  // namespace
+
+// static
+void WebContentsTags::CreateForBackgroundContents(
+    content::WebContents* web_contents,
+    BackgroundContents* background_contents) {
+  if (!WebContentsTag::FromWebContents(web_contents)) {
+    TagWebContents(
+        web_contents,
+        new BackgroundContentsTag(web_contents, background_contents),
+        WebContentsTag::kTagKey);
+  }
+}
+
+}  // namespace task_management
+
diff --git a/chrome/browser/task_management/web_contents_tags.h b/chrome/browser/task_management/web_contents_tags.h
new file mode 100644
index 0000000..087ebbdb
--- /dev/null
+++ b/chrome/browser/task_management/web_contents_tags.h
@@ -0,0 +1,39 @@
+// 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_TASK_MANAGEMENT_WEB_CONTENTS_TAGS_H_
+#define CHROME_BROWSER_TASK_MANAGEMENT_WEB_CONTENTS_TAGS_H_
+
+#include "base/macros.h"
+
+class BackgroundContents;
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+namespace task_management {
+
+// Defines a factory class for creating the TaskManager-specific Tags for the
+// web_contents that are owned by various types of services.
+//
+// Any service that creates WebContents instances (via WebContents::Create)
+// needs to make sure that they are tagged using this mechanism, otherwise the
+// associated render processes will not show up in the task manager.
+class WebContentsTags {
+ public:
+  // Creates a BackgroundContentsTag, and attaches it to the specified
+  // WebContents. If an instance is already attached, it does nothing.
+  static void CreateForBackgroundContents(
+      content::WebContents* web_contents,
+      BackgroundContents* background_contents);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WebContentsTags);
+};
+
+}  // namespace task_management
+
+
+#endif  // CHROME_BROWSER_TASK_MANAGEMENT_WEB_CONTENTS_TAGS_H_
diff --git a/chrome/browser/tracing/background_tracing_field_trial.cc b/chrome/browser/tracing/background_tracing_field_trial.cc
new file mode 100644
index 0000000..8d459ba0
--- /dev/null
+++ b/chrome/browser/tracing/background_tracing_field_trial.cc
@@ -0,0 +1,73 @@
+// 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>
+
+#include "base/json/json_reader.h"
+#include "base/metrics/field_trial.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/tracing/crash_service_uploader.h"
+#include "chrome/common/variations/variations_util.h"
+#include "components/variations/variations_associated_data.h"
+#include "content/public/browser/background_tracing_config.h"
+#include "content/public/browser/background_tracing_manager.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace tracing {
+
+namespace {
+
+const char kBackgroundTracingFieldTrial[] = "BackgroundTracing";
+const char kBackgroundTracingConfig[] = "config";
+
+void OnUploadProgress(int64, int64) {
+  // We don't actually care about the progress, but TraceUploader::DoUpload
+  // requires we pass something valid.
+}
+
+void OnUploadComplete(TraceCrashServiceUploader* uploader,
+                      base::Closure done_callback,
+                      bool success,
+                      const std::string& feedback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  done_callback.Run();
+}
+
+void UploadCallback(const scoped_refptr<base::RefCountedString>& file_contents,
+                    base::Closure callback) {
+  TraceCrashServiceUploader* uploader = new TraceCrashServiceUploader(
+      g_browser_process->system_request_context());
+
+  uploader->DoUpload(
+      file_contents->data(), base::Bind(&OnUploadProgress),
+      base::Bind(&OnUploadComplete, base::Owned(uploader), callback));
+}
+
+}  // namespace
+
+void SetupBackgroundTracingFieldTrial() {
+  std::string config_text = variations::GetVariationParamValue(
+      kBackgroundTracingFieldTrial, kBackgroundTracingConfig);
+  if (config_text.empty())
+    return;
+
+  scoped_ptr<base::Value> value = base::JSONReader::Read(config_text);
+  if (!value)
+    return;
+
+  const base::DictionaryValue* dict = nullptr;
+  if (!value->GetAsDictionary(&dict))
+    return;
+
+  scoped_ptr<content::BackgroundTracingConfig> config =
+      content::BackgroundTracingConfig::FromDict(dict);
+  if (!config)
+    return;
+
+  content::BackgroundTracingManager::GetInstance()->SetActiveScenario(
+      config.Pass(), base::Bind(&UploadCallback),
+      content::BackgroundTracingManager::ANONYMIZE_DATA);
+}
+
+}  // namespace tracing
diff --git a/chrome/browser/tracing/background_tracing_field_trial.h b/chrome/browser/tracing/background_tracing_field_trial.h
new file mode 100644
index 0000000..94a0448
--- /dev/null
+++ b/chrome/browser/tracing/background_tracing_field_trial.h
@@ -0,0 +1,14 @@
+// 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_TRACING_BACKGROUND_TRACING_FIELD_TRIAL_H_
+#define CHROME_BROWSER_TRACING_BACKGROUND_TRACING_FIELD_TRIAL_H_
+
+namespace tracing {
+
+void SetupBackgroundTracingFieldTrial();
+
+}  // namespace tracing
+
+#endif  // CHROME_BROWSER_TRACING_BACKGROUND_TRACING_FIELD_TRIAL_H_
diff --git a/chrome/browser/tracing/chrome_tracing_delegate.cc b/chrome/browser/tracing/chrome_tracing_delegate.cc
index fe76f203..5521df48 100644
--- a/chrome/browser/tracing/chrome_tracing_delegate.cc
+++ b/chrome/browser/tracing/chrome_tracing_delegate.cc
@@ -3,10 +3,102 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/tracing/chrome_tracing_delegate.h"
+
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_service.h"
+#include "base/time/time.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/tracing/crash_service_uploader.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_otr_state.h"
+#include "chrome/common/pref_names.h"
+#include "content/public/browser/background_tracing_config.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace {
+
+const int kMinDaysUntilNextUpload = 7;
+
+}  // namespace
+
+void ChromeTracingDelegate::RegisterPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterInt64Pref(prefs::kBackgroundTracingLastUpload, 0);
+}
+
+ChromeTracingDelegate::ChromeTracingDelegate() : incognito_launched_(false) {
+  CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  BrowserList::AddObserver(this);
+}
+
+ChromeTracingDelegate::~ChromeTracingDelegate() {
+  CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  BrowserList::RemoveObserver(this);
+}
+
+void ChromeTracingDelegate::OnBrowserAdded(Browser* browser) {
+  if (browser->profile()->IsOffTheRecord())
+    incognito_launched_ = true;
+}
 
 scoped_ptr<content::TraceUploader> ChromeTracingDelegate::GetTraceUploader(
     net::URLRequestContextGetter* request_context) {
   return scoped_ptr<content::TraceUploader>(
       new TraceCrashServiceUploader(request_context));
 }
+
+bool ChromeTracingDelegate::IsAllowedToBeginBackgroundScenario(
+    const content::BackgroundTracingConfig& config,
+    bool requires_anonymized_data) {
+  Profile* profile = g_browser_process->profile_manager()
+                         ->GetLastUsedProfile()
+                         ->GetOriginalProfile();
+  DCHECK(profile);
+  // Safeguard, in case background tracing is responsible for a crash on
+  // startup.
+  if (profile->GetLastSessionExitType() == Profile::EXIT_CRASHED)
+    return false;
+
+  if (requires_anonymized_data && chrome::IsOffTheRecordSessionActive())
+    return false;
+
+  if (config.mode ==
+      content::BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) {
+    PrefService* local_state = g_browser_process->local_state();
+    DCHECK(local_state);
+    const base::Time last_upload_time = base::Time::FromInternalValue(
+        local_state->GetInt64(prefs::kBackgroundTracingLastUpload));
+    if (!last_upload_time.is_null()) {
+      base::Time computed_next_allowed_time =
+          last_upload_time + base::TimeDelta::FromDays(kMinDaysUntilNextUpload);
+      if (computed_next_allowed_time > base::Time::Now()) {
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+bool ChromeTracingDelegate::IsAllowedToEndBackgroundScenario(
+    const content::BackgroundTracingConfig& config,
+    bool requires_anonymized_data) {
+  if (requires_anonymized_data && incognito_launched_)
+    return false;
+
+  if (config.mode ==
+      content::BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) {
+    PrefService* local_state = g_browser_process->local_state();
+    DCHECK(local_state);
+    local_state->SetInt64(prefs::kBackgroundTracingLastUpload,
+                          base::Time::Now().ToInternalValue());
+
+    // We make sure we've persisted the value in case finalizing the tracing
+    // causes a crash.
+    local_state->CommitPendingWrite();
+  }
+
+  return true;
+}
diff --git a/chrome/browser/tracing/chrome_tracing_delegate.h b/chrome/browser/tracing/chrome_tracing_delegate.h
index b1c97398..99964df1 100644
--- a/chrome/browser/tracing/chrome_tracing_delegate.h
+++ b/chrome/browser/tracing/chrome_tracing_delegate.h
@@ -5,12 +5,35 @@
 #ifndef CHROME_BROWSER_TRACING_CHROME_TRACING_DELEGATE_H_
 #define CHROME_BROWSER_TRACING_CHROME_TRACING_DELEGATE_H_
 
+#include "chrome/browser/ui/browser_list_observer.h"
 #include "content/public/browser/tracing_delegate.h"
 
-class ChromeTracingDelegate : public content::TracingDelegate {
+class PrefRegistrySimple;
+
+class ChromeTracingDelegate : public content::TracingDelegate,
+                              public chrome::BrowserListObserver {
  public:
+  ChromeTracingDelegate();
+  ~ChromeTracingDelegate() override;
+
+  static void RegisterPrefs(PrefRegistrySimple* registry);
+
   scoped_ptr<content::TraceUploader> GetTraceUploader(
       net::URLRequestContextGetter* request_context) override;
+
+  bool IsAllowedToBeginBackgroundScenario(
+      const content::BackgroundTracingConfig& config,
+      bool requires_anonymized_data) override;
+
+  bool IsAllowedToEndBackgroundScenario(
+      const content::BackgroundTracingConfig& config,
+      bool requires_anonymized_data) override;
+
+ private:
+  // chrome::BrowserListObserver implementation.
+  void OnBrowserAdded(Browser* browser) override;
+
+  bool incognito_launched_;
 };
 
 #endif  // CHROME_BROWSER_TRACING_CHROME_TRACING_DELEGATE_H_
diff --git a/chrome/browser/tracing/chrome_tracing_delegate_browsertest.cc b/chrome/browser/tracing/chrome_tracing_delegate_browsertest.cc
new file mode 100644
index 0000000..b6b48523
--- /dev/null
+++ b/chrome/browser/tracing/chrome_tracing_delegate_browsertest.cc
@@ -0,0 +1,187 @@
+// 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/prefs/pref_service.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "content/public/browser/background_tracing_manager.h"
+#include "content/public/browser/background_tracing_preemptive_config.h"
+#include "content/public/browser/background_tracing_reactive_config.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_utils.h"
+
+namespace {
+
+class ChromeTracingDelegateBrowserTest : public InProcessBrowserTest {
+ public:
+  ChromeTracingDelegateBrowserTest()
+      : receive_count_(0),
+        started_finalizations_count_(0),
+        last_on_started_finalizing_success_(false) {}
+
+  bool StartPreemptiveScenario(
+      const base::Closure& on_upload_callback,
+      content::BackgroundTracingManager::DataFiltering data_filtering) {
+    on_upload_callback_ = on_upload_callback;
+
+    scoped_ptr<content::BackgroundTracingPreemptiveConfig> config(
+        new content::BackgroundTracingPreemptiveConfig());
+
+    content::BackgroundTracingPreemptiveConfig::MonitoringRule rule;
+    rule.type = content::BackgroundTracingPreemptiveConfig::
+        MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED;
+    rule.named_trigger_info.trigger_name = "test";
+
+    config->configs.push_back(rule);
+
+    content::BackgroundTracingManager::ReceiveCallback receive_callback =
+        base::Bind(&ChromeTracingDelegateBrowserTest::OnUpload,
+                   base::Unretained(this));
+
+    return content::BackgroundTracingManager::GetInstance()->SetActiveScenario(
+        config.Pass(), receive_callback, data_filtering);
+  }
+
+  void TriggerReactiveScenario(
+      const base::Closure& on_started_finalization_callback) {
+    on_started_finalization_callback_ = on_started_finalization_callback;
+    trigger_handle_ =
+        content::BackgroundTracingManager::GetInstance()->RegisterTriggerType(
+            "test");
+
+    content::BackgroundTracingManager::StartedFinalizingCallback
+        started_finalizing_callback =
+            base::Bind(&ChromeTracingDelegateBrowserTest::OnStartedFinalizing,
+                       base::Unretained(this));
+    content::BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
+        trigger_handle_, started_finalizing_callback);
+  }
+
+  int get_receive_count() const { return receive_count_; }
+  bool get_started_finalizations() const {
+    return started_finalizations_count_;
+  }
+  bool get_last_started_finalization_success() const {
+    return last_on_started_finalizing_success_;
+  }
+
+ private:
+  void OnUpload(const scoped_refptr<base::RefCountedString>& file_contents,
+                base::Callback<void()> done_callback) {
+    receive_count_ += 1;
+
+    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+                                     base::Bind(done_callback));
+    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+                                     base::Bind(on_upload_callback_));
+  }
+
+  void OnStartedFinalizing(bool success) {
+    started_finalizations_count_++;
+    last_on_started_finalizing_success_ = success;
+
+    if (!on_started_finalization_callback_.is_null()) {
+      content::BrowserThread::PostTask(
+          content::BrowserThread::UI, FROM_HERE,
+          base::Bind(on_started_finalization_callback_));
+    }
+  }
+
+  base::Closure on_upload_callback_;
+  base::Closure on_started_finalization_callback_;
+  int receive_count_;
+  int started_finalizations_count_;
+  content::BackgroundTracingManager::TriggerHandle trigger_handle_;
+  bool last_on_started_finalizing_success_;
+};
+
+IN_PROC_BROWSER_TEST_F(ChromeTracingDelegateBrowserTest,
+                       BackgroundTracingTimeThrottled) {
+  base::RunLoop wait_for_upload;
+
+  EXPECT_TRUE(StartPreemptiveScenario(
+      wait_for_upload.QuitClosure(),
+      content::BackgroundTracingManager::NO_DATA_FILTERING));
+
+  TriggerReactiveScenario(base::Closure());
+
+  wait_for_upload.Run();
+
+  EXPECT_TRUE(get_receive_count() == 1);
+
+  PrefService* local_state = g_browser_process->local_state();
+  DCHECK(local_state);
+  const base::Time last_upload_time = base::Time::FromInternalValue(
+      local_state->GetInt64(prefs::kBackgroundTracingLastUpload));
+  EXPECT_FALSE(last_upload_time.is_null());
+
+  // We should not be able to start a new reactive scenario immediately after
+  // a previous one gets uploaded.
+  EXPECT_FALSE(StartPreemptiveScenario(
+      base::Closure(), content::BackgroundTracingManager::NO_DATA_FILTERING));
+}
+
+IN_PROC_BROWSER_TEST_F(ChromeTracingDelegateBrowserTest,
+                       BackgroundTracingThrottleTimeElapsed) {
+  base::RunLoop wait_for_upload;
+
+  EXPECT_TRUE(StartPreemptiveScenario(
+      wait_for_upload.QuitClosure(),
+      content::BackgroundTracingManager::NO_DATA_FILTERING));
+
+  TriggerReactiveScenario(base::Closure());
+
+  wait_for_upload.Run();
+
+  EXPECT_TRUE(get_receive_count() == 1);
+
+  PrefService* local_state = g_browser_process->local_state();
+  DCHECK(local_state);
+  const base::Time last_upload_time = base::Time::FromInternalValue(
+      local_state->GetInt64(prefs::kBackgroundTracingLastUpload));
+  EXPECT_FALSE(last_upload_time.is_null());
+
+  // We move the last upload time to eight days in the past,
+  // and at that point should be able to start a scenario again.
+  base::Time new_upload_time = last_upload_time - base::TimeDelta::FromDays(8);
+  local_state->SetInt64(prefs::kBackgroundTracingLastUpload,
+                        new_upload_time.ToInternalValue());
+  EXPECT_TRUE(StartPreemptiveScenario(
+      base::Closure(), content::BackgroundTracingManager::NO_DATA_FILTERING));
+}
+
+// If we need a PII-stripped trace, any existing OTR session should block the
+// trace.
+IN_PROC_BROWSER_TEST_F(ChromeTracingDelegateBrowserTest,
+                       ExistingIncognitoSessionBlockingTraceStart) {
+  EXPECT_TRUE(chrome::ExecuteCommand(browser(), IDC_NEW_INCOGNITO_WINDOW));
+  EXPECT_TRUE(BrowserList::IsOffTheRecordSessionActive());
+  EXPECT_FALSE(StartPreemptiveScenario(
+      base::Closure(), content::BackgroundTracingManager::ANONYMIZE_DATA));
+}
+
+// If we need a PII-stripped trace, any new OTR session during tracing should
+// block the finalization of the trace.
+IN_PROC_BROWSER_TEST_F(ChromeTracingDelegateBrowserTest,
+                       NewIncognitoSessionBlockingTraceFinalization) {
+  EXPECT_TRUE(StartPreemptiveScenario(
+      base::Closure(), content::BackgroundTracingManager::ANONYMIZE_DATA));
+
+  EXPECT_TRUE(chrome::ExecuteCommand(browser(), IDC_NEW_INCOGNITO_WINDOW));
+  EXPECT_TRUE(BrowserList::IsOffTheRecordSessionActive());
+
+  base::RunLoop wait_for_finalization_start;
+  TriggerReactiveScenario(wait_for_finalization_start.QuitClosure());
+  wait_for_finalization_start.Run();
+
+  EXPECT_TRUE(get_started_finalizations() == 1);
+  EXPECT_FALSE(get_last_started_finalization_success());
+}
+
+}  // namespace
diff --git a/chrome/browser/ui/android/infobars/account_chooser_infobar.cc b/chrome/browser/ui/android/infobars/account_chooser_infobar.cc
index 761d5bb..758dfbb 100644
--- a/chrome/browser/ui/android/infobars/account_chooser_infobar.cc
+++ b/chrome/browser/ui/android/infobars/account_chooser_infobar.cc
@@ -114,8 +114,7 @@
       GetDelegate()->local_credentials_forms().size());
   base::android::ScopedJavaGlobalRef<jobject> java_infobar_global;
   java_infobar_global.Reset(Java_AccountChooserInfoBar_show(
-      env, reinterpret_cast<intptr_t>(this), GetEnumeratedIconId(),
-      java_credentials_array.obj()));
+      env, GetEnumeratedIconId(), java_credentials_array.obj()));
   base::android::ScopedJavaLocalRef<jobject> java_infobar(java_infobar_global);
   content::WebContents* web_contents =
       InfoBarService::WebContentsFromInfoBar(this);
@@ -153,6 +152,14 @@
   return static_cast<AccountChooserInfoBarDelegateAndroid*>(delegate());
 }
 
+void AccountChooserInfoBar::SetJavaInfoBar(
+    const base::android::JavaRef<jobject>& java_info_bar) {
+  InfoBarAndroid::SetJavaInfoBar(java_info_bar);
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_AccountChooserInfoBar_setNativePtr(env, java_info_bar.obj(),
+                                          reinterpret_cast<intptr_t>(this));
+}
+
 bool RegisterAccountChooserInfoBar(JNIEnv* env) {
   return RegisterNativesImpl(env);
 }
diff --git a/chrome/browser/ui/android/infobars/account_chooser_infobar.h b/chrome/browser/ui/android/infobars/account_chooser_infobar.h
index 07b5abb3c4..b2d800c 100644
--- a/chrome/browser/ui/android/infobars/account_chooser_infobar.h
+++ b/chrome/browser/ui/android/infobars/account_chooser_infobar.h
@@ -33,6 +33,8 @@
       JNIEnv* env) override;
   void ProcessButton(int action, const std::string& action_value) override;
   AccountChooserInfoBarDelegateAndroid* GetDelegate();
+  void SetJavaInfoBar(
+      const base::android::JavaRef<jobject>& java_info_bar) override;
 
   DISALLOW_COPY_AND_ASSIGN(AccountChooserInfoBar);
 };
diff --git a/chrome/browser/ui/android/infobars/app_banner_infobar_android.cc b/chrome/browser/ui/android/infobars/app_banner_infobar_android.cc
index 16e8f14..cf9847c 100644
--- a/chrome/browser/ui/android/infobars/app_banner_infobar_android.cc
+++ b/chrome/browser/ui/android/infobars/app_banner_infobar_android.cc
@@ -49,7 +49,6 @@
   if (!japp_data_.is_null()) {
     infobar.Reset(Java_AppBannerInfoBarAndroid_createNativeAppInfoBar(
         env,
-        reinterpret_cast<intptr_t>(this),
         app_title.obj(),
         java_bitmap.obj(),
         japp_data_.obj()));
@@ -65,7 +64,6 @@
 
     infobar.Reset(Java_AppBannerInfoBarAndroid_createWebAppInfoBar(
         env,
-        reinterpret_cast<intptr_t>(this),
         app_title.obj(),
         java_bitmap.obj(),
         app_url.obj()));
diff --git a/chrome/browser/ui/android/infobars/confirm_infobar.cc b/chrome/browser/ui/android/infobars/confirm_infobar.cc
index 149e0de..9fef5cf 100644
--- a/chrome/browser/ui/android/infobars/confirm_infobar.cc
+++ b/chrome/browser/ui/android/infobars/confirm_infobar.cc
@@ -54,9 +54,9 @@
   }
 
   return Java_ConfirmInfoBarDelegate_showConfirmInfoBar(
-      env, java_confirm_delegate_.obj(), reinterpret_cast<intptr_t>(this),
-      GetEnumeratedIconId(), java_bitmap.obj(), message_text.obj(),
-      link_text.obj(), ok_button_text.obj(), cancel_button_text.obj());
+      env, java_confirm_delegate_.obj(), GetEnumeratedIconId(),
+      java_bitmap.obj(), message_text.obj(), link_text.obj(),
+      ok_button_text.obj(), cancel_button_text.obj());
 }
 
 void ConfirmInfoBar::OnLinkClicked(JNIEnv* env, jobject obj) {
diff --git a/chrome/browser/ui/android/infobars/data_reduction_proxy_infobar.cc b/chrome/browser/ui/android/infobars/data_reduction_proxy_infobar.cc
index 57e295e7..f123334 100644
--- a/chrome/browser/ui/android/infobars/data_reduction_proxy_infobar.cc
+++ b/chrome/browser/ui/android/infobars/data_reduction_proxy_infobar.cc
@@ -43,10 +43,7 @@
       Java_DataReductionProxyInfoBarDelegate_create(env));
 
   return Java_DataReductionProxyInfoBarDelegate_showDataReductionProxyInfoBar(
-      env,
-      java_data_reduction_proxy_delegate_.obj(),
-      reinterpret_cast<intptr_t>(this),
-      GetEnumeratedIconId());
+      env, java_data_reduction_proxy_delegate_.obj(), GetEnumeratedIconId());
 }
 
 DataReductionProxyInfoBarDelegate* DataReductionProxyInfoBar::GetDelegate() {
diff --git a/chrome/browser/ui/android/infobars/download_overwrite_infobar.cc b/chrome/browser/ui/android/infobars/download_overwrite_infobar.cc
index a5da969..ec5f13a 100644
--- a/chrome/browser/ui/android/infobars/download_overwrite_infobar.cc
+++ b/chrome/browser/ui/android/infobars/download_overwrite_infobar.cc
@@ -40,8 +40,7 @@
       base::android::ConvertUTF8ToJavaString(env, delegate->GetDirFullPath());
   base::android::ScopedJavaLocalRef<jobject> java_infobar(
       Java_DownloadOverwriteInfoBar_createInfoBar(
-          env, reinterpret_cast<intptr_t>(this), j_file_name.obj(),
-          j_dir_name.obj(), j_dir_full_path.obj()));
+          env, j_file_name.obj(), j_dir_name.obj(), j_dir_full_path.obj()));
   return java_infobar;
 }
 
diff --git a/chrome/browser/ui/android/infobars/generated_password_saved_infobar.cc b/chrome/browser/ui/android/infobars/generated_password_saved_infobar.cc
index 2412b69..823ee04 100644
--- a/chrome/browser/ui/android/infobars/generated_password_saved_infobar.cc
+++ b/chrome/browser/ui/android/infobars/generated_password_saved_infobar.cc
@@ -33,7 +33,7 @@
       static_cast<GeneratedPasswordSavedInfoBarDelegateAndroid*>(delegate());
 
   return Java_GeneratedPasswordSavedInfoBarDelegate_show(
-      env, reinterpret_cast<intptr_t>(this), GetEnumeratedIconId(),
+      env, GetEnumeratedIconId(),
       base::android::ConvertUTF16ToJavaString(
           env, infobar_delegate->message_text()).obj(),
       infobar_delegate->inline_link_range().start(),
diff --git a/chrome/browser/ui/android/infobars/infobar_android.cc b/chrome/browser/ui/android/infobars/infobar_android.cc
index 137eb74..27de345 100644
--- a/chrome/browser/ui/android/infobars/infobar_android.cc
+++ b/chrome/browser/ui/android/infobars/infobar_android.cc
@@ -21,20 +21,31 @@
 }
 
 InfoBarAndroid::~InfoBarAndroid() {
+  if (!java_info_bar_.is_null()) {
+    JNIEnv* env = base::android::AttachCurrentThread();
+    Java_InfoBar_onNativeDestroyed(env, java_info_bar_.obj());
+  }
 }
 
 void InfoBarAndroid::ReassignJavaInfoBar(InfoBarAndroid* replacement) {
   DCHECK(replacement);
   if (!java_info_bar_.is_null()) {
-    replacement->set_java_infobar(java_info_bar_);
+    replacement->SetJavaInfoBar(java_info_bar_);
     java_info_bar_.Reset();
   }
 }
 
-void InfoBarAndroid::set_java_infobar(
+void InfoBarAndroid::SetJavaInfoBar(
     const base::android::JavaRef<jobject>& java_info_bar) {
   DCHECK(java_info_bar_.is_null());
   java_info_bar_.Reset(java_info_bar);
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_InfoBar_setNativeInfoBar(env, java_info_bar.obj(),
+                                reinterpret_cast<intptr_t>(this));
+}
+
+jobject InfoBarAndroid::GetJavaInfoBar() {
+  return java_info_bar_.obj();
 }
 
 bool InfoBarAndroid::HasSetJavaInfoBar() const {
diff --git a/chrome/browser/ui/android/infobars/infobar_android.h b/chrome/browser/ui/android/infobars/infobar_android.h
index 8070753..ea36813d 100644
--- a/chrome/browser/ui/android/infobars/infobar_android.h
+++ b/chrome/browser/ui/android/infobars/infobar_android.h
@@ -44,7 +44,9 @@
   virtual base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
       JNIEnv* env) = 0;
 
-  void set_java_infobar(const base::android::JavaRef<jobject>& java_info_bar);
+  virtual void SetJavaInfoBar(
+      const base::android::JavaRef<jobject>& java_info_bar);
+  jobject GetJavaInfoBar();
   bool HasSetJavaInfoBar() const;
 
   // Tells the Java-side counterpart of this InfoBar to point to the replacement
@@ -74,6 +76,7 @@
   virtual void ProcessButton(int action,
                              const std::string& action_value) = 0;
   void CloseInfoBar();
+  InfoBarAndroid* infobar_android() { return this; }
 
  private:
   base::android::ScopedJavaGlobalRef<jobject> java_info_bar_;
diff --git a/chrome/browser/ui/android/infobars/infobar_container_android.cc b/chrome/browser/ui/android/infobars/infobar_container_android.cc
index 7e17d63e..d30b8ee 100644
--- a/chrome/browser/ui/android/infobars/infobar_container_android.cc
+++ b/chrome/browser/ui/android/infobars/infobar_container_android.cc
@@ -63,7 +63,7 @@
       android_bar->CreateRenderInfoBar(env);
   Java_InfoBarContainer_addInfoBar(
       env, weak_java_infobar_container_.get(env).obj(), java_infobar.obj());
-  android_bar->set_java_infobar(java_infobar);
+  android_bar->SetJavaInfoBar(java_infobar);
 }
 
 void InfoBarContainerAndroid::PlatformSpecificReplaceInfoBar(
diff --git a/chrome/browser/ui/android/infobars/save_password_infobar.cc b/chrome/browser/ui/android/infobars/save_password_infobar.cc
index 88e1824..5f181d12 100644
--- a/chrome/browser/ui/android/infobars/save_password_infobar.cc
+++ b/chrome/browser/ui/android/infobars/save_password_infobar.cc
@@ -30,8 +30,8 @@
       env, save_password_delegate->GetMessageText());
 
   return Java_SavePasswordInfoBar_show(
-      env, reinterpret_cast<intptr_t>(this), GetEnumeratedIconId(),
-      message_text.obj(), save_password_delegate->title_link_range().start(),
+      env, GetEnumeratedIconId(), message_text.obj(),
+      save_password_delegate->title_link_range().start(),
       save_password_delegate->title_link_range().end(), ok_button_text.obj(),
       cancel_button_text.obj(), save_password_delegate->ShouldShowMoreButton());
 }
diff --git a/chrome/browser/ui/android/infobars/translate_infobar.cc b/chrome/browser/ui/android/infobars/translate_infobar.cc
index d287757..eaa7af75 100644
--- a/chrome/browser/ui/android/infobars/translate_infobar.cc
+++ b/chrome/browser/ui/android/infobars/translate_infobar.cc
@@ -9,7 +9,7 @@
 #include "base/android/jni_weak_ref.h"
 #include "chrome/browser/translate/chrome_translate_client.h"
 #include "components/translate/core/browser/translate_infobar_delegate.h"
-#include "jni/TranslateInfoBarDelegate_jni.h"
+#include "jni/TranslateInfoBar_jni.h"
 
 // ChromeTranslateClient
 // ----------------------------------------------------------
@@ -24,14 +24,13 @@
 
 TranslateInfoBar::TranslateInfoBar(
     scoped_ptr<translate::TranslateInfoBarDelegate> delegate)
-    : InfoBarAndroid(delegate.Pass()), java_translate_delegate_() {
+    : InfoBarAndroid(delegate.Pass()) {
 }
 
 TranslateInfoBar::~TranslateInfoBar() {
 }
 
 ScopedJavaLocalRef<jobject> TranslateInfoBar::CreateRenderInfoBar(JNIEnv* env) {
-  java_translate_delegate_.Reset(Java_TranslateInfoBarDelegate_create(env));
   translate::TranslateInfoBarDelegate* delegate = GetDelegate();
   std::vector<base::string16> languages;
   languages.reserve(delegate->num_languages());
@@ -40,9 +39,8 @@
 
   base::android::ScopedJavaLocalRef<jobjectArray> java_languages =
       base::android::ToJavaArrayOfStrings(env, languages);
-  return Java_TranslateInfoBarDelegate_showTranslateInfoBar(
-      env, java_translate_delegate_.obj(), reinterpret_cast<intptr_t>(this),
-      delegate->translate_step(), delegate->original_language_index(),
+  return Java_TranslateInfoBar_show(
+      env, delegate->translate_step(), delegate->original_language_index(),
       delegate->target_language_index(), delegate->ShouldAlwaysTranslate(),
       ShouldDisplayNeverTranslateInfoBarOnCancel(),
       delegate->triggered_from_menu(), java_languages.obj());
@@ -80,6 +78,14 @@
       this, delegate->translate_step());
 }
 
+void TranslateInfoBar::SetJavaInfoBar(
+    const base::android::JavaRef<jobject>& java_info_bar) {
+  InfoBarAndroid::SetJavaInfoBar(java_info_bar);
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_TranslateInfoBar_setNativePtr(env, java_info_bar.obj(),
+                                     reinterpret_cast<intptr_t>(this));
+}
+
 void TranslateInfoBar::ApplyTranslateOptions(JNIEnv* env,
                                              jobject obj,
                                              int source_language_index,
@@ -104,17 +110,9 @@
 void TranslateInfoBar::TransferOwnership(TranslateInfoBar* destination,
                                          translate::TranslateStep new_type) {
   JNIEnv* env = base::android::AttachCurrentThread();
-  if (Java_TranslateInfoBarDelegate_changeTranslateInfoBarTypeAndPointer(
-      env, java_translate_delegate_.obj(),
-      reinterpret_cast<intptr_t>(destination), new_type)) {
-    ReassignJavaInfoBar(destination);
-    destination->SetJavaDelegate(java_translate_delegate_.Release());
-  }
-}
-
-void TranslateInfoBar::SetJavaDelegate(jobject delegate) {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  java_translate_delegate_.Reset(env, delegate);
+  Java_TranslateInfoBar_changeTranslateInfoBarType(env, GetJavaInfoBar(),
+                                                   new_type);
+  ReassignJavaInfoBar(destination);
 }
 
 bool TranslateInfoBar::ShouldDisplayNeverTranslateInfoBarOnCancel() {
diff --git a/chrome/browser/ui/android/infobars/translate_infobar.h b/chrome/browser/ui/android/infobars/translate_infobar.h
index e210a0ca..06e514ae 100644
--- a/chrome/browser/ui/android/infobars/translate_infobar.h
+++ b/chrome/browser/ui/android/infobars/translate_infobar.h
@@ -35,16 +35,15 @@
       JNIEnv* env) override;
   void ProcessButton(int action, const std::string& action_value) override;
   void PassJavaInfoBar(InfoBarAndroid* source) override;
+  void SetJavaInfoBar(
+      const base::android::JavaRef<jobject>& java_info_bar) override;
 
   void TransferOwnership(TranslateInfoBar* destination,
                          translate::TranslateStep new_type);
-  void SetJavaDelegate(jobject delegate);
   bool ShouldDisplayNeverTranslateInfoBarOnCancel();
 
   translate::TranslateInfoBarDelegate* GetDelegate();
 
-  base::android::ScopedJavaGlobalRef<jobject> java_translate_delegate_;
-
   DISALLOW_COPY_AND_ASSIGN(TranslateInfoBar);
 };
 
diff --git a/chrome/browser/ui/app_list/app_list_controller_delegate.cc b/chrome/browser/ui/app_list/app_list_controller_delegate.cc
index 0e913304..e6a19fcb 100644
--- a/chrome/browser/ui/app_list/app_list_controller_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_controller_delegate.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
 
 #include "base/metrics/histogram.h"
-#include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/install_tracker_factory.h"
 #include "chrome/browser/extensions/launch_util.h"
@@ -38,10 +37,9 @@
 
 const extensions::Extension* GetExtension(Profile* profile,
                                           const std::string& extension_id) {
-  const ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile)->extension_service();
+  const ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
   const extensions::Extension* extension =
-      service->GetInstalledExtension(extension_id);
+      registry->GetInstalledExtension(extension_id);
   return extension;
 }
 
@@ -99,11 +97,7 @@
     Profile* profile,
     const std::string& extension_id) {
   DCHECK(CanDoShowAppInfoFlow());
-  ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile)->extension_service();
-  DCHECK(service);
-  const extensions::Extension* extension = service->GetInstalledExtension(
-      extension_id);
+  const extensions::Extension* extension = GetExtension(profile, extension_id);
   DCHECK(extension);
 
   OnShowChildDialog();
diff --git a/chrome/browser/ui/app_list/app_list_controller_delegate_impl.cc b/chrome/browser/ui/app_list/app_list_controller_delegate_impl.cc
index 61b4542..4733461f 100644
--- a/chrome/browser/ui/app_list/app_list_controller_delegate_impl.cc
+++ b/chrome/browser/ui/app_list/app_list_controller_delegate_impl.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/ui/app_list/app_list_controller_delegate_impl.h"
 
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/app_list/app_list_service_impl.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -14,7 +13,7 @@
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
-#include "extensions/browser/extension_system.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "net/base/url_util.h"
@@ -64,10 +63,9 @@
     Profile* profile,
     const std::string& extension_id) {
   DCHECK(CanDoCreateShortcutsFlow());
-  ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile)->extension_service();
-  DCHECK(service);
-  const extensions::Extension* extension = service->GetInstalledExtension(
+  extensions::ExtensionRegistry* registry =
+      extensions::ExtensionRegistry::Get(profile);
+  const extensions::Extension* extension = registry->GetInstalledExtension(
       extension_id);
   DCHECK(extension);
 
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.cc b/chrome/browser/ui/app_list/app_list_syncable_service.cc
index 0932d2c..b3bc806 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.cc
@@ -121,11 +121,9 @@
 }
 
 void UninstallExtension(ExtensionService* service, const std::string& id) {
-  if (service && service->GetInstalledExtension(id)) {
-    service->UninstallExtension(id,
-                                extensions::UNINSTALL_REASON_SYNC,
-                                base::Bind(&base::DoNothing),
-                                NULL);
+  if (service) {
+    ExtensionService::UninstallExtensionHelper(
+        service, id, extensions::UNINSTALL_REASON_SYNC);
   }
 }
 
diff --git a/chrome/browser/ui/app_list/extension_app_item.cc b/chrome/browser/ui/app_list/extension_app_item.cc
index a15893f1..471182c 100644
--- a/chrome/browser/ui/app_list/extension_app_item.cc
+++ b/chrome/browser/ui/app_list/extension_app_item.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/ui/app_list/extension_app_item.h"
 
 #include "base/prefs/pref_service.h"
-#include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/launch_util.h"
 #include "chrome/browser/profiles/profile.h"
@@ -19,7 +18,7 @@
 #include "content/public/browser/user_metrics.h"
 #include "extensions/browser/app_sorting.h"
 #include "extensions/browser/extension_prefs.h"
-#include "extensions/browser/extension_system.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_icon_set.h"
 #include "extensions/common/manifest_handlers/icons_handler.h"
@@ -196,7 +195,7 @@
   if (has_overlay_)
     icon = gfx::ImageSkia(new ShortcutOverlayImageSource(icon), icon.size());
 
-  SetIcon(icon, true);
+  SetIcon(icon);
 }
 
 void ExtensionAppItem::Move(const ExtensionAppItem* prev,
@@ -229,9 +228,10 @@
 }
 
 const Extension* ExtensionAppItem::GetExtension() const {
-  const ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile_)->extension_service();
-  const Extension* extension = service->GetInstalledExtension(extension_id_);
+  const extensions::ExtensionRegistry* registry =
+      extensions::ExtensionRegistry::Get(profile_);
+  const Extension* extension = registry->GetInstalledExtension(
+      extension_id_);
   return extension;
 }
 
diff --git a/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc b/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc
index e31e7128..b5aa353 100644
--- a/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc
+++ b/chrome/browser/ui/app_list/extension_app_model_builder_unittest.cc
@@ -23,6 +23,7 @@
 #include "chrome/test/base/testing_profile.h"
 #include "extensions/browser/app_sorting.h"
 #include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/uninstall_reason.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension_set.h"
@@ -183,7 +184,7 @@
 
 TEST_F(ExtensionAppModelBuilderTest, UninstallTerminatedApp) {
   const extensions::Extension* app =
-      service_->GetInstalledExtension(kPackagedApp2Id);
+      registry()->GetInstalledExtension(kPackagedApp2Id);
   ASSERT_TRUE(app != NULL);
 
   // Simulate an app termination.
diff --git a/chrome/browser/ui/app_list/extension_uninstaller.cc b/chrome/browser/ui/app_list/extension_uninstaller.cc
index 7927afa6..d6371c73 100644
--- a/chrome/browser/ui/app_list/extension_uninstaller.cc
+++ b/chrome/browser/ui/app_list/extension_uninstaller.cc
@@ -4,10 +4,9 @@
 
 #include "chrome/browser/ui/app_list/extension_uninstaller.h"
 
-#include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
-#include "extensions/browser/extension_system.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/uninstall_reason.h"
 #include "extensions/common/extension.h"
 
@@ -25,8 +24,8 @@
 
 void ExtensionUninstaller::Run() {
   const extensions::Extension* extension =
-      extensions::ExtensionSystem::Get(profile_)->extension_service()->
-          GetInstalledExtension(app_id_);
+      extensions::ExtensionRegistry::Get(profile_)->GetInstalledExtension(
+          app_id_);
   if (!extension) {
     CleanUp();
     return;
diff --git a/chrome/browser/ui/app_list/fast_show_pickler.cc b/chrome/browser/ui/app_list/fast_show_pickler.cc
index bd03646..35d5b50 100644
--- a/chrome/browser/ui/app_list/fast_show_pickler.cc
+++ b/chrome/browser/ui/app_list/fast_show_pickler.cc
@@ -159,13 +159,10 @@
   if (!it->ReadString(&short_name))
     return scoped_ptr<AppListItem>();
   result->SetNameAndShortName(name, short_name);
-  bool has_shadow = false;
-  if (!it->ReadBool(&has_shadow))
-    return scoped_ptr<AppListItem>();
   gfx::ImageSkia icon;
   if (!UnpickleImage(it, &icon))
     return scoped_ptr<AppListItem>();
-  result->SetIcon(icon, has_shadow);
+  result->SetIcon(icon);
   return result.Pass();
 }
 
@@ -177,8 +174,6 @@
     return false;
   if (!pickle->WriteString(item->short_name()))
     return false;
-  if (!pickle->WriteBool(item->has_shadow()))
-    return false;
   if (!PickleImage(pickle, item->icon()))
     return false;
   return true;
@@ -187,13 +182,13 @@
 void FastShowPickler::CopyOverItem(AppListItem* src_item,
                                    AppListItem* dest_item) {
   dest_item->SetNameAndShortName(src_item->name(), src_item->short_name());
-  dest_item->SetIcon(src_item->icon(), src_item->has_shadow());
+  dest_item->SetIcon(src_item->icon());
   // Do not set folder_id, pass that to AppListModel::AddItemToFolder() instead.
 }
 
 // The version of the pickle format defined here. This needs to be incremented
 // whenever this format is changed so new clients can invalidate old versions.
-const int FastShowPickler::kVersion = 3;
+const int FastShowPickler::kVersion = 4;
 
 scoped_ptr<base::Pickle> FastShowPickler::PickleAppListModelForFastShow(
     AppListModel* model) {
diff --git a/chrome/browser/ui/app_list/search/app_result.cc b/chrome/browser/ui/app_list/search/app_result.cc
index ec50023..89dbe9c 100644
--- a/chrome/browser/ui/app_list/search/app_result.cc
+++ b/chrome/browser/ui/app_list/search/app_result.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/ui/app_list/search/app_result.h"
 
 #include "base/time/time.h"
-#include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/app_context_menu.h"
@@ -15,7 +14,6 @@
 #include "chrome/common/extensions/extension_metrics.h"
 #include "content/public/browser/user_metrics.h"
 #include "extensions/browser/extension_registry.h"
-#include "extensions/browser/extension_system.h"
 #include "extensions/browser/extension_system_provider.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/common/constants.h"
@@ -41,8 +39,8 @@
     set_display_type(is_recommendation ? DISPLAY_RECOMMENDATION : DISPLAY_TILE);
 
   const extensions::Extension* extension =
-      extensions::ExtensionSystem::Get(profile_)->extension_service()
-          ->GetInstalledExtension(app_id_);
+      extensions::ExtensionRegistry::Get(profile_)->GetInstalledExtension(
+          app_id_);
   DCHECK(extension);
 
   is_platform_app_ = extension->is_platform_app();
@@ -83,8 +81,8 @@
 void AppResult::Open(int event_flags) {
   RecordHistogram(APP_SEARCH_RESULT);
   const extensions::Extension* extension =
-      extensions::ExtensionSystem::Get(profile_)->extension_service()
-          ->GetInstalledExtension(app_id_);
+      extensions::ExtensionRegistry::Get(profile_)->GetInstalledExtension(
+          app_id_);
   if (!extension)
     return;
 
diff --git a/chrome/browser/ui/app_list/search/launcher_search/extension_badged_icon_image.cc b/chrome/browser/ui/app_list/search/launcher_search/extension_badged_icon_image.cc
index 40d22dc5..283354d3a 100644
--- a/chrome/browser/ui/app_list/search/launcher_search/extension_badged_icon_image.cc
+++ b/chrome/browser/ui/app_list/search/launcher_search/extension_badged_icon_image.cc
@@ -24,26 +24,28 @@
   BadgedIconSource(const gfx::ImageSkia& custom_icon,
                    const gfx::ImageSkia& extension_icon,
                    const gfx::Size& icon_size)
-      : CanvasImageSource(icon_size, false), custom_icon_(custom_icon) {
-    // Badged icon size is 2/3 of custom icon.
-    int badge_dimension = size().width() * 2 / 3;
-    gfx::Size badge_size = gfx::Size(badge_dimension, badge_dimension);
-    resized_extension_icon_ = gfx::ImageSkiaOperations::CreateResizedImage(
-        extension_icon, skia::ImageOperations::ResizeMethod::RESIZE_GOOD,
-        badge_size);
-  }
+      : CanvasImageSource(icon_size, false),
+        custom_icon_(custom_icon),
+        extension_icon_(extension_icon) {}
 
   void Draw(gfx::Canvas* canvas) override {
-    canvas->DrawImageInt(custom_icon_, 0, 0);
-    canvas->DrawImageInt(
-        resized_extension_icon_,
-        size().width() - resized_extension_icon_.size().width(),
-        size().height() - resized_extension_icon_.size().height());
+    canvas->DrawImageInt(custom_icon_, 0, 0, custom_icon_.size().width(),
+                         custom_icon_.height(), 0, 0, size().width(),
+                         size().height(), true);
+
+    // Badged icon size is 2/3 of custom icon.
+    const int badge_dimension = size().width() * 2 / 3;
+    const gfx::Size badge_size = gfx::Size(badge_dimension, badge_dimension);
+    canvas->DrawImageInt(extension_icon_, 0, 0, extension_icon_.size().width(),
+                         extension_icon_.size().height(),
+                         size().width() - badge_size.width(),
+                         size().height() - badge_size.height(),
+                         badge_size.width(), badge_size.height(), true);
   }
 
  private:
-  gfx::ImageSkia custom_icon_;
-  gfx::ImageSkia resized_extension_icon_;
+  const gfx::ImageSkia custom_icon_;
+  const gfx::ImageSkia extension_icon_;
 
   DISALLOW_COPY_AND_ASSIGN(BadgedIconSource);
 };
diff --git a/chrome/browser/ui/app_list/search/launcher_search/extension_badged_icon_image_impl.cc b/chrome/browser/ui/app_list/search/launcher_search/extension_badged_icon_image_impl.cc
index 71caf57..496b8da 100644
--- a/chrome/browser/ui/app_list/search/launcher_search/extension_badged_icon_image_impl.cc
+++ b/chrome/browser/ui/app_list/search/launcher_search/extension_badged_icon_image_impl.cc
@@ -43,11 +43,14 @@
   const extensions::ExtensionResource& resource =
       extension_->GetResource(file_path);
 
-  // Load image with ImageLoader. ImageLoader resizes image to |icon_size_|.
+  // Load image as scale factor 2.0. Resizing image to proper size depending on
+  // DPI is done in BadgedIconSource.
   std::vector<extensions::ImageLoader::ImageRepresentation> info_list;
   info_list.push_back(extensions::ImageLoader::ImageRepresentation(
-      resource, extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
-      icon_size_, ui::SCALE_FACTOR_100P));
+      resource,
+      extensions::ImageLoader::ImageRepresentation::RESIZE_WHEN_LARGER,
+      gfx::Size(icon_size_.width() * 2, icon_size_.height() * 2),
+      ui::SCALE_FACTOR_200P));
   extensions::ImageLoader::Get(profile_)->LoadImagesAsync(
       extension_, info_list,
       base::Bind(&ExtensionBadgedIconImageImpl::OnCustomIconImageLoaded,
diff --git a/chrome/browser/ui/app_list/test/fast_show_pickler_unittest.cc b/chrome/browser/ui/app_list/test/fast_show_pickler_unittest.cc
index 678742f6..9e9dd1b4 100644
--- a/chrome/browser/ui/app_list/test/fast_show_pickler_unittest.cc
+++ b/chrome/browser/ui/app_list/test/fast_show_pickler_unittest.cc
@@ -98,7 +98,7 @@
   AppListItem* app1 =
       model.AddItem(make_scoped_ptr(new AppListItem("abc")).Pass());
   model.SetItemName(app1, "hello, there");
-  app1->SetIcon(MakeImage(), true);
+  app1->SetIcon(MakeImage());
   AppListItem* app2 =
       model.AddItem(make_scoped_ptr(new AppListItem("abc2")).Pass());
   model.SetItemName(app2, "hello, there 2");
@@ -111,7 +111,7 @@
   AppListItem* app1 =
       model.AddItem(make_scoped_ptr(new AppListItem("abc")).Pass());
   model.SetItemName(app1, "hello, there");
-  app1->SetIcon(gfx::ImageSkia(), true);
+  app1->SetIcon(gfx::ImageSkia());
 
   DoConsistencyChecks(&model);
 }
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc
index ac0ae5f..ee37e65 100644
--- a/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc
@@ -127,8 +127,10 @@
   UnregisterApp(window);
 }
 
-void AppWindowLauncherController::OnWindowActivated(aura::Window* new_active,
-                                                    aura::Window* old_active) {
+void AppWindowLauncherController::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* new_active,
+    aura::Window* old_active) {
   // Make the newly active window the active (first) entry in the controller.
   AppWindowLauncherItemController* new_controller =
       ControllerForWindow(new_active);
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_controller.h b/chrome/browser/ui/ash/launcher/app_window_launcher_controller.h
index 4ff452ee..a4993dc 100644
--- a/chrome/browser/ui/ash/launcher/app_window_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/app_window_launcher_controller.h
@@ -59,8 +59,10 @@
   void OnWindowDestroying(aura::Window* window) override;
 
   // Overriden from client::ActivationChangeObserver:
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
 
  protected:
   // Registers a app window with the shelf and this object.
diff --git a/chrome/browser/ui/ash/launcher/browser_status_monitor.cc b/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
index 08f96c0..0ef0124e 100644
--- a/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
+++ b/chrome/browser/ui/ash/launcher/browser_status_monitor.cc
@@ -164,8 +164,10 @@
       UpdateBrowserItemState();
 }
 
-void BrowserStatusMonitor::OnWindowActivated(aura::Window* gained_active,
-                                             aura::Window* lost_active) {
+void BrowserStatusMonitor::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
   Browser* browser = NULL;
   content::WebContents* contents_from_gained = NULL;
   content::WebContents* contents_from_lost = NULL;
diff --git a/chrome/browser/ui/ash/launcher/browser_status_monitor.h b/chrome/browser/ui/ash/launcher/browser_status_monitor.h
index b0a4e5b..e7671ba 100644
--- a/chrome/browser/ui/ash/launcher/browser_status_monitor.h
+++ b/chrome/browser/ui/ash/launcher/browser_status_monitor.h
@@ -56,8 +56,10 @@
   void UpdateBrowserItemState();
 
   // aura::client::ActivationChangeObserver overrides:
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
 
   // aura::WindowObserver overrides:
   void OnWindowDestroyed(aura::Window* window) override;
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
index 0535f8cb..16e4113c 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
@@ -237,7 +237,7 @@
   while (app_observer_iterator != user_id_to_app_observer_.end()) {
     Profile* profile = multi_user_util::GetProfileFromUserID(
         app_observer_iterator->first);
-    DCHECK(profile);
+    CHECK(profile) << "profile not found for:" << app_observer_iterator->first;
     extensions::AppWindowRegistry::Get(profile)
         ->RemoveObserver(app_observer_iterator->second);
     delete app_observer_iterator->second;
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
index 8a0bc14..91f4a40 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
@@ -109,6 +109,11 @@
   current_tree_->SetSelection(id, start, end);
 }
 
+void AutomationManagerAura::ShowContextMenu(int32 id) {
+  CHECK(enabled_);
+  current_tree_->ShowContextMenu(id);
+}
+
 AutomationManagerAura::AutomationManagerAura()
     : enabled_(false), processing_events_(false) {
 }
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
index 1483e142..6d1fcf9 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
@@ -47,6 +47,7 @@
   void Focus(int32 id) override;
   void MakeVisible(int32 id) override;
   void SetSelection(int32 id, int32 start, int32 end) override;
+  void ShowContextMenu(int32 id) override;
 
  protected:
   virtual ~AutomationManagerAura();
diff --git a/chrome/browser/ui/aura/accessibility/ax_tree_source_aura.cc b/chrome/browser/ui/aura/accessibility/ax_tree_source_aura.cc
index 29912c7..9ab3f3eb 100644
--- a/chrome/browser/ui/aura/accessibility/ax_tree_source_aura.cc
+++ b/chrome/browser/ui/aura/accessibility/ax_tree_source_aura.cc
@@ -51,6 +51,12 @@
   obj->SetSelection(start, end);
 }
 
+void AXTreeSourceAura::ShowContextMenu(int32 id) {
+  AXAuraObjWrapper* obj = AXAuraObjCache::GetInstance()->Get(id);
+  CHECK(obj);
+  obj->ShowContextMenu();
+}
+
 AXAuraObjWrapper* AXTreeSourceAura::GetRoot() const {
   return root_.get();
 }
diff --git a/chrome/browser/ui/aura/accessibility/ax_tree_source_aura.h b/chrome/browser/ui/aura/accessibility/ax_tree_source_aura.h
index f5ac5be..fbe5f5f 100644
--- a/chrome/browser/ui/aura/accessibility/ax_tree_source_aura.h
+++ b/chrome/browser/ui/aura/accessibility/ax_tree_source_aura.h
@@ -28,6 +28,7 @@
   void Focus(int32 id);
   void MakeVisible(int32 id);
   void SetSelection(int32 id, int32 start, int32 end);
+  void ShowContextMenu(int32 id);
 
   // AXTreeSource implementation.
   views::AXAuraObjWrapper* GetRoot() const override;
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 6ccb52ca..1cc78f2 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -107,7 +107,7 @@
 #include "chrome/browser/ui/chrome_select_file_policy.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
 #include "chrome/browser/ui/exclusive_access/mouse_lock_controller.h"
-#include "chrome/browser/ui/extensions/bookmark_app_browser_controller.h"
+#include "chrome/browser/ui/extensions/hosted_app_browser_controller.h"
 #include "chrome/browser/ui/fast_unload_controller.h"
 #include "chrome/browser/ui/find_bar/find_bar.h"
 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
@@ -418,9 +418,9 @@
   if (chrome::IsInstantExtendedAPIEnabled() && is_type_tabbed())
     instant_controller_.reset(new BrowserInstantController(this));
 
-  if (extensions::BookmarkAppBrowserController::IsForBookmarkApp(this)) {
-    bookmark_app_controller_.reset(
-        new extensions::BookmarkAppBrowserController(this));
+  if (extensions::HostedAppBrowserController::IsForHostedApp(this)) {
+    hosted_app_controller_.reset(
+        new extensions::HostedAppBrowserController(this));
   }
 
   UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_INIT);
@@ -429,8 +429,8 @@
 
   window_ = params.window ? params.window : CreateBrowserWindow(this);
 
-  if (bookmark_app_controller_)
-    bookmark_app_controller_->UpdateLocationBarVisibility(false);
+  if (hosted_app_controller_)
+    hosted_app_controller_->UpdateLocationBarVisibility(false);
 
   // Create the extension window controller before sending notifications.
   extension_window_controller_.reset(
@@ -1438,8 +1438,8 @@
                        content::INVALIDATE_TYPE_LOAD))
     command_controller_->TabStateChanged();
 
-  if (bookmark_app_controller_)
-    bookmark_app_controller_->UpdateLocationBarVisibility(true);
+  if (hosted_app_controller_)
+    hosted_app_controller_->UpdateLocationBarVisibility(true);
 }
 
 void Browser::VisibleSSLStateChanged(const WebContents* source) {
@@ -2429,8 +2429,8 @@
   if (!is_app())
     return !is_trusted_source();
 
-  if (bookmark_app_controller_)
-    return bookmark_app_controller_->SupportsLocationBar();
+  if (hosted_app_controller_)
+    return hosted_app_controller_->SupportsLocationBar();
 
   return false;
 }
@@ -2441,8 +2441,8 @@
   if (!is_app())
     return false;
 
-  if (bookmark_app_controller_)
-    return bookmark_app_controller_->should_use_web_app_frame();
+  if (hosted_app_controller_)
+    return hosted_app_controller_->should_use_web_app_frame();
 
   return false;
 }
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index 0fee68b7..c4a3a62c 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -81,7 +81,7 @@
 }
 
 namespace extensions {
-class BookmarkAppBrowserController;
+class HostedAppBrowserController;
 class Extension;
 class ExtensionRegistry;
 class WindowController;
@@ -283,8 +283,8 @@
   BrowserInstantController* instant_controller() {
     return instant_controller_.get();
   }
-  extensions::BookmarkAppBrowserController* bookmark_app_controller() {
-    return bookmark_app_controller_.get();
+  extensions::HostedAppBrowserController* hosted_app_controller() {
+    return hosted_app_controller_.get();
   }
 
   // Get the FindBarController for this browser, creating it if it does not
@@ -963,7 +963,7 @@
   scoped_ptr<BrowserInstantController> instant_controller_;
 
   // Helper which handles bookmark app specific browser configuration.
-  scoped_ptr<extensions::BookmarkAppBrowserController> bookmark_app_controller_;
+  scoped_ptr<extensions::HostedAppBrowserController> hosted_app_controller_;
 
   BookmarkBar::State bookmark_bar_state_;
 
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 9cf66fa..451c41f 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -1415,7 +1415,10 @@
 
   EXPECT_FALSE(
       dev_tools_browser->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR));
-  EXPECT_FALSE(
+
+  // App windows can show location bars, for example when they navigate away
+  // from their starting origin.
+  EXPECT_TRUE(
       app_browser->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR));
 
   DevToolsWindowTesting::CloseDevToolsWindowSync(devtools_window);
diff --git a/chrome/browser/ui/cocoa/framed_browser_window.mm b/chrome/browser/ui/cocoa/framed_browser_window.mm
index 22f44a2..5d098be8 100644
--- a/chrome/browser/ui/cocoa/framed_browser_window.mm
+++ b/chrome/browser/ui/cocoa/framed_browser_window.mm
@@ -55,7 +55,7 @@
   if ((self = [super initWithContentRect:contentRect
                                styleMask:styleMask
                                  backing:NSBackingStoreBuffered
-                                   defer:NO
+                                   defer:YES
                   wantsViewsOverTitlebar:hasTabStrip])) {
     // The 10.6 fullscreen code copies the title to a different window, which
     // will assert if it's nil.
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h
index 1786be9..9c30285 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h
@@ -83,6 +83,12 @@
   virtual void OnDidChange() = 0;
   virtual void OnDidEndEditing() = 0;
 
+  // Called when -insertText: is invoked on the editor.
+  virtual void OnInsertText() = 0;
+
+  // Called after the completion of a -drawRect: operation.
+  virtual void OnDidDrawRect() = 0;
+
   // NSResponder translates certain keyboard actions into selectors
   // passed to -doCommandBySelector:.  The selector is forwarded here,
   // return true if |cmd| is handled, false if the caller should
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm
index 45b4a01..f8228b3 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm
@@ -359,6 +359,10 @@
 // Prevent control characters from being entered into the Omnibox.
 // This is invoked for keyboard entry, not for pasting.
 - (void)insertText:(id)aString {
+  AutocompleteTextFieldObserver* observer = [self observer];
+  if (observer)
+    observer->OnInsertText();
+
   // Repeatedly remove control characters.  The loop will only ever
   // execute at all when the user enters control characters (using
   // Ctrl-Alt- or Ctrl-Q).  Making this generally efficient would
@@ -408,9 +412,6 @@
   return modifiedRange;
 }
 
-
-
-
 - (void)setSelectedRange:(NSRange)charRange
                 affinity:(NSSelectionAffinity)affinity
           stillSelecting:(BOOL)flag {
@@ -546,6 +547,9 @@
       [[self delegate] suggestColor],
       self,
       [self bounds]);
+  AutocompleteTextFieldObserver* observer = [self observer];
+  if (observer)
+    observer->OnDidDrawRect();
 }
 
 @end
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
index 6f866f7..1d07e37 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
@@ -828,6 +828,7 @@
   EXPECT_CALL(field_observer_, OnSetFocus(false)).Times(testing::AnyNumber());
   EXPECT_CALL(field_observer_, OnKillFocus()).Times(testing::AnyNumber());
   EXPECT_CALL(field_observer_, OnDidEndEditing()).Times(testing::AnyNumber());
+  EXPECT_CALL(field_observer_, OnDidDrawRect()).Times(testing::AnyNumber());
 
   // Ensure the field is currently not first responder.
   [test_window() makePretendKeyWindowAndSetFirstResponder:nil];
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h
index 4ac3e5f..9d1b77c 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h
@@ -50,6 +50,8 @@
   MOCK_METHOD0(OnBeforeChange, void());
   MOCK_METHOD0(OnDidChange, void());
   MOCK_METHOD0(OnDidEndEditing, void());
+  MOCK_METHOD0(OnInsertText, void());
+  MOCK_METHOD0(OnDidDrawRect, void());
   MOCK_METHOD1(OnDoCommandBySelector, bool(SEL cmd));
   MOCK_METHOD1(OnSetFocus, void(bool control_down));
   MOCK_METHOD0(OnKillFocus, void());
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
index 385b79ed..6ecc9368 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
@@ -88,6 +88,8 @@
   void OnBeforeChange() override;
   void OnDidChange() override;
   void OnDidEndEditing() override;
+  void OnInsertText() override;
+  void OnDidDrawRect() override;
   bool OnDoCommandBySelector(SEL cmd) override;
   void OnSetFocus(bool control_down) override;
   void OnKillFocus() override;
@@ -201,6 +203,10 @@
   bool do_coalesced_range_update_;
   NSRange coalesced_range_update_;
 
+  // The time of the first character insert operation that has not yet been
+  // painted. Used to measure omnibox responsiveness with a histogram.
+  base::TimeTicks insert_char_time_;
+
   DISALLOW_COPY_AND_ASSIGN(OmniboxViewMac);
 };
 
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
index 0e8f701..aa59925 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
@@ -721,6 +721,21 @@
   ClosePopup();
 }
 
+void OmniboxViewMac::OnInsertText() {
+  // If |insert_char_time_| is not null, there's a pending insert char operation
+  // that hasn't been painted yet. Keep the earlier time.
+  if (insert_char_time_.is_null())
+    insert_char_time_ = base::TimeTicks::Now();
+}
+
+void OmniboxViewMac::OnDidDrawRect() {
+  if (!insert_char_time_.is_null()) {
+    UMA_HISTOGRAM_TIMES("Omnibox.CharTypedToRepaintLatency",
+                        base::TimeTicks::Now() - insert_char_time_);
+    insert_char_time_ = base::TimeTicks();
+  }
+}
+
 bool OmniboxViewMac::OnDoCommandBySelector(SEL cmd) {
   if (cmd == @selector(deleteForward:))
     delete_was_pressed_ = true;
diff --git a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
index 4c00e6e..9e6140c 100644
--- a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
+++ b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
@@ -1121,6 +1121,7 @@
       SyncConfirmationUIClosed(true);
   ProfileMetrics::LogProfileNewAvatarMenuSignin(
       ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_SETTINGS);
+  [self close];
 }
 
 - (IBAction)syncSettingsConfirmed:(id)sender {
diff --git a/chrome/browser/ui/cocoa/tab_contents/sad_tab_view_cocoa.mm b/chrome/browser/ui/cocoa/tab_contents/sad_tab_view_cocoa.mm
index c831e68..b2688dfb 100644
--- a/chrome/browser/ui/cocoa/tab_contents/sad_tab_view_cocoa.mm
+++ b/chrome/browser/ui/cocoa/tab_contents/sad_tab_view_cocoa.mm
@@ -199,21 +199,27 @@
 
 @implementation SadTabView
 
++ (NSColor*)backgroundColor {
+  return [NSColor colorWithCalibratedWhite:245.0f/255.0f alpha:1.0];
+}
+
 - (instancetype)initWithFrame:(NSRect)frame {
   if ((self = [super initWithFrame:frame])) {
     [self setWantsLayer:YES];
 
-    NSColor* backgroundColor = [NSColor colorWithCalibratedWhite:245.0f/255.0f
-                                                           alpha:1.0];
-    [[self layer] setBackgroundColor:[backgroundColor cr_CGColor]];
-
-    container_.reset(
-        [[SadTabContainerView alloc] initWithBackgroundColor:backgroundColor]);
+    container_.reset([[SadTabContainerView alloc]
+        initWithBackgroundColor:[SadTabView backgroundColor]]);
     [self addSubview:container_];
   }
   return self;
 }
 
+- (CALayer*)makeBackingLayer {
+  CALayer* layer = [super makeBackingLayer];
+  [layer setBackgroundColor:[[SadTabView backgroundColor] cr_CGColor]];
+  return layer;
+}
+
 - (BOOL)isFlipped {
   return YES;
 }
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
index 9c169727..b0acf9a 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -300,8 +300,7 @@
   };
   // Fields as for kBlockedAllowIDs, above.
   static const ContentSettingsTypeIdEntry kAllowedAllowIDs[] = {
-    // TODO(bauerb): The string shouldn't be "unblock" (they weren't blocked).
-    {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_UNBLOCK},
+    {CONTENT_SETTINGS_TYPE_COOKIES, IDS_ALLOWED_COOKIES_NO_ACTION},
     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_NO_ACTION},
     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_NO_ACTION},
   };
@@ -311,9 +310,7 @@
     int resource_id = GetIdForContentType(kAllowedAllowIDs,
                                           arraysize(kAllowedAllowIDs),
                                           content_type());
-    radio_allow_label = (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) ?
-        l10n_util::GetStringFUTF8(resource_id, display_host) :
-        l10n_util::GetStringUTF8(resource_id);
+    radio_allow_label = l10n_util::GetStringUTF8(resource_id);
   } else {
     radio_allow_label = l10n_util::GetStringFUTF8(
         GetIdForContentType(kBlockedAllowIDs, arraysize(kBlockedAllowIDs),
@@ -331,8 +328,7 @@
     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_NO_ACTION},
   };
   static const ContentSettingsTypeIdEntry kAllowedBlockIDs[] = {
-    // TODO(bauerb): The string should say "block".
-    {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_NO_ACTION},
+    {CONTENT_SETTINGS_TYPE_COOKIES, IDS_ALLOWED_COOKIES_BLOCK},
     {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_BLOCK},
     {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_BLOCK},
   };
@@ -342,9 +338,7 @@
     int resource_id = GetIdForContentType(kAllowedBlockIDs,
                                           arraysize(kAllowedBlockIDs),
                                           content_type());
-    radio_block_label = (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) ?
-        l10n_util::GetStringUTF8(resource_id) :
-        l10n_util::GetStringFUTF8(resource_id, display_host);
+    radio_block_label = l10n_util::GetStringFUTF8(resource_id, display_host);
   } else {
     radio_block_label = l10n_util::GetStringUTF8(
         GetIdForContentType(kBlockedBlockIDs, arraysize(kBlockedBlockIDs),
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc
index 961332f9..943693c9 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc
@@ -98,8 +98,6 @@
   std::string title = bubble_content.title;
   EXPECT_FALSE(title.empty());
   ASSERT_EQ(2U, bubble_content.radio_group.radio_items.size());
-  std::string radio1 = bubble_content.radio_group.radio_items[0];
-  std::string radio2 = bubble_content.radio_group.radio_items[1];
   EXPECT_FALSE(bubble_content.custom_link.empty());
   EXPECT_TRUE(bubble_content.custom_link_enabled);
   EXPECT_FALSE(bubble_content.manage_link.empty());
@@ -115,9 +113,14 @@
   EXPECT_FALSE(bubble_content_2.title.empty());
   EXPECT_NE(title, bubble_content_2.title);
   ASSERT_EQ(2U, bubble_content_2.radio_group.radio_items.size());
-  // TODO(bauerb): Update this once the strings have been updated.
-  EXPECT_EQ(radio1, bubble_content_2.radio_group.radio_items[0]);
-  EXPECT_EQ(radio2, bubble_content_2.radio_group.radio_items[1]);
+  EXPECT_EQ(bubble_content_2.radio_group.radio_items[0],
+            l10n_util::GetStringUTF8(IDS_ALLOWED_COOKIES_NO_ACTION));
+  EXPECT_EQ(bubble_content_2.radio_group.radio_items[1],
+            l10n_util::GetStringFUTF8(
+                IDS_ALLOWED_COOKIES_BLOCK,
+                FormatUrlForSecurityDisplay(web_contents()->GetURL(),
+                                            profile()->GetPrefs()->GetString(
+                                                prefs::kAcceptLanguages))));
   EXPECT_FALSE(bubble_content_2.custom_link.empty());
   EXPECT_TRUE(bubble_content_2.custom_link_enabled);
   EXPECT_FALSE(bubble_content_2.manage_link.empty());
diff --git a/chrome/browser/ui/extensions/bookmark_app_browser_controller.h b/chrome/browser/ui/extensions/bookmark_app_browser_controller.h
deleted file mode 100644
index e47aaf39..0000000
--- a/chrome/browser/ui/extensions/bookmark_app_browser_controller.h
+++ /dev/null
@@ -1,51 +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_UI_EXTENSIONS_BOOKMARK_APP_BROWSER_CONTROLLER_H_
-#define CHROME_BROWSER_UI_EXTENSIONS_BOOKMARK_APP_BROWSER_CONTROLLER_H_
-
-#include <string>
-
-#include "base/macros.h"
-
-class Browser;
-class Profile;
-
-namespace extensions {
-
-// Class to encapsulate logic to control the browser UI for bookmark apps.
-class BookmarkAppBrowserController {
- public:
-  // Indicates whether |browser| is a bookmark app browser.
-  static bool IsForBookmarkApp(Browser* browser);
-
-  explicit BookmarkAppBrowserController(Browser* browser);
-  ~BookmarkAppBrowserController();
-
-  // Whether the browser being controlled can ever show the location bar.
-  bool SupportsLocationBar();
-
-  // Whether the browser being controlled should be currently showing the
-  // location bar.
-  bool ShouldShowLocationBar();
-
-  // Updates the location bar visibility based on whether it should be
-  // currently visible or not. If |animate| is set, the change will be
-  // animated.
-  void UpdateLocationBarVisibility(bool animate);
-
-  // Whether the controlled browser should use the web app style frame.
-  bool should_use_web_app_frame() { return should_use_web_app_frame_; }
-
- private:
-  Browser* browser_;
-  const std::string extension_id_;
-  const bool should_use_web_app_frame_;
-
-  DISALLOW_COPY_AND_ASSIGN(BookmarkAppBrowserController);
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_UI_EXTENSIONS_BOOKMARK_APP_BROWSER_CONTROLLER_H_
diff --git a/chrome/browser/ui/extensions/bookmark_app_browser_controller.cc b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
similarity index 73%
rename from chrome/browser/ui/extensions/bookmark_app_browser_controller.cc
rename to chrome/browser/ui/extensions/hosted_app_browser_controller.cc
index 773250a1..7a3a930 100644
--- a/chrome/browser/ui/extensions/bookmark_app_browser_controller.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.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 "chrome/browser/ui/extensions/bookmark_app_browser_controller.h"
+#include "chrome/browser/ui/extensions/hosted_app_browser_controller.h"
 
 #include "base/command_line.h"
 #include "chrome/browser/profiles/profile.h"
@@ -18,6 +18,7 @@
 #include "content/public/browser/web_contents.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
+#include "net/base/net_util.h"
 #include "url/gurl.h"
 
 namespace extensions {
@@ -25,9 +26,11 @@
 namespace {
 
 bool IsSameOriginOrMoreSecure(const GURL& app_url, const GURL& page_url) {
+  const std::string www("www.");
   return (app_url.scheme() == page_url.scheme() ||
           page_url.scheme() == url::kHttpsScheme) &&
-         app_url.host() == page_url.host() &&
+         (app_url.host() == page_url.host() ||
+          www + app_url.host() == page_url.host()) &&
          app_url.port() == page_url.port();
 }
 
@@ -39,32 +42,37 @@
 }  // namespace
 
 // static
-bool BookmarkAppBrowserController::IsForBookmarkApp(Browser* browser) {
+bool HostedAppBrowserController::IsForHostedApp(Browser* browser) {
   const std::string extension_id =
       web_app::GetExtensionIdFromApplicationName(browser->app_name());
   const Extension* extension =
       ExtensionRegistry::Get(browser->profile())->GetExtensionById(
           extension_id, ExtensionRegistry::EVERYTHING);
-  return extension && extension->from_bookmark();
+  return extension && extension->is_hosted_app();
 }
 
-BookmarkAppBrowserController::BookmarkAppBrowserController(Browser* browser)
+HostedAppBrowserController::HostedAppBrowserController(Browser* browser)
     : browser_(browser),
       extension_id_(
-          web_app::GetExtensionIdFromApplicationName(browser->app_name())),
-      should_use_web_app_frame_(browser->host_desktop_type() ==
-                                    chrome::HOST_DESKTOP_TYPE_ASH &&
-                                IsWebAppFrameEnabled()) {
+          web_app::GetExtensionIdFromApplicationName(browser->app_name())) {
+  const Extension* extension =
+      ExtensionRegistry::Get(browser->profile())->GetExtensionById(
+          extension_id_, ExtensionRegistry::EVERYTHING);
+  DCHECK(extension);
+  should_use_web_app_frame_ =
+      extension->from_bookmark() &&
+      browser->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH &&
+      IsWebAppFrameEnabled();
 }
 
-BookmarkAppBrowserController::~BookmarkAppBrowserController() {
+HostedAppBrowserController::~HostedAppBrowserController() {
 }
 
-bool BookmarkAppBrowserController::SupportsLocationBar() {
+bool HostedAppBrowserController::SupportsLocationBar() const {
   return !should_use_web_app_frame();
 }
 
-bool BookmarkAppBrowserController::ShouldShowLocationBar() {
+bool HostedAppBrowserController::ShouldShowLocationBar() const {
   const Extension* extension =
       ExtensionRegistry::Get(browser_->profile())->GetExtensionById(
           extension_id_, ExtensionRegistry::EVERYTHING);
@@ -77,7 +85,7 @@
   if (!extension || !web_contents)
     return false;
 
-  if (!extension->from_bookmark())
+  if (!extension->is_hosted_app())
     return false;
 
   // Don't show a location bar until a navigation has occurred.
@@ -96,7 +104,8 @@
                                     web_contents->GetLastCommittedURL()));
 }
 
-void BookmarkAppBrowserController::UpdateLocationBarVisibility(bool animate) {
+void HostedAppBrowserController::UpdateLocationBarVisibility(
+    bool animate) const {
   if (!SupportsLocationBar())
     return;
 
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.h b/chrome/browser/ui/extensions/hosted_app_browser_controller.h
new file mode 100644
index 0000000..09384d07
--- /dev/null
+++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.h
@@ -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.
+
+#ifndef CHROME_BROWSER_UI_EXTENSIONS_HOSTED_APP_BROWSER_CONTROLLER_H_
+#define CHROME_BROWSER_UI_EXTENSIONS_HOSTED_APP_BROWSER_CONTROLLER_H_
+
+#include <string>
+
+#include "base/macros.h"
+
+class Browser;
+class Profile;
+
+namespace extensions {
+
+// Class to encapsulate logic to control the browser UI for hosted apps.
+class HostedAppBrowserController {
+ public:
+  // Indicates whether |browser| is a hosted app browser.
+  static bool IsForHostedApp(Browser* browser);
+
+  explicit HostedAppBrowserController(Browser* browser);
+  ~HostedAppBrowserController();
+
+  // Whether the browser being controlled can ever show the location bar.
+  bool SupportsLocationBar() const;
+
+  // Whether the browser being controlled should be currently showing the
+  // location bar.
+  bool ShouldShowLocationBar() const;
+
+  // Updates the location bar visibility based on whether it should be
+  // currently visible or not. If |animate| is set, the change will be
+  // animated.
+  void UpdateLocationBarVisibility(bool animate) const;
+
+  // Whether the controlled browser should use the web app style frame.
+  bool should_use_web_app_frame() const { return should_use_web_app_frame_; }
+
+ private:
+  Browser* browser_;
+  const std::string extension_id_;
+  bool should_use_web_app_frame_;
+
+  DISALLOW_COPY_AND_ASSIGN(HostedAppBrowserController);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_UI_EXTENSIONS_HOSTED_APP_BROWSER_CONTROLLER_H_
diff --git a/chrome/browser/ui/extensions/bookmark_app_browsertest.cc b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
similarity index 60%
rename from chrome/browser/ui/extensions/bookmark_app_browsertest.cc
rename to chrome/browser/ui/extensions/hosted_app_browsertest.cc
index 186029b..fa96455 100644
--- a/chrome/browser/ui/extensions/bookmark_app_browsertest.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browsertest.cc
@@ -14,7 +14,7 @@
 #include "chrome/browser/ui/browser_iterator.h"
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
-#include "chrome/browser/ui/extensions/bookmark_app_browser_controller.h"
+#include "chrome/browser/ui/extensions/hosted_app_browser_controller.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/common/chrome_switches.h"
@@ -28,8 +28,6 @@
 using content::WebContents;
 using extensions::Extension;
 
-typedef ExtensionBrowserTest BookmarkAppTest;
-
 namespace {
 
 // Used by ShouldLocationBarForXXX. Performs a navigation and then checks that
@@ -40,141 +38,174 @@
   GURL url(url_string);
   ui_test_utils::NavigateToURL(browser, url);
   EXPECT_EQ(expected_visibility,
-      browser->bookmark_app_controller()->ShouldShowLocationBar());
+      browser->hosted_app_controller()->ShouldShowLocationBar());
 }
 
 }  // namespace
 
+class HostedAppTest : public ExtensionBrowserTest {
+ public:
+  HostedAppTest() : app_browser_(nullptr) {}
+  ~HostedAppTest() override {}
+
+ protected:
+  void SetupApp(const std::string& app_folder, bool is_bookmark_app) {
+    const Extension* app = InstallExtensionWithSourceAndFlags(
+        test_data_dir_.AppendASCII(app_folder), 1,
+        extensions::Manifest::INTERNAL,
+        is_bookmark_app ? extensions::Extension::FROM_BOOKMARK
+                        : extensions::Extension::NO_FLAGS);
+    ASSERT_TRUE(app);
+
+    // Launch it in a window.
+    ASSERT_TRUE(OpenApplication(AppLaunchParams(
+        browser()->profile(), app, extensions::LAUNCH_CONTAINER_WINDOW,
+        NEW_WINDOW, extensions::SOURCE_TEST)));
+
+    for (chrome::BrowserIterator it; !it.done(); it.Next()) {
+      if (*it == browser())
+        continue;
+
+      std::string browser_app_id =
+          web_app::GetExtensionIdFromApplicationName((*it)->app_name());
+      if (browser_app_id == app->id()) {
+        app_browser_ = *it;
+        break;
+      }
+    }
+
+    ASSERT_TRUE(app_browser_);
+    ASSERT_TRUE(app_browser_ != browser());
+  }
+
+  Browser* app_browser_;
+};
+
 // Check that the location bar is shown correctly for HTTP bookmark apps.
-IN_PROC_BROWSER_TEST_F(BookmarkAppTest,
+IN_PROC_BROWSER_TEST_F(HostedAppTest,
                        ShouldShowLocationBarForHTTPBookmarkApp) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableNewBookmarkApps);
-  ASSERT_TRUE(test_server()->Start());
 
-  // Load a http bookmark app.
-  const Extension* http_bookmark_app = InstallExtensionWithSourceAndFlags(
-      test_data_dir_.AppendASCII("app/"),
-      1,
-      extensions::Manifest::INTERNAL,
-      extensions::Extension::FROM_BOOKMARK);
-  ASSERT_TRUE(http_bookmark_app);
-
-  // Launch it in a window.
-  WebContents* app_window = OpenApplication(AppLaunchParams(
-      browser()->profile(), http_bookmark_app,
-      extensions::LAUNCH_CONTAINER_WINDOW, NEW_WINDOW,
-      extensions::SOURCE_TEST));
-  ASSERT_TRUE(app_window);
-
-  // Find the new browser.
-  Browser* http_app_browser = NULL;
-  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
-    std::string app_id =
-        web_app::GetExtensionIdFromApplicationName((*it)->app_name());
-    if (*it == browser()) {
-      continue;
-    } else if (app_id == http_bookmark_app->id()) {
-      http_app_browser = *it;
-    }
-  }
-  ASSERT_TRUE(http_app_browser);
-  ASSERT_TRUE(http_app_browser != browser());
+  SetupApp("app", true);
 
   // Navigate to the app's launch page; the location bar should be hidden.
   NavigateAndCheckForLocationBar(
-      http_app_browser, "http://www.example.com/empty.html", false);
+      app_browser_, "http://www.example.com/empty.html", false);
 
   // Navigate to another page on the same origin; the location bar should still
   // hidden.
   NavigateAndCheckForLocationBar(
-      http_app_browser, "http://www.example.com/blah", false);
+      app_browser_, "http://www.example.com/blah", false);
 
   // Navigate to the https version of the site; the location bar should
-  // be hidden for both browsers.
+  // be hidden.
   NavigateAndCheckForLocationBar(
-      http_app_browser, "https://www.example.com/blah", false);
+      app_browser_, "https://www.example.com/blah", false);
 
   // Navigate to different origin; the location bar should now be visible.
   NavigateAndCheckForLocationBar(
-      http_app_browser, "http://www.foo.com/blah", true);
+      app_browser_, "http://www.foo.com/blah", true);
 
   // Navigate back to the app's origin; the location bar should now be hidden.
   NavigateAndCheckForLocationBar(
-      http_app_browser, "http://www.example.com/blah", false);
+      app_browser_, "http://www.example.com/blah", false);
 }
 
 // Check that the location bar is shown correctly for HTTPS bookmark apps.
-IN_PROC_BROWSER_TEST_F(BookmarkAppTest,
+IN_PROC_BROWSER_TEST_F(HostedAppTest,
                        ShouldShowLocationBarForHTTPSBookmarkApp) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableNewBookmarkApps);
-  ASSERT_TRUE(test_server()->Start());
 
-  // Load a https bookmark app.
-  const Extension* https_bookmark_app = InstallExtensionWithSourceAndFlags(
-      test_data_dir_.AppendASCII("https_app/"),
-      1,
-      extensions::Manifest::INTERNAL,
-      extensions::Extension::FROM_BOOKMARK);
-  ASSERT_TRUE(https_bookmark_app);
-
-  // Launch it in a window.
-  WebContents* app_window = OpenApplication(AppLaunchParams(
-      browser()->profile(), https_bookmark_app,
-      extensions::LAUNCH_CONTAINER_WINDOW, NEW_WINDOW,
-      extensions::SOURCE_TEST));
-  ASSERT_TRUE(app_window);
-
-  // Find the new browser.
-  Browser* https_app_browser = NULL;
-  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
-    std::string app_id =
-        web_app::GetExtensionIdFromApplicationName((*it)->app_name());
-    if (*it == browser()) {
-      continue;
-    } else if (app_id == https_bookmark_app->id()) {
-      https_app_browser = *it;
-    }
-  }
-  ASSERT_TRUE(https_app_browser);
-  ASSERT_TRUE(https_app_browser != browser());
+  SetupApp("https_app", true);
 
   // Navigate to the app's launch page; the location bar should be hidden.
   NavigateAndCheckForLocationBar(
-      https_app_browser, "https://www.example.com/empty.html", false);
+      app_browser_, "https://www.example.com/empty.html", false);
 
   // Navigate to another page on the same origin; the location bar should still
   // hidden.
   NavigateAndCheckForLocationBar(
-      https_app_browser, "https://www.example.com/blah", false);
+      app_browser_, "https://www.example.com/blah", false);
 
   // Navigate to the http version of the site; the location bar should
   // be visible for the https version as it is now on a less secure version
   // of its host.
   NavigateAndCheckForLocationBar(
-      https_app_browser, "http://www.example.com/blah", true);
+      app_browser_, "http://www.example.com/blah", true);
 
   // Navigate to different origin; the location bar should now be visible.
   NavigateAndCheckForLocationBar(
-      https_app_browser, "http://www.foo.com/blah", true);
+      app_browser_, "http://www.foo.com/blah", true);
 
   // Navigate back to the app's origin; the location bar should now be hidden.
   NavigateAndCheckForLocationBar(
-      https_app_browser, "https://www.example.com/blah", false);
+      app_browser_, "https://www.example.com/blah", false);
+}
+
+// Check that the location bar is shown correctly for normal hosted apps.
+IN_PROC_BROWSER_TEST_F(HostedAppTest,
+                       ShouldShowLocationBarForHostedApp) {
+  SetupApp("app", false);
+
+  // Navigate to the app's launch page; the location bar should be hidden.
+  NavigateAndCheckForLocationBar(
+      app_browser_, "http://www.example.com/empty.html", false);
+
+  // Navigate to another page on the same origin; the location bar should still
+  // hidden.
+  NavigateAndCheckForLocationBar(
+      app_browser_, "http://www.example.com/blah", false);
+
+  // Navigate to the https version of the site; the location bar should
+  // be hidden.
+  NavigateAndCheckForLocationBar(
+      app_browser_, "https://www.example.com/blah", false);
+
+  // Navigate to different origin; the location bar should now be visible.
+  NavigateAndCheckForLocationBar(
+      app_browser_, "http://www.foo.com/blah", true);
+
+  // Navigate back to the app's origin; the location bar should now be hidden.
+  NavigateAndCheckForLocationBar(
+      app_browser_, "http://www.example.com/blah", false);
+}
+
+// Check that the location bar is shown correctly for hosted apps that specify
+// start URLs without the 'www.' prefix.
+IN_PROC_BROWSER_TEST_F(HostedAppTest,
+                       LocationBarForHostedAppWithoutWWW) {
+  SetupApp("app_no_www", false);
+
+  // Navigate to the app's launch page; the location bar should be hidden.
+  NavigateAndCheckForLocationBar(
+      app_browser_, "http://example.com/empty.html", false);
+
+  // Navigate to the app's launch page with the 'www.' prefis; the location bar
+  // should be hidden.
+  NavigateAndCheckForLocationBar(
+      app_browser_, "http://www.example.com/empty.html", false);
+
+  // Navigate to different origin; the location bar should now be visible.
+  NavigateAndCheckForLocationBar(
+      app_browser_, "http://www.foo.com/blah", true);
+
+  // Navigate back to the app's origin; the location bar should now be hidden.
+  NavigateAndCheckForLocationBar(
+      app_browser_, "http://example.com/blah", false);
 }
 
 // Open a normal browser window, a hosted app window, a legacy packaged app
 // window and a dev tools window, and check that the web app frame feature is
 // supported correctly.
-IN_PROC_BROWSER_TEST_F(BookmarkAppTest, ShouldUseWebAppFrame) {
-  ASSERT_TRUE(test_server()->Start());
+IN_PROC_BROWSER_TEST_F(HostedAppTest, ShouldUseWebAppFrame) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kEnableWebAppFrame);
 
   // Load a hosted app.
    const Extension* bookmark_app = InstallExtensionWithSourceAndFlags(
-      test_data_dir_.AppendASCII("app/"),
+      test_data_dir_.AppendASCII("app"),
       1,
       extensions::Manifest::INTERNAL,
       extensions::Extension::FROM_BOOKMARK);
@@ -187,7 +218,7 @@
   ASSERT_TRUE(bookmark_app_window);
 
   //  Load a packaged app.
-  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("packaged_app/")));
+  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("packaged_app")));
   const Extension* packaged_app = nullptr;
   extensions::ExtensionRegistry* registry =
       extensions::ExtensionRegistry::Get(browser()->profile());
@@ -212,9 +243,9 @@
                                         browser()->host_desktop_type()));
 
   // Find the new browsers.
-  Browser* bookmark_app_browser = NULL;
-  Browser* packaged_app_browser = NULL;
-  Browser* dev_tools_browser = NULL;
+  Browser* bookmark_app_browser = nullptr;
+  Browser* packaged_app_browser = nullptr;
+  Browser* dev_tools_browser = nullptr;
   for (chrome::BrowserIterator it; !it.done(); it.Next()) {
     if (*it == browser()) {
       continue;
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
index 101db29..8f05ef9 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller.cc
@@ -36,6 +36,9 @@
 
 namespace {
 
+// Minimal time span the bubble should survive implicit navigations.
+const int kBubbleMinTime = 5;
+
 password_manager::PasswordStore* GetPasswordStore(
     content::WebContents* web_contents) {
   return PasswordStoreFactory::GetForProfile(
@@ -298,7 +301,7 @@
 
   // Don't do anything if a navigation occurs before a user could reasonably
   // interact with the password bubble.
-  if (Elapsed() < base::TimeDelta::FromSeconds(1))
+  if (Elapsed() < base::TimeDelta::FromSeconds(kBubbleMinTime))
     return;
 
   // Otherwise, reset the password manager and the timer.
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
index 491f9ec1..b5c3cec7 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
@@ -30,7 +30,7 @@
 
 namespace {
 
-const int64 kSlowNavigationDelayInMS = 2000;
+const int64 kSlowNavigationDelayInMS = 6000;
 const int64 kQuickNavigationDelayInMS = 500;
 
 // This sublass is used to disable some code paths which are not essential for
diff --git a/chrome/browser/ui/sad_tab.cc b/chrome/browser/ui/sad_tab.cc
index 3881455..5f17784 100644
--- a/chrome/browser/ui/sad_tab.cc
+++ b/chrome/browser/ui/sad_tab.cc
@@ -10,6 +10,9 @@
 bool SadTab::ShouldShow(base::TerminationStatus status) {
   return (status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION ||
           status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED ||
+#if defined(OS_CHROMEOS)
+          status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM ||
+#endif
           status == base::TERMINATION_STATUS_PROCESS_CRASHED);
 }
 
diff --git a/chrome/browser/ui/sad_tab_helper.cc b/chrome/browser/ui/sad_tab_helper.cc
index ab8a6e03..f590396 100644
--- a/chrome/browser/ui/sad_tab_helper.cc
+++ b/chrome/browser/ui/sad_tab_helper.cc
@@ -11,6 +11,24 @@
 
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SadTabHelper);
 
+namespace {
+
+chrome::SadTabKind SadTabKindFromTerminationStatus(
+    base::TerminationStatus status) {
+  switch (status) {
+#if defined(OS_CHROMEOS)
+    case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
+      return chrome::SAD_TAB_KIND_KILLED_BY_OOM;
+#endif
+    case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
+      return chrome::SAD_TAB_KIND_KILLED;
+    default:
+      return chrome::SAD_TAB_KIND_CRASHED;
+  }
+}
+
+}  // namespace
+
 SadTabHelper::~SadTabHelper() {
 }
 
@@ -40,9 +58,7 @@
 }
 
 void SadTabHelper::InstallSadTab(base::TerminationStatus status) {
-  chrome::SadTabKind kind =
-      (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) ?
-          chrome::SAD_TAB_KIND_KILLED : chrome::SAD_TAB_KIND_CRASHED;
-  sad_tab_.reset(chrome::SadTab::Create(web_contents(), kind));
+  sad_tab_.reset(chrome::SadTab::Create(
+      web_contents(), SadTabKindFromTerminationStatus(status)));
   sad_tab_->Show();
 }
diff --git a/chrome/browser/ui/sad_tab_types.h b/chrome/browser/ui/sad_tab_types.h
index d3ecde96..94cc6c29 100644
--- a/chrome/browser/ui/sad_tab_types.h
+++ b/chrome/browser/ui/sad_tab_types.h
@@ -7,10 +7,11 @@
 
 namespace chrome {
 
-// NOTE: Do not remove or reorder the elements in this enum, and only add new
-// items at the end. We depend on these specific values in a histogram.
 enum SadTabKind {
-  SAD_TAB_KIND_CRASHED = 0,  // Tab crashed. Display the "Aw, Snap!" page.
+  SAD_TAB_KIND_CRASHED,  // Tab crashed. Display the "Aw, Snap!" page.
+#if defined(OS_CHROMEOS)
+  SAD_TAB_KIND_KILLED_BY_OOM,  // Tab killed by oom killer.
+#endif
   SAD_TAB_KIND_KILLED  // Tab killed. Display the "He's dead, Jim!" tab page.
 };
 
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index 6bc2d07..7d27f47 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -52,6 +52,7 @@
 #include "chrome/browser/ui/android/context_menu_helper.h"
 #include "chrome/browser/ui/android/window_android_helper.h"
 #else
+#include "chrome/browser/banners/app_banner_manager_desktop.h"
 #include "chrome/browser/plugins/plugin_observer.h"
 #include "chrome/browser/safe_browsing/safe_browsing_tab_observer.h"
 #include "chrome/browser/thumbnails/thumbnail_tab_helper.h"
@@ -195,6 +196,11 @@
   TabDialogs::CreateForWebContents(web_contents);
   ThumbnailTabHelper::CreateForWebContents(web_contents);
   web_modal::WebContentsModalDialogManager::CreateForWebContents(web_contents);
+
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableAddToShelf)) {
+    banners::AppBannerManagerDesktop::CreateForWebContents(web_contents);
+  }
 #endif
 
 #if defined(OS_WIN)
diff --git a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
index 67e4e8061..4824b5a2 100644
--- a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
+++ b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
@@ -496,15 +496,9 @@
             browser_actions_bar()->GetExtensionId(1));
 }
 
-// http://crbug.com/495678
-#if defined(OS_MACOSX)
-#define MAYBE_PageActionPopupsTest DISABLED_PageActionPopupsTest
-#else
-#define MAYBE_PageActionPopupsTest PageActionPopupsTest
-#endif
 // Test that page action popups work with the toolbar redesign.
 IN_PROC_BROWSER_TEST_F(BrowserActionsBarRedesignBrowserTest,
-                       MAYBE_PageActionPopupsTest) {
+                       PageActionPopupsTest) {
   ExtensionTestMessageListener listener("ready", false);
   const extensions::Extension* page_action_extension =
       LoadExtension(test_data_dir_.AppendASCII("trigger_actions").
@@ -517,4 +511,8 @@
   browser_actions_bar()->Press(0);
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(browser_actions_bar()->HasPopup());
+  // Cleanup the popup (to avoid having windows open at tear down).
+  browser_actions_bar()->HidePopup();
+  content::RunAllBlockingPoolTasksUntilIdle();
+  EXPECT_FALSE(browser_actions_bar()->HasPopup());
 }
diff --git a/chrome/browser/ui/toolbar/media_router_action.cc b/chrome/browser/ui/toolbar/media_router_action.cc
index 6895711..0f39f11 100644
--- a/chrome/browser/ui/toolbar/media_router_action.cc
+++ b/chrome/browser/ui/toolbar/media_router_action.cc
@@ -6,12 +6,15 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/toolbar/toolbar_action_view_delegate.h"
+#include "chrome/browser/ui/webui/media_router/media_router_dialog_controller.h"
 #include "chrome/grit/generated_resources.h"
 #include "grit/theme_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image_skia.h"
 
+using media_router::MediaRouterDialogController;
+
 MediaRouterAction::MediaRouterAction()
     : id_("media_router_action"),
       name_(l10n_util::GetStringUTF16(IDS_MEDIA_ROUTER_TITLE)),
@@ -63,40 +66,43 @@
 
 bool MediaRouterAction::WantsToRun(
     content::WebContents* web_contents) const {
-  NOTIMPLEMENTED();
   return false;
 }
 
 bool MediaRouterAction::HasPopup(
     content::WebContents* web_contents) const {
-  NOTIMPLEMENTED();
   return true;
 }
 
 void MediaRouterAction::HidePopup() {
-  NOTIMPLEMENTED();
+  GetMediaRouterDialogController()->CloseMediaRouterDialog();
 }
 
 gfx::NativeView MediaRouterAction::GetPopupNativeView() {
-  NOTIMPLEMENTED();
   return nullptr;
 }
 
 ui::MenuModel* MediaRouterAction::GetContextMenu() {
-  NOTIMPLEMENTED();
   return nullptr;
 }
 
 bool MediaRouterAction::CanDrag() const {
-  NOTIMPLEMENTED();
   return false;
 }
 
 bool MediaRouterAction::ExecuteAction(bool by_user) {
-  NOTIMPLEMENTED();
-  return false;
+  GetMediaRouterDialogController()->ShowMediaRouterDialog();
+  return true;
 }
 
 void MediaRouterAction::UpdateState() {
   NOTIMPLEMENTED();
 }
+
+MediaRouterDialogController*
+MediaRouterAction::GetMediaRouterDialogController() {
+  DCHECK(delegate_);
+  content::WebContents* web_contents = delegate_->GetCurrentWebContents();
+  DCHECK(web_contents);
+  return MediaRouterDialogController::GetOrCreateForWebContents(web_contents);
+}
diff --git a/chrome/browser/ui/toolbar/media_router_action.h b/chrome/browser/ui/toolbar/media_router_action.h
index da2bc24..70e2164 100644
--- a/chrome/browser/ui/toolbar/media_router_action.h
+++ b/chrome/browser/ui/toolbar/media_router_action.h
@@ -7,6 +7,10 @@
 
 #include "chrome/browser/ui/toolbar/toolbar_action_view_controller.h"
 
+namespace media_router {
+class MediaRouterDialogController;
+}  // namespace media_router
+
 // The class for the Media Router component action that will be shown in
 // the toolbar.
 class MediaRouterAction : public ToolbarActionViewController {
@@ -35,6 +39,11 @@
   void UpdateState() override;
 
  private:
+  // Returns a reference to the MediaRouterDialogController associated with
+  // |delegate_|'s current WebContents. Guaranteed to be non-null.
+  // |delegate_| and its current WebContents must not be null.
+  media_router::MediaRouterDialogController* GetMediaRouterDialogController();
+
   const std::string id_;
   const base::string16 name_;
 
diff --git a/chrome/browser/ui/views/extensions/bookmark_app_bubble_view.cc b/chrome/browser/ui/views/extensions/bookmark_app_bubble_view.cc
index 46f8d15f3..0b3fede 100644
--- a/chrome/browser/ui/views/extensions/bookmark_app_bubble_view.cc
+++ b/chrome/browser/ui/views/extensions/bookmark_app_bubble_view.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/extensions/bookmark_app_bubble_view.h"
 
+#include "base/numerics/safe_conversions.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -15,7 +16,6 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/gfx/geometry/safe_integer_conversions.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_source.h"
 #include "ui/views/controls/button/checkbox.h"
@@ -47,7 +47,7 @@
 
  private:
   gfx::ImageSkiaRep GetImageForScale(float scale) override {
-    int size = gfx::ClampToInt(dip_size_ * scale);
+    int size = base::saturated_cast<int>(dip_size_ * scale);
     for (const auto& icon_info : info_.icons) {
       if (icon_info.width == size) {
         return gfx::ImageSkiaRep(icon_info.data, scale);
diff --git a/chrome/browser/ui/views/extensions/extension_popup_aura.cc b/chrome/browser/ui/views/extensions/extension_popup_aura.cc
index e3e7c90..7901f3f 100644
--- a/chrome/browser/ui/views/extensions/extension_popup_aura.cc
+++ b/chrome/browser/ui/views/extensions/extension_popup_aura.cc
@@ -53,8 +53,10 @@
   }
 }
 
-void ExtensionPopupAura::OnWindowActivated(aura::Window* gained_active,
-                                           aura::Window* lost_active) {
+void ExtensionPopupAura::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
   // Close on anchor window activation (ie. user clicked the browser window).
   // DesktopNativeWidgetAura does not trigger the expected browser widget
   // [de]activation events when activating widgets in its own root window.
diff --git a/chrome/browser/ui/views/extensions/extension_popup_aura.h b/chrome/browser/ui/views/extensions/extension_popup_aura.h
index d9b0dbf8..d9b8e50 100644
--- a/chrome/browser/ui/views/extensions/extension_popup_aura.h
+++ b/chrome/browser/ui/views/extensions/extension_popup_aura.h
@@ -21,8 +21,10 @@
   void OnWidgetDestroying(views::Widget* widget) override;
 
   // aura::client::ActivationChangeObserver overrides.
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ExtensionPopupAura);
diff --git a/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc b/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc
new file mode 100644
index 0000000..249042b
--- /dev/null
+++ b/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc
@@ -0,0 +1,89 @@
+// 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/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/toolbar/media_router_action.h"
+#include "chrome/browser/ui/toolbar/toolbar_action_view_delegate.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
+#include "chrome/browser/ui/views/toolbar/toolbar_action_view.h"
+#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/test_navigation_observer.h"
+#include "content/public/test/test_utils.h"
+
+namespace media_router {
+
+class MediaRouterUIBrowserTest : public InProcessBrowserTest {
+ public:
+  MediaRouterUIBrowserTest() {}
+  ~MediaRouterUIBrowserTest() override {}
+
+  void SetUpOnMainThread() override {
+    InProcessBrowserTest::SetUpOnMainThread();
+
+    BrowserActionsContainer* browser_actions_container =
+        BrowserView::GetBrowserViewForBrowser(browser())
+            ->toolbar()
+            ->browser_actions();
+    ASSERT_TRUE(browser_actions_container);
+
+    media_router_action_.reset(new MediaRouterAction);
+
+    // Sets delegate on |media_router_action_|.
+    toolbar_action_view_.reset(
+        new ToolbarActionView(media_router_action_.get(), browser()->profile(),
+                              browser_actions_container));
+  }
+
+  void OpenMediaRouterDialogAndWaitForNewWebContents() {
+    content::TestNavigationObserver nav_observer(NULL);
+    nav_observer.StartWatchingNewWebContents();
+    media_router_action_->ExecuteAction(true);
+    nav_observer.Wait();
+    nav_observer.StopWatchingNewWebContents();
+  }
+
+ protected:
+  // Must be initialized after |InProcessBrowserTest::SetUpOnMainThread|.
+  scoped_ptr<MediaRouterAction> media_router_action_;
+
+  // ToolbarActionView constructed to set the delegate on |mr_action|.
+  scoped_ptr<ToolbarActionView> toolbar_action_view_;
+};
+
+IN_PROC_BROWSER_TEST_F(MediaRouterUIBrowserTest,
+                       OpenDialogWithMediaRouterAction) {
+  // We start off at about:blank page.
+  // Make sure there is 1 tab and media router is enabled.
+  ASSERT_EQ(1, browser()->tab_strip_model()->count());
+
+  OpenMediaRouterDialogAndWaitForNewWebContents();
+
+  // Reload the browser and wait.
+  content::TestNavigationObserver reload_observer(
+      browser()->tab_strip_model()->GetActiveWebContents());
+  chrome::Reload(browser(), CURRENT_TAB);
+  reload_observer.Wait();
+
+  // The reload should have removed the previously created dialog.
+  // We expect a new dialog WebContents to be created by calling this.
+  OpenMediaRouterDialogAndWaitForNewWebContents();
+
+  // Navigate away and wait.
+  content::TestNavigationObserver nav_observer(
+      browser()->tab_strip_model()->GetActiveWebContents(), 1);
+  ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
+  nav_observer.Wait();
+
+  // The navigation should have removed the previously created dialog.
+  // We expect a new dialog WebContents to be created by calling this.
+  OpenMediaRouterDialogAndWaitForNewWebContents();
+}
+
+}  // namespace media_router
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.cc b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
index 14c9241..1606b2f 100644
--- a/chrome/browser/ui/views/profiles/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
@@ -872,6 +872,7 @@
     tutorial_mode_ = profiles::TUTORIAL_MODE_NONE;
     ProfileMetrics::LogProfileNewAvatarMenuSignin(
         ProfileMetrics::PROFILE_AVATAR_MENU_SIGNIN_SETTINGS);
+    Hide();
   } else if (sender == tutorial_not_you_link_) {
     ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
         ProfileMetrics::PROFILE_AVATAR_MENU_UPGRADE_NOT_YOU);
diff --git a/chrome/browser/ui/views/sad_tab_view.cc b/chrome/browser/ui/views/sad_tab_view.cc
index 508d7a90..d8e6c69 100644
--- a/chrome/browser/ui/views/sad_tab_view.cc
+++ b/chrome/browser/ui/views/sad_tab_view.cc
@@ -42,6 +42,36 @@
 const int kMinColumnWidth = 120;
 const char kCategoryTagCrash[] = "Crash";
 
+void RecordKillCreated() {
+  static int killed = 0;
+  killed++;
+  UMA_HISTOGRAM_CUSTOM_COUNTS(
+      "Tabs.SadTab.KillCreated", killed, 1, 1000, 50);
+}
+
+void RecordKillDisplayed() {
+  static int killed = 0;
+  killed++;
+  UMA_HISTOGRAM_CUSTOM_COUNTS(
+      "Tabs.SadTab.KillDisplayed", killed, 1, 1000, 50);
+}
+
+#if defined(OS_CHROMEOS)
+void RecordKillCreatedOOM() {
+  static int oom_killed = 0;
+  oom_killed++;
+  UMA_HISTOGRAM_CUSTOM_COUNTS(
+      "Tabs.SadTab.KillCreated.OOM", oom_killed, 1, 1000, 50);
+}
+
+void RecordKillDisplayedOOM() {
+  static int oom_killed = 0;
+  oom_killed++;
+  UMA_HISTOGRAM_CUSTOM_COUNTS(
+      "Tabs.SadTab.KillDisplayed.OOM", oom_killed, 1, 1000, 50);
+}
+#endif
+
 }  // namespace
 
 SadTabView::SadTabView(WebContents* web_contents, chrome::SadTabKind kind)
@@ -56,12 +86,6 @@
       help_message_(nullptr) {
   DCHECK(web_contents);
 
-  // Sometimes the user will never see this tab, so keep track of the total
-  // number of creation events to compare to display events.
-  // TODO(jamescook): Remove this after R20 stable.  Keep it for now so we can
-  // compare R20 to earlier versions.
-  UMA_HISTOGRAM_COUNTS("SadTab.Created", kind_);
-
   // These stats should use the same counting approach and bucket size used for
   // tab discard events in chromeos::OomPriorityManager so they can be
   // directly compared.
@@ -74,13 +98,15 @@
           "Tabs.SadTab.CrashCreated", crashed, 1, 1000, 50);
       break;
     }
-    case chrome::SAD_TAB_KIND_KILLED: {
-      static int killed = 0;
-      killed++;
-      UMA_HISTOGRAM_CUSTOM_COUNTS(
-          "Tabs.SadTab.KillCreated", killed, 1, 1000, 50);
+    case chrome::SAD_TAB_KIND_KILLED:
+      RecordKillCreated();
       break;
-    }
+#if defined(OS_CHROMEOS)
+    case chrome::SAD_TAB_KIND_KILLED_BY_OOM:
+      RecordKillCreated();
+      RecordKillCreatedOOM();
+      break;
+#endif
     default:
       NOTREACHED();
   }
@@ -252,11 +278,6 @@
 
 void SadTabView::OnPaint(gfx::Canvas* canvas) {
   if (!painted_) {
-    // User actually saw the error, keep track for user experience stats.
-    // TODO(jamescook): Remove this after R20 stable.  Keep it for now so we can
-    // compare R20 to earlier versions.
-    UMA_HISTOGRAM_COUNTS("SadTab.Displayed", kind_);
-
     // These stats should use the same counting approach and bucket size used
     // for tab discard events in chromeos::OomPriorityManager so they
     // can be directly compared.
@@ -267,14 +288,15 @@
             "Tabs.SadTab.CrashDisplayed", ++crashed, 1, 1000, 50);
         break;
       }
-      case chrome::SAD_TAB_KIND_KILLED: {
-        static int killed = 0;
-        UMA_HISTOGRAM_CUSTOM_COUNTS(
-            "Tabs.SadTab.KillDisplayed", ++killed, 1, 1000, 50);
+      case chrome::SAD_TAB_KIND_KILLED:
+        RecordKillDisplayed();
         break;
-      }
-      default:
-        NOTREACHED();
+#if defined(OS_CHROMEOS)
+      case chrome::SAD_TAB_KIND_KILLED_BY_OOM:
+        RecordKillDisplayed();
+        RecordKillDisplayedOOM();
+        break;
+#endif
     }
     painted_ = true;
   }
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index bea6af3..089c569d 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -507,8 +507,12 @@
       // selected (i.e. in the foreground) -- we won't reload these
       // automatically since we don't want to get into a crash loop.
       if (IsSelected() ||
-          data_.crashed_status != base::TERMINATION_STATUS_PROCESS_WAS_KILLED)
+          (data_.crashed_status
+           != base::TERMINATION_STATUS_PROCESS_WAS_KILLED &&
+           data_.crashed_status
+           != base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM)) {
         StartCrashAnimation();
+      }
 #else
       StartCrashAnimation();
 #endif
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 53e78b4..e604c7c 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -71,12 +71,18 @@
 // Delay for moving tabs after the initial delay has passed.
 const int kMoveAttachedSubsequentDelay = 300;
 
-const int kHorizontalMoveThreshold = 16;  // Pixels.
+const int kHorizontalMoveThreshold = 16;  // DIPs.
 
 // Distance from the next/previous stacked before before we consider the tab
 // close enough to trigger moving.
 const int kStackedDistance = 36;
 
+// A dragged window is forced to be a bit smaller than maximized bounds during a
+// drag. This prevents the dragged browser widget from getting maximized at
+// creation and makes it easier to drag tabs out of a restored window that had
+// maximized size.
+const int kMaximizedWindowInset = 10;  // DIPs.
+
 #if defined(USE_ASH)
 void SetWindowPositionManaged(gfx::NativeWindow window, bool value) {
   ash::wm::GetWindowState(window)->set_window_position_managed(value);
@@ -1640,6 +1646,20 @@
   gfx::Point center(0, source->height() / 2);
   views::View::ConvertPointToWidget(source, &center);
   gfx::Rect new_bounds(source->GetWidget()->GetRestoredBounds());
+
+  gfx::Rect work_area =
+      screen_->GetDisplayNearestPoint(last_point_in_screen_).work_area();
+  if (new_bounds.size().width() >= work_area.size().width() &&
+      new_bounds.size().height() >= work_area.size().height()) {
+    new_bounds = work_area;
+    new_bounds.Inset(kMaximizedWindowInset, kMaximizedWindowInset,
+                     kMaximizedWindowInset, kMaximizedWindowInset);
+    // Behave as if the |source| was maximized at the start of a drag since this
+    // is consistent with a browser window creation logic in case of windows
+    // that are as large as the |work_area|.
+    was_source_maximized_ = true;
+  }
+
   if (source->GetWidget()->IsMaximized()) {
     // If the restore bounds is really small, we don't want to honor it
     // (dragging a really small window looks wrong), instead make sure the new
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index f69b34c..2790730d 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -795,6 +795,74 @@
 #if defined(OS_CHROMEOS) || defined(OS_LINUX)
 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
 // compositor. crbug.com/331924
+#define MAYBE_DetachFromFullsizeWindow DISABLED_DetachFromFullsizeWindow
+#else
+#define MAYBE_DetachFromFullsizeWindow DetachFromFullsizeWindow
+#endif
+// Tests that a tab can be dragged from a browser window that is resized to full
+// screen.
+IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
+                       MAYBE_DetachFromFullsizeWindow) {
+  // Resize the browser window so that it is as big as the work area.
+  gfx::Rect work_area =
+      gfx::Screen::GetNativeScreen()
+          ->GetDisplayNearestWindow(browser()->window()->GetNativeWindow())
+          .work_area();
+  browser()->window()->SetBounds(work_area);
+  const gfx::Rect initial_bounds(browser()->window()->GetBounds());
+  // Add another tab.
+  AddTabAndResetBrowser(browser());
+  TabStrip* tab_strip = GetTabStripForBrowser(browser());
+
+  // Move to the first tab and drag it enough so that it detaches.
+  gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
+  ASSERT_TRUE(PressInput(tab_0_center));
+  ASSERT_TRUE(DragInputToNotifyWhenDone(
+      tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
+      base::Bind(&DetachToOwnWindowStep2, this)));
+  if (input_source() == INPUT_SOURCE_MOUSE) {
+    ASSERT_TRUE(ReleaseMouseAsync());
+    QuitWhenNotDragging();
+  }
+
+  // Should no longer be dragging.
+  ASSERT_FALSE(tab_strip->IsDragSessionActive());
+  ASSERT_FALSE(TabDragController::IsActive());
+
+  // There should now be another browser.
+  ASSERT_EQ(2u, native_browser_list->size());
+  Browser* new_browser = native_browser_list->get(1);
+  ASSERT_TRUE(new_browser->window()->IsActive());
+  TabStrip* tab_strip2 = GetTabStripForBrowser(new_browser);
+  ASSERT_FALSE(tab_strip2->IsDragSessionActive());
+
+  EXPECT_EQ("0", IDString(new_browser->tab_strip_model()));
+  EXPECT_EQ("1", IDString(browser()->tab_strip_model()));
+
+  // The bounds of the initial window should not have changed.
+  EXPECT_EQ(initial_bounds.ToString(),
+            browser()->window()->GetBounds().ToString());
+
+  EXPECT_FALSE(GetIsDragged(browser()));
+  EXPECT_FALSE(GetIsDragged(new_browser));
+  // After this both windows should still be manageable.
+  EXPECT_TRUE(IsWindowPositionManaged(browser()->window()->GetNativeWindow()));
+  EXPECT_TRUE(
+      IsWindowPositionManaged(new_browser->window()->GetNativeWindow()));
+
+  // Only second window should be maximized.
+  EXPECT_FALSE(browser()->window()->IsMaximized());
+  EXPECT_TRUE(new_browser->window()->IsMaximized());
+
+  // The tab strip should no longer have capture because the drag was ended and
+  // mouse/touch was released.
+  EXPECT_FALSE(tab_strip->GetWidget()->HasCapture());
+  EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
+}
+
+#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+// TODO(sky,sad): Disabled as it fails due to resize locks with a real
+// compositor. crbug.com/331924
 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
   DISABLED_DetachToOwnWindowFromMaximizedWindow
 #else
diff --git a/chrome/browser/ui/views/tabs/tab_renderer_data.cc b/chrome/browser/ui/views/tabs/tab_renderer_data.cc
index 19e6555..83bd52d5 100644
--- a/chrome/browser/ui/views/tabs/tab_renderer_data.cc
+++ b/chrome/browser/ui/views/tabs/tab_renderer_data.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
 
+#include "base/process/kill.h"
+
 TabRendererData::TabRendererData()
     : network_state(NETWORK_STATE_NONE),
       loading(false),
@@ -18,6 +20,16 @@
 
 TabRendererData::~TabRendererData() {}
 
+bool TabRendererData::IsCrashed() const {
+  return (crashed_status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED ||
+#if defined(OS_CHROMEOS)
+          crashed_status ==
+          base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM ||
+#endif
+          crashed_status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
+          crashed_status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION);
+}
+
 bool TabRendererData::Equals(const TabRendererData& data) {
   return
       favicon.BackedBySameObjectAs(data.favicon) &&
diff --git a/chrome/browser/ui/views/tabs/tab_renderer_data.h b/chrome/browser/ui/views/tabs/tab_renderer_data.h
index 6ba2011..e16f61c 100644
--- a/chrome/browser/ui/views/tabs/tab_renderer_data.h
+++ b/chrome/browser/ui/views/tabs/tab_renderer_data.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_RENDERER_DATA_H_
 #define CHROME_BROWSER_UI_VIEWS_TABS_TAB_RENDERER_DATA_H_
 
-#include "base/process/kill.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/ui/tabs/tab_utils.h"
 #include "chrome/browser/ui/views/chrome_views_export.h"
@@ -29,11 +28,7 @@
   // This interprets the crashed status to decide whether or not this
   // render data represents a tab that is "crashed" (i.e. the render
   // process died unexpectedly).
-  bool IsCrashed() const {
-    return (crashed_status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED ||
-            crashed_status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
-            crashed_status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION);
-  }
+  bool IsCrashed() const;
 
   // Returns true if the TabRendererData is same as given |data|.
   bool Equals(const TabRendererData& data);
diff --git a/chrome/browser/ui/website_settings/permission_bubble_manager.cc b/chrome/browser/ui/website_settings/permission_bubble_manager.cc
index b8a53e5f..03051d61 100644
--- a/chrome/browser/ui/website_settings/permission_bubble_manager.cc
+++ b/chrome/browser/ui/website_settings/permission_bubble_manager.cc
@@ -78,12 +78,14 @@
 
 PermissionBubbleManager::PermissionBubbleManager(
     content::WebContents* web_contents)
-  : content::WebContentsObserver(web_contents),
-    require_user_gesture_(false),
-    bubble_showing_(false),
-    view_(NULL),
-    request_url_has_loaded_(false),
-    weak_factory_(this) {}
+    : content::WebContentsObserver(web_contents),
+      require_user_gesture_(false),
+      bubble_showing_(false),
+      view_(NULL),
+      request_url_has_loaded_(false),
+      auto_response_for_test_(NONE),
+      weak_factory_(this) {
+}
 
 PermissionBubbleManager::~PermissionBubbleManager() {
   if (view_ != NULL)
@@ -346,6 +348,10 @@
   // case we may do in-line calling of finalization.
   bubble_showing_ = true;
   view_->Show(requests_, accept_states_);
+
+  // If in testing mode, automatically respond to the bubble that was shown.
+  if (auto_response_for_test_ != NONE)
+    DoAutoResponseForTesting();
 }
 
 void PermissionBubbleManager::FinalizeBubble() {
@@ -414,3 +420,18 @@
   return false;
 }
 
+void PermissionBubbleManager::DoAutoResponseForTesting() {
+  switch (auto_response_for_test_) {
+    case ACCEPT_ALL:
+      Accept();
+      break;
+    case DENY_ALL:
+      Deny();
+      break;
+    case DISMISS:
+      Closing();
+      break;
+    case NONE:
+      NOTREACHED();
+  }
+}
diff --git a/chrome/browser/ui/website_settings/permission_bubble_manager.h b/chrome/browser/ui/website_settings/permission_bubble_manager.h
index 1c624b66..72366d3 100644
--- a/chrome/browser/ui/website_settings/permission_bubble_manager.h
+++ b/chrome/browser/ui/website_settings/permission_bubble_manager.h
@@ -30,6 +30,13 @@
       public content::WebContentsUserData<PermissionBubbleManager>,
       public PermissionBubbleView::Delegate {
  public:
+  enum AutoResponseType {
+    NONE,
+    ACCEPT_ALL,
+    DENY_ALL,
+    DISMISS
+  };
+
   // Return the enabled state of permissions bubbles.
   // Controlled by a flag and FieldTrial.
   static bool Enabled();
@@ -64,6 +71,14 @@
   // comes in with a user gesture.
   void RequireUserGesture(bool required);
 
+  // Do NOT use this methods in production code. Use this methods in browser
+  // tests that need to accept or deny permissions when requested in
+  // JavaScript. Your test needs to set this appropriately, and then the bubble
+  // will proceed as desired as soon as Show() is called.
+  void set_auto_response_for_test(AutoResponseType response) {
+    auto_response_for_test_ = response;
+  }
+
  private:
   friend class DownloadRequestLimiterTest;
   friend class GeolocationBrowserTest;
@@ -119,6 +134,8 @@
   bool HasUserGestureRequest(
       const std::vector<PermissionBubbleRequest*>& queue);
 
+  void DoAutoResponseForTesting();
+
   // Whether to delay displaying the bubble until a request with a user gesture.
   // False by default, unless RequireUserGesture(bool) changes the value.
   bool require_user_gesture_;
@@ -140,6 +157,8 @@
 
   std::vector<bool> accept_states_;
 
+  AutoResponseType auto_response_for_test_;
+
   base::WeakPtrFactory<PermissionBubbleManager> weak_factory_;
 };
 
diff --git a/chrome/browser/ui/website_settings/website_settings.cc b/chrome/browser/ui/website_settings/website_settings.cc
index 74c37e9a..d6b51f1 100644
--- a/chrome/browser/ui/website_settings/website_settings.cc
+++ b/chrome/browser/ui/website_settings/website_settings.cc
@@ -200,6 +200,14 @@
 
   // Use a separate histogram to record actions if they are done on a page with
   // an HTTPS URL. Note that this *disregards* security status.
+  //
+
+  // TODO(palmer): Consider adding a new histogram for
+  // GURL::SchemeIsCryptographic. (We don't want to replace this call with a
+  // call to that function because we don't want to change the meanings of
+  // existing metrics.) This would inform the decision to mark non-secure
+  // origins as Dubious or Non-Secure; the overall bug for that is
+  // crbug.com/454579.
   if (site_url_.SchemeIs(url::kHttpsScheme)) {
     UMA_HISTOGRAM_ENUMERATION("WebsiteSettings.Action.HttpsUrl",
                               action,
diff --git a/chrome/browser/ui/webui/chromeos/login/authenticated_user_email_retriever.cc b/chrome/browser/ui/webui/chromeos/login/authenticated_user_email_retriever.cc
index 06dbd6b..3c1ed8b 100644
--- a/chrome/browser/ui/webui/chromeos/login/authenticated_user_email_retriever.cc
+++ b/chrome/browser/ui/webui/chromeos/login/authenticated_user_email_retriever.cc
@@ -29,12 +29,12 @@
 
 void AuthenticatedUserEmailRetriever::OnListAccountsSuccess(
     const std::string& data) {
-  std::vector<std::pair<std::string, bool> > accounts;
+  std::vector<gaia::ListedAccount> accounts;
   gaia::ParseListAccountsData(data, &accounts);
   if (accounts.size() != 1)
     callback_.Run(std::string());
   else
-    callback_.Run(accounts.front().first);
+    callback_.Run(accounts.front().email);
 }
 
 void AuthenticatedUserEmailRetriever::OnListAccountsFailure(
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index e71da5a..db20a8b 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -356,7 +356,7 @@
 
 void GaiaScreenHandler::DeclareLocalizedValues(
     ::login::LocalizedValuesBuilder* builder) {
-  builder->Add("signinScreenTitle", IDS_SIGNIN_SCREEN_TITLE);
+  builder->Add("signinScreenTitle", IDS_SIGNIN_SCREEN_TITLE_TAB_PROMPT);
   builder->Add("signinScreenPasswordChanged",
                IDS_SIGNIN_SCREEN_PASSWORD_CHANGED);
   builder->Add("createAccount", IDS_CREATE_ACCOUNT_HTML);
diff --git a/chrome/browser/ui/webui/media_router/media_router_dialog_controller.cc b/chrome/browser/ui/webui/media_router/media_router_dialog_controller.cc
index 1265f53d..546eaee3 100644
--- a/chrome/browser/ui/webui/media_router/media_router_dialog_controller.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_dialog_controller.cc
@@ -100,6 +100,16 @@
 
 }  // namespace
 
+// static
+MediaRouterDialogController*
+MediaRouterDialogController::GetOrCreateForWebContents(
+    WebContents* web_contents) {
+  DCHECK(web_contents);
+  // This call does nothing if the controller already exists.
+  MediaRouterDialogController::CreateForWebContents(web_contents);
+  return MediaRouterDialogController::FromWebContents(web_contents);
+}
+
 class MediaRouterDialogController::DialogWebContentsObserver
     : public content::WebContentsObserver {
  public:
diff --git a/chrome/browser/ui/webui/media_router/media_router_dialog_controller.h b/chrome/browser/ui/webui/media_router/media_router_dialog_controller.h
index 96b1fe0..5cdf88b 100644
--- a/chrome/browser/ui/webui/media_router/media_router_dialog_controller.h
+++ b/chrome/browser/ui/webui/media_router/media_router_dialog_controller.h
@@ -21,6 +21,12 @@
  public:
   ~MediaRouterDialogController() override;
 
+  // Gets a reference to the MediaRouterDialogController associated with
+  // |web_contents|, creating one if it does not exist. The returned pointer is
+  // guaranteed to be non-null.
+  static MediaRouterDialogController* GetOrCreateForWebContents(
+      content::WebContents* web_contents);
+
   // Shows the media router dialog modal to the initiator WebContents.
   // Creates the dialog if it did not exist prior to this call.
   // If the dialog already exists, brings the dialog to the front.
diff --git a/chrome/browser/ui/webui/settings/downloads_handler.cc b/chrome/browser/ui/webui/settings/downloads_handler.cc
index 4654d41..6a6a9ec0 100644
--- a/chrome/browser/ui/webui/settings/downloads_handler.cc
+++ b/chrome/browser/ui/webui/settings/downloads_handler.cc
@@ -48,7 +48,7 @@
   info.support_drive = true;
   select_folder_dialog_->SelectFile(
       ui::SelectFileDialog::SELECT_FOLDER,
-      l10n_util::GetStringUTF16(IDS_SETTINGS_DOWNLOADS_LOCATION_LABEL),
+      l10n_util::GetStringUTF16(IDS_SETTINGS_DOWNLOAD_LOCATION),
       pref_service->GetFilePath(prefs::kDownloadDefaultDirectory), &info, 0,
       base::FilePath::StringType(),
       web_ui()->GetWebContents()->GetTopLevelNativeWindow(), NULL);
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 4201b10..e9b373e 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
@@ -4,7 +4,9 @@
 
 #include "chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.h"
 
+#include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
+#include "chrome/grit/locale_settings.h"
 #include "content/public/browser/web_ui_data_source.h"
 
 namespace {
@@ -17,98 +19,89 @@
   html_source->AddLocalizedString(
       "a11yPageTitle", IDS_SETTINGS_ACCESSIBILITY_PAGE_TITLE);
   html_source->AddLocalizedString(
-      "accessibilityMoreFeaturesLink",
-      IDS_SETTINGS_ACCESSIBILITY_MORE_FEATURES_LINK);
+      "moreFeaturesLink", IDS_SETTINGS_MORE_FEATURES_LINK);
   html_source->AddLocalizedString(
-      "accessibilityOptionsInMenuLabel",
-      IDS_SETTINGS_ACCESSIBILITY_OPTIONS_IN_MENU_LABEL);
+      "optionsInMenuLabel", IDS_SETTINGS_OPTIONS_IN_MENU_LABEL);
   html_source->AddLocalizedString(
-      "accessibilityLargeMouseCursorLabel",
-      IDS_SETTINGS_ACCESSIBILITY_LARGE_MOUSE_CURSOR_LABEL);
+      "largeMouseCursorLabel", IDS_SETTINGS_LARGE_MOUSE_CURSOR_LABEL);
   html_source->AddLocalizedString(
-      "accessibilityHighContrastLabel",
-      IDS_SETTINGS_ACCESSIBILITY_HIGH_CONTRAST_LABEL);
+      "highContrastLabel", IDS_SETTINGS_HIGH_CONTRAST_LABEL);
   html_source->AddLocalizedString(
-      "accessibilityStickyKeysLabel",
-      IDS_SETTINGS_ACCESSIBILITY_STICKY_KEYS_LABEL);
+      "stickyKeysLabel", IDS_SETTINGS_STICKY_KEYS_LABEL);
   html_source->AddLocalizedString(
-      "accessibilityStickyKeysSublabel",
-      IDS_SETTINGS_ACCESSIBILITY_STICKY_KEYS_SUBLABEL);
+      "stickyKeysSublabel", IDS_SETTINGS_STICKY_KEYS_SUBLABEL);
   html_source->AddLocalizedString(
-      "accessibilityChromeVoxLabel",
-      IDS_SETTINGS_ACCESSIBILITY_CHROMEVOX_LABEL);
+      "chromeVoxLabel", IDS_SETTINGS_CHROMEVOX_LABEL);
   html_source->AddLocalizedString(
-      "accessibilityChromeVoxSublabel",
-      IDS_SETTINGS_ACCESSIBILITY_CHROMEVOX_SUBLABEL);
+      "chromeVoxSublabel", IDS_SETTINGS_CHROMEVOX_SUBLABEL);
   html_source->AddLocalizedString(
-      "accessibilityScreenMagnifierLabel",
-      IDS_SETTINGS_ACCESSIBILITY_SCREEN_MAGNIFIER_LABEL);
+      "screenMagnifierLabel", IDS_SETTINGS_SCREEN_MAGNIFIER_LABEL);
   html_source->AddLocalizedString(
-      "accessibilityTapDraggingLabel",
-      IDS_SETTINGS_ACCESSIBILITY_TAP_DRAGGING_LABEL);
+      "tapDraggingLabel", IDS_SETTINGS_TAP_DRAGGING_LABEL);
   html_source->AddLocalizedString(
-      "accessibilityClickOnStopLabel",
-      IDS_SETTINGS_ACCESSIBILITY_CLICK_ON_STOP_LABEL);
+      "clickOnStopLabel", IDS_SETTINGS_CLICK_ON_STOP_LABEL);
   html_source->AddLocalizedString(
-      "accessibilityDelayBeforeClickLabel",
-      IDS_SETTINGS_ACCESSIBILITY_DELAY_BEFORE_CLICK_LABEL);
+      "delayBeforeClickLabel", IDS_SETTINGS_DELAY_BEFORE_CLICK_LABEL);
   html_source->AddLocalizedString(
-      "accessibilityDelayBeforeClickExtremelyShort",
-      IDS_SETTINGS_ACCESSIBILITY_DELAY_BEFORE_CLICK_EXTREMELY_SHORT);
+      "delayBeforeClickExtremelyShort",
+      IDS_SETTINGS_DELAY_BEFORE_CLICK_EXTREMELY_SHORT);
   html_source->AddLocalizedString(
-      "accessibilityDelayBeforeClickVeryShort",
-      IDS_SETTINGS_ACCESSIBILITY_DELAY_BEFORE_CLICK_VERY_SHORT);
+      "delayBeforeClickVeryShort", IDS_SETTINGS_DELAY_BEFORE_CLICK_VERY_SHORT);
   html_source->AddLocalizedString(
-      "accessibilityDelayBeforeClickShort",
-      IDS_SETTINGS_ACCESSIBILITY_DELAY_BEFORE_CLICK_SHORT);
+      "delayBeforeClickShort", IDS_SETTINGS_DELAY_BEFORE_CLICK_SHORT);
   html_source->AddLocalizedString(
-      "accessibilityDelayBeforeClickLong",
-      IDS_SETTINGS_ACCESSIBILITY_DELAY_BEFORE_CLICK_LONG);
+      "delayBeforeClickLong", IDS_SETTINGS_DELAY_BEFORE_CLICK_LONG);
   html_source->AddLocalizedString(
-      "accessibilityDelayBeforeClickVeryLong",
-      IDS_SETTINGS_ACCESSIBILITY_DELAY_BEFORE_CLICK_VERY_LONG);
+      "delayBeforeClickVeryLong", IDS_SETTINGS_DELAY_BEFORE_CLICK_VERY_LONG);
   html_source->AddLocalizedString(
-      "accessibilityOnScreenKeyboardLabel",
-      IDS_SETTINGS_ACCESSIBILITY_ON_SCREEN_KEYBOARD_LABEL);
+      "onScreenKeyboardLabel", IDS_SETTINGS_ON_SCREEN_KEYBOARD_LABEL);
 }
 
 void AddAppearanceStrings(content::WebUIDataSource* html_source) {
   html_source->AddLocalizedString(
       "appearancePageTitle", IDS_SETTINGS_APPEARANCE_PAGE_TITLE);
   html_source->AddLocalizedString(
-      "appearanceShowHomeButtonLabel",
-      IDS_SETTINGS_APPEARANCE_SHOW_HOME_BUTTON_LABEL);
+      "setWallpaper", IDS_SETTINGS_SET_WALLPAPER);
   html_source->AddLocalizedString(
-      "appearanceShowBookmarksBarLabel",
-      IDS_SETTINGS_APPEARANCE_SHOW_BOOKMARKS_BAR_LABEL);
+      "getThemes", IDS_SETTINGS_GET_THEMES);
+  html_source->AddLocalizedString(
+      "resetToDefaultTheme", IDS_SETTINGS_RESET_TO_DEFAULT_THEME);
+  html_source->AddLocalizedString(
+      "showHomeButton", IDS_SETTINGS_SHOW_HOME_BUTTON);
+  html_source->AddLocalizedString(
+      "showBookmarksBar", IDS_SETTINGS_SHOW_BOOKMARKS_BAR);
+  html_source->AddLocalizedString(
+      "homePageNtp", IDS_SETTINGS_HOME_PAGE_NTP);
+  html_source->AddLocalizedString(
+      "changeHomePage", IDS_SETTINGS_CHANGE_HOME_PAGE);
+  html_source->AddLocalizedString(
+      "themesGalleryUrl", IDS_THEMES_GALLERY_URL);
+}
+
+void AddCommonStrings(content::WebUIDataSource* html_source) {
+  html_source->AddLocalizedString("addLabel", IDS_ADD);
 }
 
 void AddDownloadsStrings(content::WebUIDataSource* html_source) {
   html_source->AddLocalizedString(
       "downloadsPageTitle", IDS_SETTINGS_DOWNLOADS_PAGE_TITLE);
   html_source->AddLocalizedString(
-      "downloadsLocationLabel", IDS_SETTINGS_DOWNLOADS_LOCATION_LABEL);
+      "downloadLocation", IDS_SETTINGS_DOWNLOAD_LOCATION);
   html_source->AddLocalizedString(
-      "downloadsChangeLocationButton",
-      IDS_SETTINGS_DOWNLOADS_CHANGE_LOCATION_BUTTON);
+      "changeDownloadLocation", IDS_SETTINGS_CHANGE_DOWNLOAD_LOCATION);
   html_source->AddLocalizedString(
-      "downloadsPromptForDownloadLabel",
-      IDS_SETTINGS_DOWNLOADS_PROMPT_FOR_DOWNLOAD_LABEL);
+      "promptForDownload", IDS_SETTINGS_PROMPT_FOR_DOWNLOAD);
 }
 
 void AddDateTimeStrings(content::WebUIDataSource* html_source) {
   html_source->AddLocalizedString(
-      "dateTimePageTitle",
-      IDS_SETTINGS_DATE_TIME_PAGE_TITLE);
+      "dateTimePageTitle", IDS_SETTINGS_DATE_TIME_PAGE_TITLE);
   html_source->AddLocalizedString(
-      "dateTimeTimeZoneLabel",
-      IDS_SETTINGS_DATE_TIME_TIME_ZONE_LABEL);
+      "timeZone", IDS_SETTINGS_TIME_ZONE);
   html_source->AddLocalizedString(
-      "dateTime24HourClockLabel",
-      IDS_SETTINGS_DATE_TIME_24_HOUR_CLOCK_LABEL);
+      "use24HourClock", IDS_SETTINGS_USE_24_HOUR_CLOCK);
   html_source->AddLocalizedString(
-      "dateTimeAutomaticallySet",
-      IDS_SETTINGS_DATE_TIME_AUTOMATICALLY_SET);
+      "dateTimeSetAutomatically", IDS_SETTINGS_DATE_TIME_SET_AUTOMATICALLY);
 }
 
 #if defined(OS_CHROMEOS)
@@ -158,6 +151,70 @@
                                   IDS_SETTINGS_SEARCH_ENGINES_ADD_BUTTON_LABEL);
 }
 
+void AddSyncStrings(content::WebUIDataSource* html_source) {
+  html_source->AddLocalizedString("syncPageTitle",
+                                  IDS_SETTINGS_SYNC_PAGE_TITLE);
+  html_source->AddLocalizedString("syncEverythingMenuOption",
+                                  IDS_SETTINGS_SYNC_EVERYTHING_MENU_OPTION);
+  html_source->AddLocalizedString("chooseWhatToSyncMenuOption",
+                                  IDS_SETTINGS_CHOOSE_WHAT_TO_SYNC_MENU_OPTION);
+  html_source->AddLocalizedString("appCheckboxLabel",
+                                  IDS_SETTINGS_APPS_CHECKBOX_LABEL);
+  html_source->AddLocalizedString("extensionsCheckboxLabel",
+                                  IDS_SETTINGS_EXTENSIONS_CHECKBOX_LABEL);
+  html_source->AddLocalizedString("settingsCheckboxLabel",
+                                  IDS_SETTINGS_SETTINGS_CHECKBOX_LABEL);
+  html_source->AddLocalizedString("autofillCheckboxLabel",
+                                  IDS_SETTINGS_AUTOFILL_CHECKBOX_LABEL);
+  html_source->AddLocalizedString("historyCheckboxLabel",
+                                  IDS_SETTINGS_HISTORY_CHECKBOX_LABEL);
+  html_source->AddLocalizedString(
+      "themesAndWallpapersCheckboxLabel",
+      IDS_SETTINGS_THEMES_AND_WALLPAPERS_CHECKBOX_LABEL);
+  html_source->AddLocalizedString("bookmarksCheckboxLabel",
+                                  IDS_SETTINGS_BOOKMARKS_CHECKBOX_LABEL);
+  html_source->AddLocalizedString("passwordsCheckboxLabel",
+                                  IDS_SETTINGS_PASSWORDS_CHECKBOX_LABEL);
+  html_source->AddLocalizedString("openTabsCheckboxLabel",
+                                  IDS_SETTINGS_OPEN_TABS_CHECKBOX_LABEL);
+  html_source->AddLocalizedString("encryptionOptionsTitle",
+                                  IDS_SETTINGS_ENCRYPTION_OPTIONS_TITLE);
+  html_source->AddLocalizedString("syncDataEncryptedText",
+                                  IDS_SETTINGS_SYNC_DATA_ENCRYPTED_TEXT);
+  html_source->AddLocalizedString(
+      "encryptWithGoogleCredentialsLabel",
+      IDS_SETTINGS_ENCRYPT_WITH_GOOGLE_CREDENTIALS_LABEL);
+  html_source->AddLocalizedString(
+      "encryptWithSyncPassphraseLabel",
+      IDS_SETTINGS_ENCRYPT_WITH_SYNC_PASSPHRASE_LABEL);
+  html_source->AddLocalizedString(
+      "encryptWithSyncPassphraseLearnMoreLink",
+      IDS_SETTINGS_ENCRYPT_WITH_SYNC_PASSPHRASE_LEARN_MORE_LINK);
+  html_source->AddLocalizedString("useDefaultSettingsButton",
+                                  IDS_SETTINGS_USE_DEFAULT_SETTINGS_BUTTON);
+  html_source->AddLocalizedString("cancelButton",
+                                  IDS_SETTINGS_CANCEL_BUTTON);
+  html_source->AddLocalizedString("okButton",
+                                  IDS_SETTINGS_OK_BUTTON);
+}
+
+void AddUsersStrings(content::WebUIDataSource* html_source) {
+  html_source->AddLocalizedString("usersPageTitle",
+                                  IDS_SETTINGS_USERS_PAGE_TITLE);
+  html_source->AddLocalizedString("usersModifiedByOwnerLabel",
+                                  IDS_SETTINGS_USERS_MODIFIED_BY_OWNER_LABEL);
+  html_source->AddLocalizedString("guestBrowsingLabel",
+                                  IDS_SETTINGS_USERS_GUEST_BROWSING_LABEL);
+  html_source->AddLocalizedString("supervisedUsersLabel",
+                                  IDS_SETTINGS_USERS_SUPERVISED_USERS_LABEL);
+  html_source->AddLocalizedString("showOnSigninLabel",
+                                  IDS_SETTINGS_USERS_SHOW_ON_SIGNIN_LABEL);
+  html_source->AddLocalizedString("restrictSigninLabel",
+                                  IDS_SETTINGS_USERS_RESTRICT_SIGNIN_LABEL);
+  html_source->AddLocalizedString("addUsersLabel",
+                                  IDS_SETTINGS_USERS_ADD_USERS_LABEL);
+}
+
 }  // namespace
 
 namespace settings {
@@ -165,6 +222,7 @@
 void AddLocalizedStrings(content::WebUIDataSource* html_source) {
   AddA11yStrings(html_source);
   AddAppearanceStrings(html_source);
+  AddCommonStrings(html_source);
   AddDownloadsStrings(html_source);
   AddDateTimeStrings(html_source);
 #if defined(OS_CHROMEOS)
@@ -172,6 +230,8 @@
 #endif
   AddSearchStrings(html_source);
   AddSearchEnginesStrings(html_source);
+  AddSyncStrings(html_source);
+  AddUsersStrings(html_source);
   html_source->SetJsonPath(kLocalizedStringsFile);
 }
 
diff --git a/chrome/browser/ui/webui/signin_internals_ui.cc b/chrome/browser/ui/webui/signin_internals_ui.cc
index a709e406..a14e6c61 100644
--- a/chrome/browser/ui/webui/signin_internals_ui.cc
+++ b/chrome/browser/ui/webui/signin_internals_ui.cc
@@ -73,7 +73,7 @@
           "chrome.signin.getSigninInfo.handleReply",
           *about_signin_internals->GetSigninStatus());
 
-      std::vector<std::pair<std::string, bool>> cookie_accounts;
+      std::vector<gaia::ListedAccount> cookie_accounts;
       GaiaCookieManagerService* cookie_manager_service =
           GaiaCookieManagerServiceFactory::GetForProfile(profile);
       if (cookie_manager_service->ListAccounts(&cookie_accounts)) {
diff --git a/chrome/browser/ui/zoom/zoom_controller_unittest.cc b/chrome/browser/ui/zoom/zoom_controller_unittest.cc
index 7614a8da..b6fc9682 100644
--- a/chrome/browser/ui/zoom/zoom_controller_unittest.cc
+++ b/chrome/browser/ui/zoom/zoom_controller_unittest.cc
@@ -65,7 +65,7 @@
 
     // This call is needed so that the RenderViewHost reports being alive. This
     // is only important for tests that call ZoomController::SetZoomLevel().
-    content::RenderViewHostTester::For(rvh())->CreateRenderView(
+    content::RenderViewHostTester::For(rvh())->CreateTestRenderView(
         base::string16(), MSG_ROUTING_NONE, MSG_ROUTING_NONE, -1, false);
   }
 
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 7e2f369..8ee8753 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -588,7 +588,7 @@
             '../base/base.gyp:base',
             '../components/components.gyp:bookmarks_java',
             '../components/components.gyp:dom_distiller_core_java',
-            '../components/components.gyp:enhanced_bookmarks_launch_location_srcjar',
+            '../components/components.gyp:enhanced_bookmarks_java_enums_srcjar',
             '../components/components.gyp:gcm_driver_java',
             '../components/components.gyp:invalidation_java',
             '../components/components.gyp:navigation_interception_java',
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index a790155..97645e85 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -738,8 +738,6 @@
       'browser/speech/tts_platform.cc',
       'browser/speech/tts_platform.h',
       'browser/speech/tts_win.cc',
-      'browser/ssl/connection_security_helper_android.cc',
-      'browser/ssl/connection_security_helper_android.h',
       'browser/status_icons/status_icon.cc',
       'browser/status_icons/status_icon.h',
       'browser/status_icons/status_icon_menu_model.cc',
@@ -772,6 +770,8 @@
       'browser/thumbnails/thumbnailing_algorithm.h',
       'browser/thumbnails/thumbnailing_context.cc',
       'browser/thumbnails/thumbnailing_context.h',
+      'browser/tracing/background_tracing_field_trial.cc',
+      'browser/tracing/background_tracing_field_trial.h',
       'browser/tracing/chrome_tracing_delegate.cc',
       'browser/tracing/chrome_tracing_delegate.h',
       'browser/tracing/crash_service_uploader.cc',
@@ -933,6 +933,12 @@
       'browser/auto_launch_trial.h',
       'browser/background/background_contents.cc',
       'browser/background/background_contents.h',
+      'browser/banners/app_banner_data_fetcher_desktop.cc',
+      'browser/banners/app_banner_data_fetcher_desktop.h',
+      'browser/banners/app_banner_infobar_delegate_desktop.cc',
+      'browser/banners/app_banner_infobar_delegate_desktop.h',
+      'browser/banners/app_banner_manager_desktop.cc',
+      'browser/banners/app_banner_manager_desktop.h',
       'browser/bookmarks/bookmark_html_writer.cc',
       'browser/bookmarks/bookmark_html_writer.h',
       'browser/certificate_viewer.cc',
@@ -1725,6 +1731,7 @@
       'android/java/src/org/chromium/chrome/browser/NavigationPopup.java',
       'android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java',
       'android/java/src/org/chromium/chrome/browser/infobar/DownloadOverwriteInfoBar.java',
+      'android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBar.java',
       'android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java',
       'android/java/src/org/chromium/chrome/browser/omnibox/AnswersImage.java',
       'android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java',
@@ -1770,7 +1777,6 @@
       'android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBarDelegate.java',
       'android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java',
       'android/java/src/org/chromium/chrome/browser/infobar/InfoBarContainer.java',
-      'android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBarDelegate.java',
       'android/java/src/org/chromium/chrome/browser/infobar/SavePasswordInfoBar.java',
       'android/java/src/org/chromium/chrome/browser/invalidation/InvalidationServiceFactory.java',
       'android/java/src/org/chromium/chrome/browser/metrics/LaunchMetrics.java',
@@ -2030,6 +2036,8 @@
       'browser/permissions/permission_manager.h',
       'browser/permissions/permission_manager_factory.cc',
       'browser/permissions/permission_manager_factory.h',
+      'browser/permissions/permission_request_id.cc',
+      'browser/permissions/permission_request_id.h',
     ],
     # See also the plugin_installation_sources list below.
     'chrome_browser_plugins_sources': [
@@ -2721,6 +2729,7 @@
       'browser/ssl/connection_security_helper.cc',
       'browser/ssl/connection_security_helper.h',
       'browser/ssl/connection_security_helper_android.cc',
+      'browser/ssl/connection_security_helper_android.h',
       'browser/ssl/ssl_blocking_page.cc',
       'browser/ssl/ssl_blocking_page.h',
       'browser/ssl/ssl_cert_reporter.h',
@@ -2953,10 +2962,22 @@
       'browser/task_management/providers/task_provider.cc',
       'browser/task_management/providers/task_provider.h',
       'browser/task_management/providers/task_provider_observer.h',
+      'browser/task_management/providers/web_contents/background_contents_tag.cc',
+      'browser/task_management/providers/web_contents/background_contents_tag.h',
+      'browser/task_management/providers/web_contents/background_contents_task.cc',
+      'browser/task_management/providers/web_contents/background_contents_task.h',
       'browser/task_management/providers/web_contents/renderer_task.cc',
       'browser/task_management/providers/web_contents/renderer_task.h',
       'browser/task_management/providers/web_contents/subframe_task.cc',
       'browser/task_management/providers/web_contents/subframe_task.h',
+      'browser/task_management/providers/web_contents/web_contents_tag.cc',
+      'browser/task_management/providers/web_contents/web_contents_tag.h',
+      'browser/task_management/providers/web_contents/web_contents_tags_manager.cc',
+      'browser/task_management/providers/web_contents/web_contents_tags_manager.h',
+      'browser/task_management/providers/web_contents/web_contents_task_provider.cc',
+      'browser/task_management/providers/web_contents/web_contents_task_provider.h',
+      'browser/task_management/web_contents_tags.cc',
+      'browser/task_management/web_contents_tags.h',
 
       # Old Task Manager Sources:
       'browser/task_manager/background_information.cc',
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index 4a56bac..f62851a 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -710,6 +710,8 @@
         'browser/chromeos/memory/low_memory_observer.h',
         'browser/chromeos/memory/oom_priority_manager.cc',
         'browser/chromeos/memory/oom_priority_manager.h',
+        'browser/chromeos/memory/system_memory_stats_recorder.cc',
+        'browser/chromeos/memory/system_memory_stats_recorder.h',
         'browser/chromeos/mobile/mobile_activator.cc',
         'browser/chromeos/mobile/mobile_activator.h',
         'browser/chromeos/mobile_config.cc',
@@ -1104,13 +1106,6 @@
       'target_name': 'browser_chromeos',
       'type': 'static_library',
       'variables': {
-        'conditions': [
-          ['sysroot!=""', {
-            'pkg-config': '../build/linux/pkg-config-wrapper "<(sysroot)" "<(target_arch)" "<(system_libdir)"',
-          }, {
-            'pkg-config': 'pkg-config'
-          }],
-        ],
         # Override to dynamically link the cras (ChromeOS audio) library.
         'use_cras%': 0,
         'enable_wexit_time_destructors': 1,
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 92426c0..58ee9ce 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -1282,8 +1282,6 @@
       'browser/ui/cocoa/view_id_util.h',
       'browser/ui/cocoa/view_id_util.mm',
       'browser/ui/cocoa/view_resizer.h',
-      'browser/ui/cocoa/web_contents_modal_dialog_host_cocoa.h',
-      'browser/ui/cocoa/web_contents_modal_dialog_host_cocoa.mm',
       'browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.h',
       'browser/ui/cocoa/web_contents_modal_dialog_manager_views_mac.mm',
       'browser/ui/cocoa/web_dialog_window_controller.h',
@@ -1458,6 +1456,8 @@
       'browser/ui/cocoa/tab_contents/web_drag_bookmark_handler_mac.mm',
       'browser/ui/cocoa/ui_localizer.h',
       'browser/ui/cocoa/ui_localizer.mm',
+      'browser/ui/cocoa/web_contents_modal_dialog_host_cocoa.h',
+      'browser/ui/cocoa/web_contents_modal_dialog_host_cocoa.mm',
       'browser/ui/cocoa/window_restore_utils.h',
       'browser/ui/cocoa/window_restore_utils.mm',
       'browser/ui/startup/autolaunch_prompt.cc',
@@ -2607,8 +2607,6 @@
       'browser/ui/extensions/app_launch_params.h',
       'browser/ui/extensions/application_launch.cc',
       'browser/ui/extensions/application_launch.h',
-      'browser/ui/extensions/bookmark_app_browser_controller.cc',
-      'browser/ui/extensions/bookmark_app_browser_controller.h',
       'browser/ui/extensions/extension_action_platform_delegate.h',
       'browser/ui/extensions/extension_action_view_controller.cc',
       'browser/ui/extensions/extension_action_view_controller.h',
@@ -2625,6 +2623,8 @@
       'browser/ui/extensions/extension_message_bubble_factory.h',
       'browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_delegate.cc',
       'browser/ui/extensions/extension_toolbar_icon_surfacing_bubble_delegate.h',
+      'browser/ui/extensions/hosted_app_browser_controller.cc',
+      'browser/ui/extensions/hosted_app_browser_controller.h',
       'browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc',
       'browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h',
       'browser/ui/webui/extensions/extension_basic_info.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 909a1ae1..f04c45a8 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -406,10 +406,12 @@
       'browser/sync_file_system/mock_remote_file_sync_service.cc',
       'browser/sync_file_system/mock_remote_file_sync_service.h',
       'browser/tab_contents/view_source_browsertest.cc',
+      'browser/task_management/providers/web_contents/background_contents_tag_browsertest.cc',
       'browser/task_manager/task_manager_browsertest.cc',
       'browser/task_manager/task_manager_browsertest_util.cc',
       'browser/task_manager/task_manager_browsertest_util.h',
       'browser/themes/theme_service_browsertest.cc',
+      'browser/tracing/chrome_tracing_delegate_browsertest.cc',
       'browser/translate/cld_data_harness.cc',
       'browser/translate/cld_data_harness.h',
       'browser/translate/cld_data_harness_factory.cc',
@@ -466,9 +468,9 @@
       'browser/ui/cocoa/content_settings/content_setting_bubble_cocoa_unittest.mm',
       'browser/ui/cocoa/dev_tools_controller_browsertest.mm',
       'browser/ui/cocoa/extensions/extension_install_dialog_controller_browsertest.mm',
-      'browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm',
       'browser/ui/cocoa/extensions/extension_install_prompt_test_utils.h',
       'browser/ui/cocoa/extensions/extension_install_prompt_test_utils.mm',
+      'browser/ui/cocoa/extensions/extension_message_bubble_browsertest_mac.mm',
       'browser/ui/cocoa/extensions/media_galleries_dialog_cocoa_browsertest.mm',
       'browser/ui/cocoa/extensions/windowed_install_dialog_controller_browsertest.mm',
       'browser/ui/cocoa/find_bar/find_bar_browsertest.mm',
@@ -486,7 +488,7 @@
       'browser/ui/exclusive_access/fullscreen_controller_browsertest.cc',
       'browser/ui/extensions/extension_message_bubble_browsertest.cc',
       'browser/ui/extensions/extension_message_bubble_browsertest.h',
-      'browser/ui/extensions/bookmark_app_browsertest.cc',
+      'browser/ui/extensions/hosted_app_browsertest.cc',
       'browser/ui/find_bar/find_bar_host_browsertest.cc',
       'browser/ui/global_error/global_error_service_browsertest.cc',
       'browser/ui/location_bar/location_bar_browsertest.cc',
@@ -505,8 +507,6 @@
       'browser/ui/tab_modal_confirm_dialog_browsertest.h',
       'browser/ui/test/scoped_fake_nswindow_main_status.h',
       'browser/ui/test/scoped_fake_nswindow_main_status.mm',
-      'browser/ui/website_settings/permission_bubble_browser_test_util.cc',
-      'browser/ui/website_settings/permission_bubble_browser_test_util.h',
       'browser/ui/toolbar/browser_actions_bar_browsertest.cc',
       'browser/ui/toolbar/browser_actions_bar_browsertest.h',
       'browser/ui/toolbar/component_toolbar_actions_browsertest.cc',
@@ -514,6 +514,8 @@
       'browser/ui/toolbar/test_toolbar_model.h',
       'browser/ui/website_settings/mock_permission_bubble_view.cc',
       'browser/ui/website_settings/mock_permission_bubble_view.h',
+      'browser/ui/website_settings/permission_bubble_browser_test_util.cc',
+      'browser/ui/website_settings/permission_bubble_browser_test_util.h',
       'browser/ui/webui/bidi_checker_web_ui_test.cc',
       'browser/ui/webui/bidi_checker_web_ui_test.h',
       'browser/ui/webui/bookmarks_ui_browsertest.cc',
@@ -623,6 +625,7 @@
       'browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc',
       'browser/ui/views/frame/browser_view_browsertest.cc',
       'browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc',
+      'browser/ui/views/media_router/media_router_ui_browsertest.cc',
       'browser/ui/views/profiles/avatar_menu_button_browsertest.cc',
       'browser/ui/views/profiles/profile_chooser_view_browsertest.cc',
       'browser/ui/views/toolbar/browser_actions_container_browsertest.cc',
@@ -716,8 +719,8 @@
       'browser/chromeos/login/screens/network_screen_browsertest.cc',
       'browser/chromeos/login/screens/update_screen_browsertest.cc',
       'browser/chromeos/login/session_login_browsertest.cc',
-      'browser/chromeos/login/signin/oauth2_browsertest.cc',
       'browser/chromeos/login/signin/device_id_browsertest.cc',
+      'browser/chromeos/login/signin/oauth2_browsertest.cc',
       'browser/chromeos/login/supervised/supervised_user_creation_browsertest.cc',
       'browser/chromeos/login/supervised/supervised_user_password_browsertest.cc',
       'browser/chromeos/login/supervised/supervised_user_test_base.cc',
@@ -2202,9 +2205,9 @@
           'sources': [ '<@(chrome_browser_tests_chromeos_sources)' ],
           'sources!': [
             '../apps/load_and_launch_browsertest.cc',
+            'browser/policy/policy_startup_browsertest.cc',
             'browser/printing/cloud_print/test/cloud_print_policy_browsertest.cc',
             'browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc',
-            'browser/policy/policy_startup_browsertest.cc',
             # chromeos does not support profile list avatar menu
             'browser/profiles/profile_list_desktop_browsertest.cc',
             'browser/service_process/service_process_control_browsertest.cc',
@@ -2256,10 +2259,6 @@
             'browser/media/chrome_webrtc_getmediadevices_browsertest.cc',
          ],
         }],
-        ['enable_media_router==1', {
-          'sources': [ '<@(chrome_browser_tests_media_router_sources)' ],
-          'dependencies': [ 'browser/media/router/media_router.gyp:media_router_test_support' ],
-        }],
         ['OS=="win"', {
           'sources': [
             '<(SHARED_INTERMEDIATE_DIR)/chrome_version/other_version.rc',
@@ -2448,6 +2447,15 @@
             'test/data/webui/print_preview.js',
           ],
         }],
+        ['enable_media_router==1', {
+          'sources': [ '<@(chrome_browser_tests_media_router_sources)' ],
+          'dependencies': [ 'browser/media/router/media_router.gyp:media_router_test_support' ],
+          'conditions': [
+            ['toolkit_views==0', {
+              'sources!': [ 'browser/ui/views/media_router/media_router_ui_browsertest.cc' ],
+            }],
+          ],
+        }],
         ['enable_mdns==1', {
           'sources' : [
             'browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc',
diff --git a/chrome/common/extensions/api/automation.idl b/chrome/common/extensions/api/automation.idl
index 2f3b0af..a0d8116 100644
--- a/chrome/common/extensions/api/automation.idl
+++ b/chrome/common/extensions/api/automation.idl
@@ -340,6 +340,16 @@
     // an <code>&lt;input&gt; element.
     DOMString value;
 
+    // The HTML tag for this element, if this node is an HTML element.
+    DOMString htmlTag;
+
+    // The level of a heading or tree item.
+    long hierarchicalLevel;
+
+    // The start and end index of each word in an inline text box.
+    long[] wordStarts;
+    long[] wordEnds;
+
     // The nodes, if any, which this node is specified to control via
     // <a href="http://www.w3.org/TR/wai-aria/states_and_properties#aria-controls">
     // <code>aria-controls</code></a>.
@@ -394,6 +404,9 @@
     // Sets selection within a text field.
     static void setSelection(long startIndex, long endIndex);
 
+    // Shows the context menu resulting from a right click on this node.
+    static void showContextMenu();
+
     // Adds a listener for the given event type and event phase.
     static void addEventListener(
         EventType eventType, AutomationListener listener, boolean capture);
@@ -481,6 +494,9 @@
     // The character index of the end of the selection within this editable
     // text element; -1 if no selection.
     long textSelEnd;
+
+    // The input type, like email or number.
+    DOMString textInputType;
   };
 
   // Attributes which are mixed in to an AutomationNode if it is a range.
diff --git a/chrome/common/extensions/api/automation_internal.idl b/chrome/common/extensions/api/automation_internal.idl
index 7b9063fe7..ce22523 100644
--- a/chrome/common/extensions/api/automation_internal.idl
+++ b/chrome/common/extensions/api/automation_internal.idl
@@ -65,7 +65,8 @@
     focus,
     doDefault,
     makeVisible,
-    setSelection
+    setSelection,
+    showContextMenu
   };
 
   // Arguments required for all actions supplied to performAction.
diff --git a/chrome/common/extensions/docs/server2/PRESUBMIT.py b/chrome/common/extensions/docs/server2/PRESUBMIT.py
index 047dee3..c64d4163 100644
--- a/chrome/common/extensions/docs/server2/PRESUBMIT.py
+++ b/chrome/common/extensions/docs/server2/PRESUBMIT.py
@@ -15,8 +15,9 @@
 
 WHITELIST = [ r'.+_test.py$' ]
 # The integration tests are selectively run from the PRESUBMIT in
-# chrome/common/extensions.
-BLACKLIST = [ r'integration_test.py$' ]
+# chrome/common/extensions. Github filesystem support is currently
+# disabled.
+BLACKLIST = [ r'integration_test.py$', r'.*github.*_test.py$' ]
 
 def _BuildServer(input_api):
   try:
@@ -26,14 +27,6 @@
   finally:
     sys.path.pop(0)
 
-def _ImportAppYamlHelper(input_api):
-  try:
-    sys.path.insert(0, input_api.PresubmitLocalPath())
-    from app_yaml_helper import AppYamlHelper
-    return AppYamlHelper
-  finally:
-    sys.path.pop(0)
-
 def _WarnIfAppYamlHasntChanged(input_api, output_api):
   app_yaml_path = os.path.join(input_api.PresubmitLocalPath(), 'app.yaml')
   if app_yaml_path in input_api.AbsoluteLocalPaths():
@@ -53,7 +46,6 @@
      THIS WILL CAUSE THE CURRENTLY RUNNING SERVER TO STOP UPDATING.
      PUSH THE NEW VERSION ASAP.
 No? Continue.
-
 Q: Is this a non-trivial change to the server?
 Yes? Bump the end version.
      Unlike above, the server will *not* stop updating.
@@ -64,25 +56,6 @@
 No? I guess this presubmit check doesn't work.
 ''')]
 
-def _CheckYamlConsistency(input_api, output_api):
-  app_yaml_path = os.path.join(input_api.PresubmitLocalPath(), 'app.yaml')
-  cron_yaml_path = os.path.join(input_api.PresubmitLocalPath(), 'cron.yaml')
-  if not (app_yaml_path in input_api.AbsoluteLocalPaths() or
-          cron_yaml_path in input_api.AbsoluteLocalPaths()):
-    return []
-
-  AppYamlHelper = _ImportAppYamlHelper(input_api)
-  app_yaml_version = AppYamlHelper.ExtractVersion(
-      input_api.ReadFile(app_yaml_path))
-  cron_yaml_version = AppYamlHelper.ExtractVersion(
-      input_api.ReadFile(cron_yaml_path), key='target')
-
-  if app_yaml_version == cron_yaml_version:
-    return []
-  return [output_api.PresubmitError(
-      'Versions of app.yaml (%s) and cron.yaml (%s) must match' % (
-          app_yaml_version, cron_yaml_version))]
-
 def _RunPresubmit(input_api, output_api):
   _BuildServer(input_api)
   # For now, print any lint errors. When these have been eliminated,
@@ -94,7 +67,6 @@
 
   return (
       _WarnIfAppYamlHasntChanged(input_api, output_api) +
-      _CheckYamlConsistency(input_api, output_api) +
       input_api.canned_checks.RunUnitTestsInDirectory(
           input_api, output_api, '.', whitelist=WHITELIST, blacklist=BLACKLIST)
   )
diff --git a/chrome/common/extensions/docs/server2/README b/chrome/common/extensions/docs/server2/README
index 9268904..2315d922 100644
--- a/chrome/common/extensions/docs/server2/README
+++ b/chrome/common/extensions/docs/server2/README
@@ -20,11 +20,40 @@
 
   3. View docs at http://localhost:8080/(apps|extensions)/<doc_name>
 
+NOTE: The dev server will not work right way: you need to populate its
+Datastore. You will need a local datastore cache in the working directory where
+you started the dev server, and you will need to manually instruct the dev
+server to pull data from that file:
 
---------------------------------------------
-Using Google Cloud Storage content providers
+  1. Run './update_cache.py --no-push --save-file=FOOCACHE'. This will take
+     a very long time (30-40 minutes). It is advisable that you keep a copy
+     of this file around if you plan use the dev server often. It can be
+     updated much faster (< 3 minutes) in that case by also including
+     --load-file=FOOCACHE on subsequent update_cache.py runs.
 
-With preview.py:
+     You MUST have branch heads fetched in your local repo in order for your
+     local data set to be populated correctly. You can accomplish this by
+     running:
+
+       gclient sync --with_branch_heads
+       git fetch origin
+
+     You may also specify --commit=<commitish> when running update_cache.py in
+     order to update the cache from a specific commit. This may be a commit ID,
+     or a partial commit ID, or a local branch ref, etc. To test local changes,
+     you MUST commit them locally and use the local commit to update your cache.
+
+  2. Once you have a cache (e.g. FOOCACHE) in the working directory of your
+     dev server, visit the URL:
+
+       http://localhost:8080/_update_cache/FOOCACHE
+
+     The server should take about a minute to fully populate its Datastore
+     from the data in your FOOCACHE file. Now you have a working dev server!
+
+
+------------------------------------------------------------
+Using Google Cloud Storage content providers with preview.py
 
   1. create a directory "[...]/server2/local_debug/gcs/<bucketname>" for every
      gcs bucket referenced in content_providers.json
@@ -32,28 +61,12 @@
   2. copy files to the respective local bucket directories. Preview.py has
      no access to the real Google Cloud Storage.
 
-With start_dev_server.py:
-
-    1. Install gsutils from https://developers.google.com/storage/docs/gsutil
-
-    2. Set gsutil accordingly to the official instructions.
-
-    3. Make sure you have permission to the GCS buckets specified in
-       content_providers.json by running "gsutil ls gs://bucketname"
-
-    4. Get an oauth token (see instructions at the comment of
-       gcs_file_system_provider.py) and save it to the file
-       "[...]/server2/local_debug/gcs_debug.conf"
-
-Remember that the step 4 needs to be repeated every 10 minutes or so,
-because the oauth access token expires quickly.
 
 --------------------
 Deploying the Server
 
 You will need to have access to the http://chrome-apps-doc.appspot.com app.
-Contact aa@chromium.org, erikkay@chromium.org, miket@chromium.org,
-kalman@chromium.org, or ernestd@chromium.org to obtain access.
+Contact kalman@chromium.org or rockot@chromium.org to obtain access.
 
 Once you have access:
 
@@ -75,3 +88,39 @@
    If you get an error about too many versions when deploying, go into this
    view and delete the version which was deployed the longest time ago.  Then
    try to deploy again.
+
+
+----------------------
+Updating the Datastore
+
+Even when the server code hasn't changed, new data is constantly flowing into
+the chromium repo and some of that data includes changes to new or existing
+content hosted by the server. In order for the front-end to reflect these
+changes, new data must be pushed into the project's Datastore.
+
+This is done periodically by a Compute Engine instance running the
+update_cache.py tool. While it is possible to push from other hosts if you
+get all the right credentials in all the right places, it is strongly
+discouraged and also therefore not documented.
+
+To force a push safely from the VM, navigate to the developer console under
+Compute -> Compute Engine -> VM instances and open SSH for the "git-processor"
+instance. From within the SSH session, first switch to user "git-processor":
+
+  sudo su - git-processor
+
+You can run './update-docs.sh' from the home directory there. This will
+automatically fetch any new objects from the upstream repository and then
+perform a full update if there are pending changes.
+
+It's almost never necessary to use this tool. For one interesting example,
+consider the case where no new commits are landing in the chrome repository
+but a change was just pushed to one of the GCS providers (like say, the
+chromedocs-multidevice bucker). In this case, you may want to force an update
+of only the content_providers data.
+
+  ./update_docs.sh --data-source=content_providers --force
+
+This will safely do the push for you, ensuring that the automated job
+does not collide with your own.
+
diff --git a/chrome/common/extensions/docs/server2/admin_servlets.py b/chrome/common/extensions/docs/server2/admin_servlets.py
index 7990761..4e0a838 100644
--- a/chrome/common/extensions/docs/server2/admin_servlets.py
+++ b/chrome/common/extensions/docs/server2/admin_servlets.py
@@ -2,35 +2,28 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from appengine_wrappers import taskqueue
+import json
+import logging
+
+from appengine_wrappers import memcache
 from commit_tracker import CommitTracker
+from environment import IsDevServer
+from environment_wrappers import CreateUrlFetcher
 from future import All
 from object_store_creator import ObjectStoreCreator
-from refresh_tracker import RefreshTracker
 from servlet import Servlet, Response
 
 
-class EnqueueServlet(Servlet):
-  '''This Servlet can be used to manually enqueue tasks on the default
-  taskqueue. Useful for when an admin wants to manually force a specific
-  DataSource refresh, but the refresh operation takes longer than the 60 sec
-  timeout of a non-taskqueue request. For example, you might query
+# This is the service account ID associated with the chrome-apps-doc project in
+# the Google Developers Console.
+_SERVICE_ACCOUNT_NAME = '636061184119-compute@developer.gserviceaccount.com'
 
-  /_enqueue/_refresh/content_providers/cr-native-client?commit=123ff65468dcafff0
-
-  which will enqueue a task (/_refresh/content_providers/cr-native-client) to
-  refresh the NaCl documentation cache for commit 123ff65468dcafff0.
-
-  Access to this servlet should always be restricted to administrative users.
-  '''
-  def __init__(self, request):
-    Servlet.__init__(self, request)
-
-  def Get(self):
-    queue = taskqueue.Queue()
-    queue.add(taskqueue.Task(url='/%s' % self._request.path,
-                             params=self._request.arguments))
-    return Response.Ok('Task enqueued.')
+# This is Google's OAuth2 service for retrieving user information from an access
+# token. It is used to authenticate an incoming access token in the metadata
+# flush servlet, ensuring that only requests from the above service account are
+# fulfilled.
+_ACCOUNT_INFO_URL = ('https://www.googleapis.com/oauth2/v1/userinfo?'
+                     'access_token=%s')
 
 
 class QueryCommitServlet(Servlet):
@@ -65,47 +58,78 @@
         All((id_future, history_future)).Then(generate_response).Get())
 
 
-class DumpRefreshServlet(Servlet):
-  def __init__(self, request):
-    Servlet.__init__(self, request)
+class FlushMemcacheServlet(Servlet):
+  '''Flushes the entire memcache.
 
-  def Get(self):
-    object_store_creator = ObjectStoreCreator(start_empty=False)
-    refresh_tracker = RefreshTracker(object_store_creator)
-    commit_id = self._request.path
-    work_order = refresh_tracker._GetWorkOrder(commit_id).Get()
-    task_names = ['%s@%s' % (commit_id, task) for task in work_order.tasks]
-    completions = refresh_tracker._task_completions.GetMulti(task_names).Get()
-    missing = []
-    for task in task_names:
-      if task not in completions:
-        missing.append(task)
-    response = 'Missing:<br>%s' % ''.join('%s<br>' % task for task in missing)
-    return Response.Ok(response)
-
-class ResetCommitServlet(Servlet):
-  '''Writes a new commit ID to the commit cache. For example:
-
-  /_reset_commit/master/123456
-
-  will reset the 'master' commit ID to '123456'. The provided commit MUST be
-  in the named commit's recent history or it will be ignored.
+  This requires an access token for the project's main service account. Without
+  said token, the request is considered invalid.
   '''
 
   class Delegate(object):
-    def CreateCommitTracker(self):
-      return CommitTracker(ObjectStoreCreator(start_empty=False))
+    def IsAuthorized(self, access_token):
+      '''Verifies that a given access_token represents the main service account.
+      '''
+      fetcher = CreateUrlFetcher()
+      response = fetcher.Fetch(_ACCOUNT_INFO_URL % access_token)
+      if response.status_code != 200:
+        return False
+      try:
+        info = json.loads(response.content)
+      except:
+        return False
+      return info['email'] == _SERVICE_ACCOUNT_NAME
 
   def __init__(self, request, delegate=Delegate()):
     Servlet.__init__(self, request)
     self._delegate = delegate
 
-  def Get(self):
-    commit_tracker = self._delegate.CreateCommitTracker()
-    commit_name, commit_id = self._request.path.split('/', 1)
-    history = commit_tracker.GetHistory(commit_name).Get()
-    if not any(entry.commit_id == commit_id for entry in history):
-      return Response.BadRequest('Commit %s not cached.' % commit_id)
-    commit_tracker.Set(commit_name, commit_id).Get()
-    return Response.Ok('Commit "%s" updated to %s' % (commit_name, commit_id))
+  def GetAccessToken(self):
+    auth_header = self._request.headers.get('Authorization')
+    if not auth_header:
+      return None
+    try:
+      method, token = auth_header.split(' ', 1)
+    except:
+      return None
+    if method != 'Bearer':
+      return None
+    return token
 
+  def Get(self):
+    access_token = self.GetAccessToken()
+    if not access_token:
+      return Response.Unauthorized('Unauthorized', 'Bearer', 'update')
+    if not self._delegate.IsAuthorized(access_token):
+      return Response.Forbidden('Forbidden')
+    result = memcache.flush_all()
+    return Response.Ok('Flushed: %s' % result)
+
+
+class UpdateCacheServlet(Servlet):
+  '''Devserver-only servlet for pushing local file data into the datastore.
+  This is useful if you've used update_cache.py to build a local datastore
+  for testing. Query:
+
+      /_update_cache/FOO_DATA
+
+  to make the devserver read FOO_DATA from its pwd and push all the data into
+  datastore.
+  '''
+  def __init__(self, request):
+    Servlet.__init__(self, request)
+
+  def Get(self):
+    if not IsDevServer():
+      return Response.BadRequest('')
+    import cPickle
+    from persistent_object_store_appengine import PersistentObjectStoreAppengine
+    with open(self._request.path, 'r') as f:
+      data = cPickle.load(f)
+    for namespace, contents in data.iteritems():
+      store = PersistentObjectStoreAppengine(namespace)
+      for k, v in cPickle.loads(contents).iteritems():
+        try:
+          store.Set(k, v).Get()
+        except:
+          logging.warn('Skipping entry %s because of errors.' % k)
+    return Response.Ok('Data pushed!')
diff --git a/chrome/common/extensions/docs/server2/admin_servlets_test.py b/chrome/common/extensions/docs/server2/admin_servlets_test.py
deleted file mode 100755
index 3fe9535..0000000
--- a/chrome/common/extensions/docs/server2/admin_servlets_test.py
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/usr/bin/env python
-# 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 unittest
-
-from admin_servlets import ResetCommitServlet
-from commit_tracker import CommitTracker
-from object_store_creator import ObjectStoreCreator
-from servlet import Request
-
-
-_COMMIT_HISTORY_DATA = (
-  '1234556789abcdef1234556789abcdef12345567',
-  'f00f00f00f00f00f00f00f00f00f00f00f00f00f',
-  '1010101010101010101010101010101010101010',
-  'abcdefabcdefabcdefabcdefabcdefabcdefabcd',
-  '4242424242424242424242424242424242424242',
-)
-
-
-class _ResetCommitDelegate(ResetCommitServlet.Delegate):
-  def __init__(self, commit_tracker):
-    self._commit_tracker = commit_tracker
-
-  def CreateCommitTracker(self):
-    return self._commit_tracker
-
-
-class AdminServletsTest(unittest.TestCase):
-  def setUp(self):
-    object_store_creator = ObjectStoreCreator(start_empty=True)
-    self._commit_tracker = CommitTracker(object_store_creator)
-    for id in _COMMIT_HISTORY_DATA:
-      self._commit_tracker.Set('master', id).Get()
-
-  def _ResetCommit(self, commit_name, commit_id):
-    return ResetCommitServlet(
-        Request.ForTest('%s/%s' % (commit_name, commit_id)),
-        _ResetCommitDelegate(self._commit_tracker)).Get()
-
-  def _AssertBadRequest(self, commit_name, commit_id):
-    response = self._ResetCommit(commit_name, commit_id)
-    self.assertEqual(response.status, 400,
-        'Should have failed to reset to commit %s to %s.' %
-        (commit_name, commit_id))
-
-  def _AssertOk(self, commit_name, commit_id):
-    response = self._ResetCommit(commit_name, commit_id)
-    self.assertEqual(response.status, 200,
-        'Failed to reset commit %s to %s.' % (commit_name, commit_id))
-
-  def testResetCommitServlet(self):
-    # Make sure all the valid commits can be used for reset.
-    for id in _COMMIT_HISTORY_DATA:
-      self._AssertOk('master', id)
-
-    # Non-existent commit should fail to update
-    self._AssertBadRequest('master',
-                           'b000000000000000000000000000000000000000')
-
-    # Commit 'master' should still point to the last valid entry
-    self.assertEqual(self._commit_tracker.Get('master').Get(),
-                     _COMMIT_HISTORY_DATA[-1])
-
-    # Reset to a valid commit but older
-    self._AssertOk('master', _COMMIT_HISTORY_DATA[0])
-
-    # Commit 'master' should point to the first history entry
-    self.assertEqual(self._commit_tracker.Get('master').Get(),
-                     _COMMIT_HISTORY_DATA[0])
-
-    # Add a new entry to the history and validate that it can be used for reset.
-    _NEW_ENTRY = '9999999999999999999999999999999999999999'
-    self._commit_tracker.Set('master', _NEW_ENTRY).Get()
-    self._AssertOk('master', _NEW_ENTRY)
-
-    # Add a bunch (> 50) of entries to ensure that _NEW_ENTRY has been flushed
-    # out of the history.
-    for i in xrange(0, 20):
-      for id in _COMMIT_HISTORY_DATA:
-        self._commit_tracker.Set('master', id).Get()
-
-    # Verify that _NEW_ENTRY is no longer valid for reset.
-    self._AssertBadRequest('master', _NEW_ENTRY)
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/chrome/common/extensions/docs/server2/api_data_source.py b/chrome/common/extensions/docs/server2/api_data_source.py
index 98408a3e..67004e9c 100644
--- a/chrome/common/extensions/docs/server2/api_data_source.py
+++ b/chrome/common/extensions/docs/server2/api_data_source.py
@@ -8,7 +8,7 @@
 from docs_server_utils import StringIdentity
 from environment import IsPreviewServer
 from file_system import FileNotFoundError
-from future import Future, All
+from future import All, Future
 from jsc_view import CreateJSCView, GetEventByNameFromEvents
 from platform_util import GetPlatforms
 from third_party.json_schema_compiler.model import UnixName
@@ -85,16 +85,14 @@
     getter.get = lambda api_name: self._GetSchemaView(platform, api_name).Get()
     return getter
 
-  def GetRefreshPaths(self):
-    tasks = []
-    for platform in GetPlatforms():
-      tasks += ['%s/%s' % (platform, UnixName(api))
-                for api in
-                    self._platform_bundle.GetAPIModels(platform).GetNames()]
-    return tasks
+  def Refresh(self):
+    def get_api_schema(platform, api):
+      return self._GetSchemaView(platform, api)
 
-  def Refresh(self, path):
-    platform, api = path.split('/')
-    logging.info('Refreshing %s/%s' % (platform, api))
-    future = self._GetSchemaView(platform, api)
-    return All([future], except_pass=FileNotFoundError)
+    def get_platform_schemas(platform):
+      return All([get_api_schema(platform, api)
+                 for api in self._platform_bundle.GetAPIModels(platform)
+                    .GetNames()],
+                 except_pass=FileNotFoundError)
+
+    return All([get_platform_schemas(platform) for platform in GetPlatforms()])
diff --git a/chrome/common/extensions/docs/server2/api_list_data_source.py b/chrome/common/extensions/docs/server2/api_list_data_source.py
index 13c064a..009ad7fe 100644
--- a/chrome/common/extensions/docs/server2/api_list_data_source.py
+++ b/chrome/common/extensions/docs/server2/api_list_data_source.py
@@ -119,5 +119,5 @@
   def get(self, key):
     return self._GetCachedAPIData().Get().get(key)
 
-  def Refresh(self, path):
+  def Refresh(self):
     return self._GetCachedAPIData()
diff --git a/chrome/common/extensions/docs/server2/api_models.py b/chrome/common/extensions/docs/server2/api_models.py
index dea2ebd..31c8a075 100644
--- a/chrome/common/extensions/docs/server2/api_models.py
+++ b/chrome/common/extensions/docs/server2/api_models.py
@@ -42,7 +42,8 @@
     return not (self == o)
 
   def __repr__(self):
-    return '<ContentScriptAPI name=%s, restrictedTo=%s>' % (name, restrictedTo)
+    return ('<ContentScriptAPI name=%s, restrictedTo=%s>' %
+            (self.name, self.restrictedTo))
 
   def __str__(self):
     return repr(self)
diff --git a/chrome/common/extensions/docs/server2/app.yaml b/chrome/common/extensions/docs/server2/app.yaml
index b68ad8c..006e8d3 100644
--- a/chrome/common/extensions/docs/server2/app.yaml
+++ b/chrome/common/extensions/docs/server2/app.yaml
@@ -1,5 +1,5 @@
 application: chrome-apps-doc
-version: 3-49-0
+version: 3-50-0
 runtime: python27
 api_version: 1
 threadsafe: false
@@ -14,18 +14,9 @@
 - url: /apple-touch-icon-precomposed\.png
   static_files: chrome-128.png
   upload: chrome-128.png
-- url: /_refresh/.*
+- url: /_flush_memcache/.*
   script: appengine_main.py
   secure: always
-  login: admin
-- url: /_enqueue/.*
-  script: appengine_main.py
-  secure: always
-  login: admin
-- url: /_reset_commit/.*
-  script: appengine_main.py
-  secure: always
-  login: admin
 - url: /.*
   script: appengine_main.py
   secure: always
diff --git a/chrome/common/extensions/docs/server2/app_engine_handler.py b/chrome/common/extensions/docs/server2/app_engine_handler.py
index 8ea30b9..14bcdf3b 100644
--- a/chrome/common/extensions/docs/server2/app_engine_handler.py
+++ b/chrome/common/extensions/docs/server2/app_engine_handler.py
@@ -3,8 +3,8 @@
 # found in the LICENSE file.
 
 import logging
+import webapp2
 
-from appengine_wrappers import webapp2
 from handler import Handler
 from servlet import Request
 
diff --git a/chrome/common/extensions/docs/server2/appengine_wrappers.py b/chrome/common/extensions/docs/server2/appengine_wrappers.py
index 18542bd..f477e53 100644
--- a/chrome/common/extensions/docs/server2/appengine_wrappers.py
+++ b/chrome/common/extensions/docs/server2/appengine_wrappers.py
@@ -2,57 +2,12 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-def IsDeadlineExceededError(error):
-  '''A general way of determining whether |error| is a DeadlineExceededError,
-  since there are 3 different types thrown by AppEngine and we might as well
-  handle them all the same way. For more info see:
-  https://developers.google.com/appengine/articles/deadlineexceedederrors
-  '''
-  return type(error).__name__ == 'DeadlineExceededError'
-
-
-def IsDownloadError(error):
-  return type(error).__name__ == 'DownloadError'
-
 
 # This will attempt to import the actual App Engine modules, and if it fails,
 # they will be replaced with fake modules. This is useful during testing.
 try:
-  import google.appengine.api.app_identity as app_identity
-  import google.appengine.api.files as files
-  import google.appengine.api.logservice as logservice
   import google.appengine.api.memcache as memcache
-  import google.appengine.api.taskqueue as taskqueue
-  import google.appengine.api.urlfetch as urlfetch
-  import google.appengine.ext.blobstore as blobstore
-  from google.appengine.ext.blobstore.blobstore import BlobReferenceProperty
-  import google.appengine.ext.db as db
-  import webapp2
 except ImportError:
-  import re
-  from StringIO import StringIO
-
-  FAKE_URL_FETCHER_CONFIGURATION = None
-
-  def ConfigureFakeUrlFetch(configuration):
-    """|configuration| is a dictionary mapping strings to fake urlfetch classes.
-    A fake urlfetch class just needs to have a fetch method. The keys of the
-    dictionary are treated as regex, and they are matched with the URL to
-    determine which fake urlfetch is used.
-    """
-    global FAKE_URL_FETCHER_CONFIGURATION
-    FAKE_URL_FETCHER_CONFIGURATION = dict(
-        (re.compile(k), v) for k, v in configuration.iteritems())
-
-  def _GetConfiguration(key):
-    if not FAKE_URL_FETCHER_CONFIGURATION:
-      raise ValueError('No fake fetch paths have been configured. '
-                       'See ConfigureFakeUrlFetch in appengine_wrappers.py.')
-    for k, v in FAKE_URL_FETCHER_CONFIGURATION.iteritems():
-      if k.match(key):
-        return v
-    raise ValueError('No configuration found for %s' % key)
-
   class _RPC(object):
     def __init__(self, result=None):
       self.result = result
@@ -63,100 +18,6 @@
     def wait(self):
       pass
 
-  class FakeAppIdentity(object):
-    """A fake app_identity module that returns no access tokens."""
-    def get_access_token(self, scope):
-      return (None, None)
-  app_identity = FakeAppIdentity()
-
-  class FakeUrlFetch(object):
-    """A fake urlfetch module that uses the current
-    |FAKE_URL_FETCHER_CONFIGURATION| to map urls to fake fetchers.
-    """
-    class DownloadError(Exception):
-      pass
-
-    class _Response(object):
-      def __init__(self, content):
-        self.content = content
-        self.headers = {'Content-Type': 'none'}
-        self.status_code = 200
-
-    def fetch(self, url, **kwargs):
-      url = url.split('?', 1)[0]
-      response = self._Response(_GetConfiguration(url).fetch(url))
-      if response.content is None:
-        response.status_code = 404
-      return response
-
-    def create_rpc(self, **kwargs):
-      return _RPC()
-
-    def make_fetch_call(self, rpc, url, **kwargs):
-      rpc.result = self.fetch(url)
-  urlfetch = FakeUrlFetch()
-
-  _BLOBS = {}
-  class FakeBlobstore(object):
-    class BlobNotFoundError(Exception):
-      pass
-
-    class BlobReader(object):
-      def __init__(self, blob_key):
-        self._data = _BLOBS[blob_key].getvalue()
-
-      def read(self):
-        return self._data
-
-  blobstore = FakeBlobstore()
-
-  class FakeFileInterface(object):
-    """This class allows a StringIO object to be used in a with block like a
-    file.
-    """
-    def __init__(self, io):
-      self._io = io
-
-    def __exit__(self, *args):
-      pass
-
-    def write(self, data):
-      self._io.write(data)
-
-    def __enter__(self, *args):
-      return self._io
-
-  class FakeFiles(object):
-    _next_blobstore_key = 0
-    class blobstore(object):
-      @staticmethod
-      def create():
-        FakeFiles._next_blobstore_key += 1
-        return FakeFiles._next_blobstore_key
-
-      @staticmethod
-      def get_blob_key(filename):
-        return filename
-
-    def open(self, filename, mode):
-      _BLOBS[filename] = StringIO()
-      return FakeFileInterface(_BLOBS[filename])
-
-    def GetBlobKeys(self):
-      return _BLOBS.keys()
-
-    def finalize(self, filename):
-      pass
-
-  files = FakeFiles()
-
-  class Logservice(object):
-    AUTOFLUSH_ENABLED = True
-
-    def flush(self):
-      pass
-
-  logservice = Logservice()
 
   class InMemoryMemcache(object):
     """An in-memory memcache implementation.
@@ -192,122 +53,8 @@
         self._namespaces[namespace] = {}
       return self._namespaces[namespace]
 
+    def flush_all(self):
+      self._namespaces = {}
+      return False
+
   memcache = InMemoryMemcache()
-
-  class webapp2(object):
-    class RequestHandler(object):
-      """A fake webapp2.RequestHandler class for Handler to extend.
-      """
-      def __init__(self, request, response):
-        self.request = request
-        self.response = response
-        self.response.status = 200
-
-      def redirect(self, path, permanent=False):
-        self.response.status = 301 if permanent else 302
-        self.response.headers['Location'] = path
-
-  class _Db_Result(object):
-    def __init__(self, data):
-      self._data = data
-
-    class _Result(object):
-      def __init__(self, value):
-        self.value = value
-
-    def get(self):
-      return self._Result(self._data)
-
-  class db(object):
-    _store = {}
-
-    class StringProperty(object):
-      pass
-
-    class BlobProperty(object):
-      pass
-
-    class Key(object):
-      def __init__(self, key):
-        self._key = key
-
-      @staticmethod
-      def from_path(model_name, path):
-        return db.Key('%s/%s' % (model_name, path))
-
-      def __eq__(self, obj):
-        return self.__class__ == obj.__class__ and self._key == obj._key
-
-      def __hash__(self):
-        return hash(self._key)
-
-      def __str__(self):
-        return str(self._key)
-
-    class Model(object):
-      key = None
-
-      def __init__(self, **optargs):
-        cls = self.__class__
-        for k, v in optargs.iteritems():
-          assert hasattr(cls, k), '%s does not define property %s' % (
-              cls.__name__, k)
-          setattr(self, k, v)
-
-      @staticmethod
-      def gql(query, key):
-        return _Db_Result(db._store.get(key))
-
-      def put(self):
-        db._store[self.key_] = self.value
-
-    @staticmethod
-    def get_async(key):
-      return _RPC(result=db._store.get(key))
-
-    @staticmethod
-    def delete_async(key):
-      db._store.pop(key, None)
-      return _RPC()
-
-    @staticmethod
-    def put_async(value):
-      db._store[value.key] = value
-      return _RPC()
-
-  class BlobReferenceProperty(object):
-    pass
-
-  # Executes any queued tasks synchronously as they are queued.
-  _task_runner = None
-
-  def SetTaskRunnerForTest(task_runner):
-    global _task_runner
-    _task_runner = task_runner
-
-  class SynchronousTaskQueue(object):
-    class Task(object):
-      def __init__(self, url=None, params={}):
-        self.url_ = url
-        self.params_ = params
-
-      def GetUrl(self):
-        return self.url_
-
-      def GetCommit(self):
-        return self.params_.get('commit')
-
-    class Queue(object):
-      def __init__(self, name='default'):
-        pass
-
-      def add(self, task):
-        global _task_runner
-        if _task_runner:
-          _task_runner(task.GetUrl(), task.GetCommit())
-        return _RPC()
-
-      def purge(self):
-        return _RPC()
-
-  taskqueue = SynchronousTaskQueue()
diff --git a/chrome/common/extensions/docs/server2/branch_utility.py b/chrome/common/extensions/docs/server2/branch_utility.py
index 3c0a1e30..955cfbb 100644
--- a/chrome/common/extensions/docs/server2/branch_utility.py
+++ b/chrome/common/extensions/docs/server2/branch_utility.py
@@ -6,7 +6,7 @@
 import logging
 import operator
 
-from appengine_url_fetcher import AppEngineUrlFetcher
+from environment_wrappers import CreateUrlFetcher
 import url_constants
 
 
@@ -60,7 +60,7 @@
   def Create(object_store_creator):
     return BranchUtility(url_constants.OMAHA_PROXY_URL,
                          url_constants.OMAHA_DEV_HISTORY,
-                         AppEngineUrlFetcher(),
+                         CreateUrlFetcher(),
                          object_store_creator)
 
   @staticmethod
diff --git a/chrome/common/extensions/docs/server2/caching_file_system.py b/chrome/common/extensions/docs/server2/caching_file_system.py
index 65b3dab4..c8bfe42 100644
--- a/chrome/common/extensions/docs/server2/caching_file_system.py
+++ b/chrome/common/extensions/docs/server2/caching_file_system.py
@@ -16,31 +16,19 @@
   '''FileSystem which implements a caching layer on top of |file_system|. If
   |fail_on_miss| is True then cache misses throw a FileNotFoundError rather than
   falling back onto the underlying FileSystem.
-
-  If the underlying FileSystem is versioned (i.e., it implements GetVersion to
-  return something other than None), this will create a persistent stat cache
-  (keyed on the FileSystem instance's version) as an additional optimization.
   '''
   def __init__(self, file_system, object_store_creator, fail_on_miss=False):
     self._file_system = file_system
     self._fail_on_miss = fail_on_miss
-    def create_object_store(category, try_versioning=False, **optargs):
-      version = file_system.GetVersion()
-      versioned = try_versioning and version is not None
-      if versioned:
-        identity = '%s/%s' % (file_system.GetIdentity(), version)
-      else:
-        identity = file_system.GetIdentity()
-      optargs['start_empty'] = optargs.get('start_empty', not versioned)
+    def create_object_store(category, start_empty=True):
       return object_store_creator.Create(
           CachingFileSystem,
-          category='%s/%s' % (identity, category),
-          **optargs)
-    self._stat_cache = create_object_store('stat', try_versioning=True)
-    # The read caches can start populated (start_empty=False) because file
-    # updates are picked up by the stat, so it doesn't need the force-refresh
-    # which starting empty is designed for. Without this optimisation, cron
-    # runs are extra slow.
+          category='%s/%s' % (file_system.GetIdentity(), category),
+          start_empty=start_empty)
+    # We only start the stat cache empty if |fail_on_miss| is False, i.e. if
+    # we're NOT running on a live instance and we can afford to fall back onto
+    # the underlying FileSystem impl.
+    self._stat_cache = create_object_store('stat', start_empty=not fail_on_miss)
     self._read_cache = create_object_store('read', start_empty=False)
     self._walk_cache = create_object_store('walk', start_empty=False)
 
@@ -77,7 +65,8 @@
       return Future(callback=lambda: make_stat_info(dir_stat))
 
     if self._fail_on_miss:
-      logging.warning('Bailing on stat cache miss for %s' % dir_path)
+      logging.warning('Bailing on stat cache miss for %s on %s' %
+                      (dir_path, self.GetIdentity()))
       return Future(callback=lambda: raise_cache_miss(dir_path))
 
     def next(dir_stat):
@@ -141,10 +130,20 @@
       paths = [path for path in paths
                if cached_read_values.get(path, (None, True))[1]]
 
-    if len(up_to_date_data) == len(paths):
+    remaining_paths = set(paths) - set(up_to_date_data.iterkeys())
+    if len(remaining_paths) == 0:
       # Everything was cached and up-to-date.
       return Future(value=up_to_date_data)
 
+    def raise_cache_miss(paths):
+      raise FileNotFoundError('Got cache miss when trying to stat %s' % paths)
+
+    if self._fail_on_miss:
+      # Ignore missing values and return anyway.
+      logging.warn('Read cache miss for %s on %s' %
+                   (remaining_paths, self.GetIdentity()))
+      return Future(callback=lambda: raise_cache_miss(remaining_paths))
+
     def next(new_results):
       # Update the cache. This is a path -> (data, version) mapping.
       self._read_cache.SetMulti(
@@ -157,8 +156,9 @@
                if stat_futures[path].Get() is None))
       new_results.update(up_to_date_data)
       return new_results
+
     # Read in the values that were uncached or old.
-    return self._file_system.Read(set(paths) - set(up_to_date_data.iterkeys()),
+    return self._file_system.Read(remaining_paths,
                                   skip_not_found=skip_not_found).Then(next)
 
   def GetCommitID(self):
diff --git a/chrome/common/extensions/docs/server2/caching_file_system_test.py b/chrome/common/extensions/docs/server2/caching_file_system_test.py
index 45ce024..51d063c 100755
--- a/chrome/common/extensions/docs/server2/caching_file_system_test.py
+++ b/chrome/common/extensions/docs/server2/caching_file_system_test.py
@@ -292,26 +292,6 @@
     # TODO(ahernandez): Test with a new instance CachingFileSystem so a
     # different object store is utilized.
 
-  def testVersionedStat(self):
-    test_fs = TestFileSystem({
-      'bob': {
-        'bob0': 'bob/bob0 contents',
-        'bob1': 'bob/bob1 contents'
-      }
-    })
-
-    # Create a versioned FileSystem and verify that multiple CachingFileSystem
-    # instances wrapping it will share the same stat cache.
-    mock_fs = MockFileSystem(test_fs)
-    mock_fs.SetVersion('abcdefg')
-
-    def run_and_expect_stat_count(paths, stat_count=0):
-      file_system = self._CreateCachingFileSystem(mock_fs, start_empty=True)
-      [file_system.Stat(path) for path in paths]
-      self.assertTrue(*mock_fs.CheckAndReset(stat_count=stat_count))
-
-    run_and_expect_stat_count(['bob/', 'bob/bob0', 'bob/bob1'], stat_count=1)
-    run_and_expect_stat_count(['bob/', 'bob/bob0', 'bob/bob1'], stat_count=0)
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/chrome/common/extensions/docs/server2/content_provider.py b/chrome/common/extensions/docs/server2/content_provider.py
index 96281cff..baa779c 100644
--- a/chrome/common/extensions/docs/server2/content_provider.py
+++ b/chrome/common/extensions/docs/server2/content_provider.py
@@ -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 logging
 import mimetypes
 import posixpath
 import traceback
@@ -80,31 +81,35 @@
   @SingleFile
   def _CompileContent(self, path, text):
     assert text is not None, path
-    _, ext = posixpath.splitext(path)
-    mimetype = _MIMETYPE_OVERRIDES.get(ext, mimetypes.guess_type(path)[0])
-    if ext == '.md':
-      # See http://pythonhosted.org/Markdown/extensions
-      # for details on "extensions=".
-      content = markdown(ToUnicode(text),
-                         extensions=('extra', 'headerid', 'sane_lists'))
-      if self._supports_templates:
-        content = Motemplate(content, name=path)
-      mimetype = 'text/html'
-    elif mimetype is None:
-      content = text
-      mimetype = 'text/plain'
-    elif mimetype == 'text/html':
-      content = ToUnicode(text)
-      if self._supports_templates:
-        content = Motemplate(content, name=path)
-    elif (mimetype.startswith('text/') or
-          mimetype in ('application/javascript', 'application/json')):
-      content = ToUnicode(text)
-    else:
-      content = text
-    return ContentAndType(content,
-                          mimetype,
-                          self.file_system.Stat(path).version)
+    try:
+      _, ext = posixpath.splitext(path)
+      mimetype = _MIMETYPE_OVERRIDES.get(ext, mimetypes.guess_type(path)[0])
+      if ext == '.md':
+        # See http://pythonhosted.org/Markdown/extensions
+        # for details on "extensions=".
+        content = markdown(ToUnicode(text),
+                           extensions=('extra', 'headerid', 'sane_lists'))
+        mimetype = 'text/html'
+        if self._supports_templates:
+          content = Motemplate(content, name=path)
+      elif mimetype is None:
+        content = text
+        mimetype = 'text/plain'
+      elif mimetype == 'text/html':
+        content = ToUnicode(text)
+        if self._supports_templates:
+          content = Motemplate(content, name=path)
+      elif (mimetype.startswith('text/') or
+            mimetype in ('application/javascript', 'application/json')):
+        content = ToUnicode(text)
+      else:
+        content = text
+      return ContentAndType(content,
+                            mimetype,
+                            self.file_system.Stat(path).version)
+    except Exception as e:
+      logging.warn('In file %s: %s' % (path, e.message))
+      return ContentAndType('', mimetype, self.file_system.Stat(path).version)
 
   def GetCanonicalPath(self, path):
     '''Gets the canonical location of |path|. This class is tolerant of
diff --git a/chrome/common/extensions/docs/server2/content_providers.py b/chrome/common/extensions/docs/server2/content_providers.py
index e520017..65009f0 100644
--- a/chrome/common/extensions/docs/server2/content_providers.py
+++ b/chrome/common/extensions/docs/server2/content_providers.py
@@ -10,8 +10,7 @@
 from content_provider import ContentProvider
 import environment
 from extensions_paths import CONTENT_PROVIDERS, LOCAL_DEBUG_DIR
-from future import Future
-from gitiles_file_system import GitilesFileSystem
+from future import All, Future
 from local_file_system import LocalFileSystem
 from third_party.json_schema_compiler.memoize import memoize
 
@@ -44,12 +43,10 @@
                object_store_creator,
                compiled_fs_factory,
                host_file_system,
-               github_file_system_provider,
                gcs_file_system_provider):
     self._object_store_creator = object_store_creator
     self._compiled_fs_factory = compiled_fs_factory
     self._host_file_system = host_file_system
-    self._github_file_system_provider = github_file_system_provider
     self._gcs_file_system_provider = gcs_file_system_provider
     self._cache = None
 
@@ -148,16 +145,6 @@
       if 'dir' in gcs_config:
         file_system = ChrootFileSystem(file_system, gcs_config['dir'])
 
-    elif 'github' in config:
-      github_config = config['github']
-      if 'owner' not in github_config or 'repo' not in github_config:
-        logging.error('%s: "github" must provide an "owner" and "repo"' % name)
-        return None
-      file_system = self._github_file_system_provider.Create(
-          github_config['owner'], github_config['repo'])
-      if 'dir' in github_config:
-        file_system = ChrootFileSystem(file_system, github_config['dir'])
-
     else:
       logging.error('%s: content provider type not supported' % name)
       return None
@@ -170,10 +157,7 @@
                            supports_templates=supports_templates,
                            supports_zip=supports_zip)
 
-  def GetRefreshPaths(self):
-    return self._GetConfig().keys()
-
-  def Refresh(self, path):
+  def Refresh(self):
     def safe(name, action, callback):
       '''Safely runs |callback| for a ContentProvider called |name| by
       swallowing exceptions and turning them into a None return value. It's
@@ -187,11 +171,14 @@
                         (action, name, traceback.format_exc()))
         return None
 
-    config = self._GetConfig()[path]
-    provider = self._CreateContentProvider(path, config)
-    future = safe(path,
-                  'initializing',
-                  self._CreateContentProvider(path, config).Refresh)
-    if future is None:
-      return Future(callback=lambda: True)
-    return Future(callback=lambda: safe(path, 'resolving', future.Get))
+    def refresh_provider(path, config):
+      provider = self._CreateContentProvider(path, config)
+      future = safe(path,
+                    'initializing',
+                    self._CreateContentProvider(path, config).Refresh)
+      if future is None:
+        return Future(callback=lambda: True)
+      return Future(callback=lambda: safe(path, 'resolving', future.Get))
+
+    return All(refresh_provider(path, config)
+               for path, config in self._GetConfig().iteritems())
diff --git a/chrome/common/extensions/docs/server2/content_providers_test.py b/chrome/common/extensions/docs/server2/content_providers_test.py
index 44d3c75..106969e 100755
--- a/chrome/common/extensions/docs/server2/content_providers_test.py
+++ b/chrome/common/extensions/docs/server2/content_providers_test.py
@@ -112,7 +112,6 @@
         object_store_creator,
         CompiledFileSystem.Factory(object_store_creator),
         test_file_system,
-        self._github_fs_provider,
         self._gcs_fs_provider)
 
   def testSimpleRootPath(self):
@@ -183,29 +182,31 @@
   def testProviderNotFound(self):
     self.assertEqual(None, self._content_providers.GetByName('cabbages'))
 
-  def testGithubContentProvider(self):
-    provider, serve_from, path = self._content_providers.GetByServeFrom(
-        'gh/apples/green/granny smith.txt')
-    self.assertEqual('github-provider', provider.name)
-    self.assertEqual('gh', serve_from)
-    self.assertEqual('apples/green/granny smith.txt', path)
-    self.assertEqual([('GoogleChrome', 'hello-world')],
-                     self._github_fs_provider.GetAndReset())
-    self.assertEqual(
-        'granny smith apples',
-        provider.GetContentAndType(path).Get().content)
+  # TODO: Re-enable these Github tests if we ever decide to restore our support
+  # for Github content providers.
+  # def testGithubContentProvider(self):
+  #   provider, serve_from, path = self._content_providers.GetByServeFrom(
+  #       'gh/apples/green/granny smith.txt')
+  #   self.assertEqual('github-provider', provider.name)
+  #   self.assertEqual('gh', serve_from)
+  #   self.assertEqual('apples/green/granny smith.txt', path)
+  #   self.assertEqual([('GoogleChrome', 'hello-world')],
+  #                    self._github_fs_provider.GetAndReset())
+  #   self.assertEqual(
+  #       'granny smith apples',
+  #       provider.GetContentAndType(path).Get().content)
 
-  def testGithubContentProviderWithDir(self):
-    provider, serve_from, path = self._content_providers.GetByServeFrom(
-        'gh2/fruit/cherry.txt')
-    self.assertEqual('github-provider-with-dir', provider.name)
-    self.assertEqual('gh2', serve_from)
-    self.assertEqual('fruit/cherry.txt', path)
-    self.assertEqual([('SomeOwner', 'some-repo')],
-                     self._github_fs_provider.GetAndReset())
-    self.assertEqual(
-        'cherry tomatoes',
-        provider.GetContentAndType(path).Get().content)
+  # def testGithubContentProviderWithDir(self):
+  #   provider, serve_from, path = self._content_providers.GetByServeFrom(
+  #       'gh2/fruit/cherry.txt')
+  #   self.assertEqual('github-provider-with-dir', provider.name)
+  #   self.assertEqual('gh2', serve_from)
+  #   self.assertEqual('fruit/cherry.txt', path)
+  #   self.assertEqual([('SomeOwner', 'some-repo')],
+  #                    self._github_fs_provider.GetAndReset())
+  #   self.assertEqual(
+  #       'cherry tomatoes',
+  #       provider.GetContentAndType(path).Get().content)
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/chrome/common/extensions/docs/server2/cron.yaml b/chrome/common/extensions/docs/server2/cron.yaml
deleted file mode 100644
index b72ccff..0000000
--- a/chrome/common/extensions/docs/server2/cron.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-cron:
-- description: Repopulates all cached data.
-  url: /_cron
-  schedule: every 180 minutes
-  target: 3-49-0
diff --git a/chrome/common/extensions/docs/server2/cron_servlet.py b/chrome/common/extensions/docs/server2/cron_servlet.py
deleted file mode 100644
index 60e9831..0000000
--- a/chrome/common/extensions/docs/server2/cron_servlet.py
+++ /dev/null
@@ -1,204 +0,0 @@
-# Copyright 2013 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 time
-import traceback
-
-from app_yaml_helper import AppYamlHelper
-from appengine_wrappers import IsDeadlineExceededError, logservice, taskqueue
-from branch_utility import BranchUtility
-from compiled_file_system import CompiledFileSystem
-from custom_logger import CustomLogger
-from data_source_registry import CreateDataSources
-from environment import GetAppVersion
-from gcs_file_system_provider import CloudStorageFileSystemProvider
-from github_file_system_provider import GithubFileSystemProvider
-from host_file_system_provider import HostFileSystemProvider
-from object_store_creator import ObjectStoreCreator
-from refresh_tracker import RefreshTracker
-from render_refresher import RenderRefresher
-from server_instance import ServerInstance
-from servlet import Servlet, Request, Response
-from timer import Timer
-
-
-_log = CustomLogger('cron')
-
-
-class CronServlet(Servlet):
-  '''Servlet which runs a cron job.
-  '''
-  def __init__(self, request, delegate_for_test=None):
-    Servlet.__init__(self, request)
-    self._delegate = delegate_for_test or CronServlet.Delegate()
-
-  class Delegate(object):
-    '''CronServlet's runtime dependencies. Override for testing.
-    '''
-    def CreateBranchUtility(self, object_store_creator):
-      return BranchUtility.Create(object_store_creator)
-
-    def CreateHostFileSystemProvider(self,
-                                     object_store_creator,
-                                     pinned_commit=None):
-      return HostFileSystemProvider(object_store_creator,
-                                    pinned_commit=pinned_commit)
-
-    def CreateGithubFileSystemProvider(self, object_store_creator):
-      return GithubFileSystemProvider(object_store_creator)
-
-    def CreateGCSFileSystemProvider(self, object_store_creator):
-      return CloudStorageFileSystemProvider(object_store_creator)
-
-    def GetAppVersion(self):
-      return GetAppVersion()
-
-  def Get(self):
-    # Refreshes may time out, and if they do we need to make sure to flush the
-    # logs before the process gets killed (Python gives us a couple of
-    # seconds).
-    #
-    # So, manually flush logs at the end of the cron run. However, sometimes
-    # even that isn't enough, which is why in this file we use _log and
-    # make it flush the log every time its used.
-    logservice.AUTOFLUSH_ENABLED = False
-    try:
-      return self._GetImpl()
-    except BaseException:
-      _log.error('Caught top-level exception! %s', traceback.format_exc())
-    finally:
-      logservice.flush()
-
-  def _GetImpl(self):
-    # Cron strategy:
-    #
-    # Collect all DataSources, the PlatformBundle, the ContentProviders, and
-    # any other statically renderered contents (e.g. examples content),
-    # and spin up taskqueue tasks which will refresh any cached data relevant
-    # to these assets.
-    #
-    # TODO(rockot/kalman): At the moment examples are not actually refreshed
-    # because they're too slow.
-
-    _log.info('starting')
-
-    server_instance = self._GetSafeServerInstance()
-    master_fs = server_instance.host_file_system_provider.GetMaster()
-    if 'commit' in self._request.arguments:
-      master_commit = self._request.arguments['commit']
-    else:
-      master_commit = master_fs.GetCommitID().Get()
-
-    # This is the guy that would be responsible for refreshing the cache of
-    # examples. Here for posterity, hopefully it will be added to the targets
-    # below someday.
-    render_refresher = RenderRefresher(server_instance, self._request)
-
-    # Used to register a new refresh cycle keyed on |master_commit|.
-    refresh_tracker = RefreshTracker(server_instance.object_store_creator)
-
-    # Get the default taskqueue
-    queue = taskqueue.Queue()
-
-    # GAE documentation specifies that it's bad to add tasks to a queue
-    # within one second of purging. We wait 2 seconds, because we like
-    # to go the extra mile.
-    queue.purge()
-    time.sleep(2)
-
-    success = True
-    try:
-      data_sources = CreateDataSources(server_instance)
-      targets = (data_sources.items() +
-                 [('content_providers', server_instance.content_providers),
-                  ('platform_bundle', server_instance.platform_bundle)])
-      title = 'initializing %s parallel targets' % len(targets)
-      _log.info(title)
-      timer = Timer()
-      tasks = []
-      for name, target in targets:
-        refresh_paths = target.GetRefreshPaths()
-        tasks += [('%s/%s' % (name, path)).strip('/') for path in refresh_paths]
-
-      # Start a new refresh cycle. In order to detect the completion of a full
-      # cache refresh, the RefreshServlet (which handles individual refresh
-      # tasks) will mark each task complete and check the set of completed tasks
-      # against the set registered here.
-      refresh_tracker.StartRefresh(master_commit, tasks).Get()
-      for task in tasks:
-        queue.add(taskqueue.Task(url='/_refresh/%s' % task,
-                                 params={'commit': master_commit}))
-
-      _log.info('%s took %s' % (title, timer.Stop().FormatElapsed()))
-    except:
-      # This should never actually happen (each cron step does its own
-      # conservative error checking), so re-raise no matter what it is.
-      _log.error('uncaught error: %s' % traceback.format_exc())
-      success = False
-      raise
-    finally:
-      _log.info('finished (%s)', 'success' if success else 'FAILED')
-      return (Response.Ok('Success') if success else
-              Response.InternalError('Failure'))
-
-  def _GetSafeServerInstance(self):
-    '''Returns a ServerInstance with a host file system at a safe commit,
-    meaning the last commit that the current running version of the server
-    existed.
-    '''
-    delegate = self._delegate
-
-    # IMPORTANT: Get a ServerInstance pinned to the most recent commit, not
-    # HEAD. These cron jobs take a while and run very frequently such that
-    # there is usually one running at any given time, and eventually a file
-    # that we're dealing with will change underneath it, putting the server in
-    # an undefined state.
-    server_instance_near_head = self._CreateServerInstance(
-        self._GetMostRecentCommit())
-
-    app_yaml_handler = AppYamlHelper(
-        server_instance_near_head.object_store_creator,
-        server_instance_near_head.host_file_system_provider)
-
-    if app_yaml_handler.IsUpToDate(delegate.GetAppVersion()):
-      return server_instance_near_head
-
-    # The version in app.yaml is greater than the currently running app's.
-    # The safe version is the one before it changed.
-    safe_revision = app_yaml_handler.GetFirstRevisionGreaterThan(
-        delegate.GetAppVersion()) - 1
-
-    _log.info('app version %s is out of date, safe is %s',
-        delegate.GetAppVersion(), safe_revision)
-
-    return self._CreateServerInstance(safe_revision)
-
-  def _GetMostRecentCommit(self):
-    '''Gets the commit of the most recent patch submitted to the host file
-    system. This is similar to HEAD but it's a concrete commit so won't
-    change as the cron runs.
-    '''
-    head_fs = (
-        self._CreateServerInstance(None).host_file_system_provider.GetMaster())
-    return head_fs.GetCommitID().Get()
-
-  def _CreateServerInstance(self, commit):
-    '''Creates a ServerInstance pinned to |commit|, or HEAD if None.
-    NOTE: If passed None it's likely that during the cron run patches will be
-    submitted at HEAD, which may change data underneath the cron run.
-    '''
-    object_store_creator = ObjectStoreCreator(start_empty=True)
-    branch_utility = self._delegate.CreateBranchUtility(object_store_creator)
-    host_file_system_provider = self._delegate.CreateHostFileSystemProvider(
-        object_store_creator, pinned_commit=commit)
-    github_file_system_provider = self._delegate.CreateGithubFileSystemProvider(
-        object_store_creator)
-    gcs_file_system_provider = self._delegate.CreateGCSFileSystemProvider(
-        object_store_creator)
-    return ServerInstance(object_store_creator,
-                          CompiledFileSystem.Factory(object_store_creator),
-                          branch_utility,
-                          host_file_system_provider,
-                          github_file_system_provider,
-                          gcs_file_system_provider)
diff --git a/chrome/common/extensions/docs/server2/cron_servlet_test.py b/chrome/common/extensions/docs/server2/cron_servlet_test.py
deleted file mode 100755
index dda11cb..0000000
--- a/chrome/common/extensions/docs/server2/cron_servlet_test.py
+++ /dev/null
@@ -1,268 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2013 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 unittest
-
-from app_yaml_helper import AppYamlHelper
-from content_providers import IgnoreMissingContentProviders
-from cron_servlet import CronServlet
-from empty_dir_file_system import EmptyDirFileSystem
-from environment import GetAppVersion
-from extensions_paths import (
-    APP_YAML, CONTENT_PROVIDERS, CHROME_EXTENSIONS, PUBLIC_TEMPLATES, SERVER2,
-    STATIC_DOCS)
-from fake_fetchers import ConfigureFakeFetchers
-from gcs_file_system_provider import CloudStorageFileSystemProvider
-from github_file_system_provider import GithubFileSystemProvider
-from host_file_system_provider import HostFileSystemProvider
-from local_file_system import LocalFileSystem
-from mock_file_system import MockFileSystem
-from servlet import Request
-from test_branch_utility import TestBranchUtility
-from test_file_system import MoveTo, TestFileSystem
-from test_util import EnableLogging, ReadFile
-
-
-# NOTE(kalman): The ObjectStore created by the CronServlet is backed onto our
-# fake AppEngine memcache/datastore, so the tests aren't isolated. Of course,
-# if the host file systems have different identities, they will be, sort of.
-class _TestDelegate(CronServlet.Delegate):
-  def __init__(self, create_file_system):
-    self.file_systems = []
-    # A callback taking a commit and returning a file system.
-    self._create_file_system = create_file_system
-    self._app_version = GetAppVersion()
-
-  def CreateBranchUtility(self, object_store_creator):
-    return TestBranchUtility.CreateWithCannedData()
-
-  def CreateHostFileSystemProvider(self,
-                                  object_store_creator,
-                                  pinned_commit=None):
-    def constructor(branch=None, commit=None):
-      file_system = self._create_file_system(commit)
-      self.file_systems.append(file_system)
-      return file_system
-    return HostFileSystemProvider(object_store_creator,
-                                  pinned_commit=pinned_commit,
-                                  constructor_for_test=constructor)
-
-  def CreateGithubFileSystemProvider(self, object_store_creator):
-    return GithubFileSystemProvider.ForEmpty()
-
-  def CreateGCSFileSystemProvider(self, object_store_creator):
-    return CloudStorageFileSystemProvider.ForEmpty()
-
-  def GetAppVersion(self):
-    return self._app_version
-
-  # (non-Delegate method).
-  def SetAppVersion(self, app_version):
-    self._app_version = app_version
-
-class CronServletTest(unittest.TestCase):
-  @EnableLogging('info')
-  def testEverything(self):
-    # All these tests are dependent (see above comment) so lump everything in
-    # the one test.
-    delegate = _TestDelegate(lambda _: MockFileSystem(LocalFileSystem.Create()))
-
-    # Test that the cron runs successfully.
-    response = CronServlet(Request.ForTest('trunk'),
-                           delegate_for_test=delegate).Get()
-    self.assertEqual(200, response.status)
-
-    # Save the file systems created, start with a fresh set for the next run.
-    first_run_file_systems = delegate.file_systems[:]
-    delegate.file_systems[:] = []
-
-    # When re-running, all file systems should be Stat()d the same number of
-    # times, but the second round shouldn't have been re-Read() since the
-    # Stats haven't changed.
-    response = CronServlet(Request.ForTest('trunk'),
-                           delegate_for_test=delegate).Get()
-    self.assertEqual(200, response.status)
-
-    self.assertEqual(len(first_run_file_systems), len(delegate.file_systems))
-    for i, second_run_file_system in enumerate(delegate.file_systems):
-      self.assertTrue(*second_run_file_system.CheckAndReset(
-          read_count=0,
-          stat_count=first_run_file_systems[i].GetStatCount()))
-
-  @IgnoreMissingContentProviders
-  def testSafeRevision(self):
-    test_data = {
-      'extensions': {
-        'browser': {
-          'api': {}
-        }
-      },
-      'chrome': {
-        'browser': {
-          'extensions': {
-            'OWNERS': '',
-            'api': {}
-          }
-        },
-        'common': {
-          'extensions': {
-            'api': {
-              '_api_features.json': '{}',
-              '_manifest_features.json': '{}',
-              '_permission_features.json': '{}',
-            },
-            'docs': {
-              'examples': {
-                'examples.txt': 'examples.txt contents'
-              },
-              'server2': {
-                'app.yaml': AppYamlHelper.GenerateAppYaml('2-0-8')
-              },
-              'static': {
-                'static.txt': 'static.txt contents'
-              },
-              'templates': {
-                'articles': {
-                  'activeTab.html': 'activeTab.html contents'
-                },
-                'intros': {
-                  'browserAction.html': 'activeTab.html contents'
-                },
-                'private': {
-                  'table_of_contents.html': 'table_of_contents.html contents',
-                },
-                'public': {
-                  'apps': {
-                    'storage.html': '<h1>storage.html</h1> contents'
-                  },
-                  'extensions': {
-                    'storage.html': '<h1>storage.html</h1> contents'
-                  },
-                },
-                'json': {
-                  'chrome_sidenav.json': '{}',
-                  'content_providers.json': ReadFile(CONTENT_PROVIDERS),
-                  'manifest.json': '{}',
-                  'permissions.json': '{}',
-                  'strings.json': '{}',
-                  'whats_new.json': '{}',
-                },
-              }
-            }
-          }
-        }
-      }
-    }
-
-    updates = []
-
-    def app_yaml_update(version):
-      return MoveTo(SERVER2, {
-        'app.yaml': AppYamlHelper.GenerateAppYaml(version)
-      })
-    def storage_html_update(update):
-      return MoveTo(PUBLIC_TEMPLATES, {
-        'apps': {'storage.html': update}
-      })
-    def static_txt_update(update):
-      return MoveTo(STATIC_DOCS, {
-        'static.txt': update
-      })
-
-    storage_html_path = PUBLIC_TEMPLATES + 'apps/storage.html'
-    static_txt_path = STATIC_DOCS + 'static.txt'
-
-    def create_file_system(commit=None):
-      '''Creates a MockFileSystem at |commit| by applying that many |updates|
-      to it.
-      '''
-      mock_file_system = MockFileSystem(TestFileSystem(test_data))
-      updates_for_commit = (
-          updates if commit is None else updates[:int(commit)])
-      for update in updates_for_commit:
-        mock_file_system.Update(update)
-      return mock_file_system
-
-    delegate = _TestDelegate(create_file_system)
-    delegate.SetAppVersion('2-0-8')
-
-    file_systems = delegate.file_systems
-
-    # No updates applied yet.
-    CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
-    self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
-                     file_systems[-1].ReadSingle(APP_YAML).Get())
-    self.assertEqual('<h1>storage.html</h1> contents',
-                     file_systems[-1].ReadSingle(storage_html_path).Get())
-
-    # Apply updates to storage.html.
-    updates.append(storage_html_update('interim contents'))
-    updates.append(storage_html_update('<h1>new</h1> contents'))
-
-    CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
-    self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
-                     file_systems[-1].ReadSingle(APP_YAML).Get())
-    self.assertEqual('<h1>new</h1> contents',
-                     file_systems[-1].ReadSingle(storage_html_path).Get())
-
-    # Apply several updates to storage.html and app.yaml. The file system
-    # should be pinned at the version before app.yaml changed.
-    updates.append(storage_html_update('<h1>stuck here</h1> contents'))
-
-    double_update = storage_html_update('<h1>newer</h1> contents')
-    double_update.update(app_yaml_update('2-0-10'))
-    updates.append(double_update)
-
-    updates.append(storage_html_update('never gonna reach here'))
-
-    CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
-    self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
-                     file_systems[-1].ReadSingle(APP_YAML).Get())
-    self.assertEqual('<h1>stuck here</h1> contents',
-                     file_systems[-1].ReadSingle(storage_html_path).Get())
-
-    # Further pushes to storage.html will keep it pinned.
-    updates.append(storage_html_update('<h1>y</h1> u not update!'))
-
-    CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
-    self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
-                     file_systems[-1].ReadSingle(APP_YAML).Get())
-    self.assertEqual('<h1>stuck here</h1> contents',
-                     file_systems[-1].ReadSingle(storage_html_path).Get())
-
-    # Likewise app.yaml.
-    updates.append(app_yaml_update('2-1-0'))
-
-    CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
-    self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
-                     file_systems[-1].ReadSingle(APP_YAML).Get())
-    self.assertEqual('<h1>stuck here</h1> contents',
-                     file_systems[-1].ReadSingle(storage_html_path).Get())
-
-    # And updates to other content won't happen either.
-    updates.append(static_txt_update('important content!'))
-
-    CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
-    self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
-                     file_systems[-1].ReadSingle(APP_YAML).Get())
-    self.assertEqual('<h1>stuck here</h1> contents',
-                     file_systems[-1].ReadSingle(storage_html_path).Get())
-    self.assertEqual('static.txt contents',
-                     file_systems[-1].ReadSingle(static_txt_path).Get())
-
-    # Lastly - when the app version changes, everything should no longer be
-    # pinned.
-    delegate.SetAppVersion('2-1-0')
-    CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
-    self.assertEqual(AppYamlHelper.GenerateAppYaml('2-1-0'),
-                     file_systems[-1].ReadSingle(APP_YAML).Get())
-    self.assertEqual('<h1>y</h1> u not update!',
-                     file_systems[-1].ReadSingle(storage_html_path).Get())
-    self.assertEqual('important content!',
-                     file_systems[-1].ReadSingle(static_txt_path).Get())
-
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/chrome/common/extensions/docs/server2/custom_logger.py b/chrome/common/extensions/docs/server2/custom_logger.py
index 974da6f..d651612b 100644
--- a/chrome/common/extensions/docs/server2/custom_logger.py
+++ b/chrome/common/extensions/docs/server2/custom_logger.py
@@ -4,7 +4,7 @@
 
 import logging
 
-from appengine_wrappers import logservice
+from environment import IsAppEngine
 
 
 class CustomLogger(object):
@@ -23,4 +23,12 @@
     try:
       logfn('%s: %s' % (self._prefix, msg), *args)
     finally:
+      self.flush()
+
+  if IsAppEngine():
+    from google.appengine.api.logservice import logservice
+    def flush(self):
       logservice.flush()
+  else:
+    def flush(self):
+      pass
diff --git a/chrome/common/extensions/docs/server2/data_source.py b/chrome/common/extensions/docs/server2/data_source.py
index ba0dfb4..a503655 100644
--- a/chrome/common/extensions/docs/server2/data_source.py
+++ b/chrome/common/extensions/docs/server2/data_source.py
@@ -19,17 +19,11 @@
   def __init__(self, server_instance, request):
     pass
 
-  def GetRefreshPaths(self):
-    '''Returns a list of paths to query
-    (relative to _refresh/<data_source_name>/) with the task queue in order
-    to refresh this DataSource's data set. Any paths listed here will be
-    routed to the DataSource Refresh method in a taskqueue task request.
+  def Refresh(self):
+    '''Refreshes the cache of data this source provides. Should return a Future
+    which resolves to a boolean indicating the success or failure of the
+    refresh.
     '''
-    return ['']
-
-  def Refresh(self, path=None):
-    '''Handles _refresh requests to this DataSource. Should return a Future
-    indicating the success or failure of the refresh.'''
     raise NotImplementedError(self.__class__)
 
   def get(self, key):
diff --git a/chrome/common/extensions/docs/server2/datastore_models.py b/chrome/common/extensions/docs/server2/datastore_models.py
index c05a0b9..eaa8cab 100644
--- a/chrome/common/extensions/docs/server2/datastore_models.py
+++ b/chrome/common/extensions/docs/server2/datastore_models.py
@@ -3,9 +3,13 @@
 # found in the LICENSE file.
 
 import cPickle
+import google.appengine.ext.db as db
+import logging
 import traceback
 
-from appengine_wrappers import db
+
+_MAX_ENTITY_SIZE = 1024*1024
+
 
 # A collection of the data store models used throughout the server.
 # These values are global within datastore.
@@ -28,8 +32,13 @@
 
   @classmethod
   def CreateItem(cls, namespace, key, value):
+    pickled_value = cPickle.dumps(value)
+    if len(pickled_value) > _MAX_ENTITY_SIZE:
+      logging.warn('Refusing to create entity greater than 1 MB in size: %s/%s'
+                   % (namespace, key))
+      return None
     return PersistentObjectStoreItem(key=cls.CreateKey(namespace, key),
-                                     pickled_value=cPickle.dumps(value))
+                                     pickled_value=pickled_value)
 
   def GetValue(self):
     return cPickle.loads(self.pickled_value)
diff --git a/chrome/common/extensions/docs/server2/datastore_util.py b/chrome/common/extensions/docs/server2/datastore_util.py
new file mode 100644
index 0000000..2deeb93
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/datastore_util.py
@@ -0,0 +1,135 @@
+# 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 cPickle
+import googledatastore as datastore
+import logging
+
+from future import Future
+
+# N.B.: In order to use this module you should have a working cloud development
+# environment configured with the googledatastore module installed.
+#
+# Please see https://cloud.google.com/datastore/docs/getstarted/start_python/
+
+
+_DATASET_NAME = 'chrome-apps-doc'
+_PERSISTENT_OBJECT_KIND = 'PersistentObjectStoreItem'
+_VALUE_PROPERTY_NAME = 'pickled_value'
+
+# The max number of entities to include in a single request. This is capped at
+# 500 by the service. In practice we may send fewer due to _MAX_REQUEST_SIZE
+_MAX_BATCH_SIZE = 500
+
+
+# The maximum entity size allowed by Datastore.
+_MAX_ENTITY_SIZE = 1024*1024
+
+
+# The maximum request size (in bytes) to send Datastore. This is an approximate
+# size based on the sum of entity blob_value sizes.
+_MAX_REQUEST_SIZE = 5*1024*1024
+
+
+def _CreateEntity(name, value):
+  entity = datastore.Entity()
+  path = entity.key.path_element.add()
+  path.kind = _PERSISTENT_OBJECT_KIND
+  path.name = name
+  pickled_value_property = entity.property.add()
+  pickled_value_property.name = _VALUE_PROPERTY_NAME
+  pickled_value_property.value.indexed = False
+  pickled_value_property.value.blob_value = value
+  return entity
+
+
+def _CreateBatches(data):
+  '''Constructs batches of at most _MAX_BATCH_SIZE entities to cover all
+  entities defined in |data| without exceeding the transaction size limit.
+  This is a generator emitting lists of entities.
+  '''
+  def get_size(entity):
+    return len(entity.property[0].value.blob_value)
+
+  entities = [_CreateEntity(name, value) for name, value in data.iteritems()]
+  batch_start = 0
+  batch_end = 1
+  batch_size = get_size(entities[0])
+  while batch_end < len(entities):
+    next_size = get_size(entities[batch_end])
+    if (batch_size + next_size > _MAX_REQUEST_SIZE or
+        batch_end - batch_start >= _MAX_BATCH_SIZE):
+      yield entities[batch_start:batch_end], batch_end, len(entities)
+      batch_start = batch_end
+      batch_size = 0
+    else:
+      batch_size += next_size
+    batch_end = batch_end + 1
+  if batch_end > batch_start and batch_start < len(entities):
+    yield entities[batch_start:batch_end], batch_end, len(entities)
+
+
+def PushData(data, original_data={}):
+  '''Pushes a bunch of data into the datastore. The data should be a dict. Each
+  key is treated as a namespace, and each value is also a dict. A new datastore
+  entry is upserted for every inner key, with the value pickled into the
+  |pickled_value| field.
+
+  For example, if given the dictionary:
+
+  {
+    'fruit': {
+      'apple': 1234,
+      'banana': 'yellow',
+      'trolling carrot': { 'arbitrarily complex': ['value', 'goes', 'here'] }
+    },
+    'animal': {
+      'sheep': 'baaah',
+      'dog': 'woof',
+      'trolling cat': 'moo'
+    }
+  }
+
+  this would result in a push of 6 keys in total, with the following IDs:
+
+    Key('PersistentObjectStoreItem', 'fruit/apple')
+    Key('PersistentObjectStoreItem', 'fruit/banana')
+    Key('PersistentObjectStoreItem', 'fruit/trolling carrot')
+    Key('PersistentObjectStoreItem', 'animal/sheep')
+    Key('PersistentObjectStoreItem', 'animal/dog')
+    Key('PersistentObjectStoreItem', 'animal/trolling cat')
+
+  If given |original_data|, this will only push key-value pairs for entries that
+  are either new or have changed from their original (pickled) value.
+
+  Caveat: Pickling and unpickling a dictionary can (but does not always) change
+  its key order. This means that objects will often be seen as changed even when
+  they haven't changed.
+  '''
+  datastore.set_options(dataset=_DATASET_NAME)
+
+  def flatten(dataset):
+    flat = {}
+    for namespace, items in dataset.iteritems():
+      for k, v in items.iteritems():
+        flat['%s/%s' % (namespace, k)] = cPickle.dumps(v)
+    return flat
+
+  logging.info('Flattening data sets...')
+  data = flatten(data)
+  original_data = flatten(original_data)
+
+  logging.info('Culling new data...')
+  for k in data.keys():
+    if ((k in original_data and original_data[k] == data[k]) or
+        (len(data[k]) > _MAX_ENTITY_SIZE)):
+      del data[k]
+
+  for batch, n, total in _CreateBatches(data):
+    commit_request = datastore.CommitRequest()
+    commit_request.mode = datastore.CommitRequest.NON_TRANSACTIONAL
+    commit_request.mutation.upsert.extend(list(batch))
+
+    logging.info('Committing %s/%s entities...' % (n, total))
+    datastore.commit(commit_request)
diff --git a/chrome/common/extensions/docs/server2/environment.py b/chrome/common/extensions/docs/server2/environment.py
index 4c8ae583..85e1828d 100644
--- a/chrome/common/extensions/docs/server2/environment.py
+++ b/chrome/common/extensions/docs/server2/environment.py
@@ -31,6 +31,10 @@
   return os.environ.get('SERVER_SOFTWARE', '').find(name) == 0
 
 
+def IsComputeEngine():
+  return _IsServerSoftware('Compute Engine')
+
+
 def IsDevServer():
   return _IsServerSoftware('Development')
 
@@ -41,3 +45,16 @@
 
 def IsPreviewServer():
   return sys.argv and os.path.basename(sys.argv[0]) == 'preview.py'
+
+
+def IsAppEngine():
+  return IsDevServer() or IsReleaseServer()
+
+
+def IsTest():
+  return sys.argv and os.path.basename(sys.argv[0]).endswith('_test.py')
+
+
+class UnknownEnvironmentError(Exception):
+  pass
+
diff --git a/chrome/common/extensions/docs/server2/environment_wrappers.py b/chrome/common/extensions/docs/server2/environment_wrappers.py
new file mode 100644
index 0000000..13e60209
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/environment_wrappers.py
@@ -0,0 +1,70 @@
+# Copyright 2013 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 json
+import logging
+import os
+
+from environment import IsAppEngine, IsComputeEngine, IsTest
+
+
+_METADATA_SERVER = 'http://metadata/computeMetadata/v1/instance/service-accounts'
+_SERVICE_ACCOUNT = 'default'
+
+# The environment variable to use as a fallback token source.
+_ACCESS_TOKEN_ENV = 'DOCSERVER_ACCESS_TOKEN'
+
+
+def CreateUrlFetcher(base_path=None):
+  if IsAppEngine():
+    from url_fetcher_appengine import UrlFetcherAppengine
+    fetcher = UrlFetcherAppengine()
+  elif not IsTest():
+    from url_fetcher_urllib2 import UrlFetcherUrllib2
+    fetcher = UrlFetcherUrllib2()
+  else:
+    from url_fetcher_fake import UrlFetcherFake
+    fetcher = UrlFetcherFake()
+  fetcher.SetBasePath(base_path)
+  return fetcher
+
+
+def CreatePersistentObjectStore(namespace):
+  if IsAppEngine():
+    from persistent_object_store_appengine import PersistentObjectStoreAppengine
+    object_store = PersistentObjectStoreAppengine(namespace)
+  else:
+    from persistent_object_store_fake import PersistentObjectStoreFake
+    object_store = PersistentObjectStoreFake(namespace)
+  return object_store
+
+
+def GetAccessToken():
+  '''Acquires an access token either from the metadata service (if running on
+  a real CE VM) or the DOCSERVER_ACCESS_TOKEN environment variable.
+
+  This may return None if no token is available. That should never happen while
+  running on a VM.
+  '''
+  # Attempt to grab an access token from the VM instance's metadata.
+  if IsComputeEngine():
+    fetcher = CreateUrlFetcher()
+    token_uri = '%s/%s/token' % (_METADATA_SERVER, _SERVICE_ACCOUNT)
+    token_response = None
+    try:
+      token_response = fetcher.Fetch(token_uri,
+          headers={'Metadata-Flavor': 'Google'})
+      if token_response.status_code == 200:
+        return json.loads(token_response.content)['access_token']
+    except Exception as e:
+      logging.warn('Failed to fetch access token from VM metadata.')
+      pass
+
+  logging.warn('Using access token from local environment.')
+  access_token = os.getenv(_ACCESS_TOKEN_ENV)
+  if access_token is None:
+    logging.error('No access token available. '
+                  'Please set %s if you want things to work.' %
+                  _ACCESS_TOKEN_ENV)
+  return access_token
diff --git a/chrome/common/extensions/docs/server2/fake_fetchers.py b/chrome/common/extensions/docs/server2/fake_fetchers.py
index 38625f1..ea30b83 100644
--- a/chrome/common/extensions/docs/server2/fake_fetchers.py
+++ b/chrome/common/extensions/docs/server2/fake_fetchers.py
@@ -3,15 +3,15 @@
 # found in the LICENSE file.
 
 # These are fake fetchers that are used for testing and the preview server.
-# They return canned responses for URLs. appengine_wrappers.py uses the fake
-# fetchers if the App Engine imports fail.
+# They return canned responses for URLs. url_fetcher_fake.py uses the fake
+# fetchers if other URL fetching APIs are unavailable.
 
 import base64
 import json
 import os
 import re
 
-import appengine_wrappers
+import url_fetcher_fake
 from extensions_paths import SERVER2
 from path_util import IsDirectory
 from test_util import ReadFile, ChromiumPath
@@ -77,48 +77,6 @@
       return None
 
 
-_GITILES_BASE_RE = re.escape('%s/%s' %
-    (url_constants.GITILES_BASE, url_constants.GITILES_SRC_ROOT))
-_GITILES_BRANCH_BASE_RE = re.escape('%s/%s/%s' %
-    (url_constants.GITILES_BASE,
-     url_constants.GITILES_SRC_ROOT,
-     url_constants.GITILES_BRANCHES_PATH))
-# NOTE: _GITILES_BRANCH_BASE_RE must be first, because _GITILES_BASE_RE is
-# a more general pattern.
-_GITILES_URL_RE = r'(%s|%s)/' % (_GITILES_BRANCH_BASE_RE, _GITILES_BASE_RE)
-_GITILES_URL_TO_COMMIT_PATTERN = re.compile(r'%s[^/]+$' % _GITILES_URL_RE)
-_GITILES_URL_TO_PATH_PATTERN = re.compile(r'%s.+?/(.*)' % _GITILES_URL_RE)
-def _ExtractPathFromGitilesUrl(url):
-  return _GITILES_URL_TO_PATH_PATTERN.match(url).group(2)
-
-
-class _FakeGitilesServer(_FakeFetcher):
-  def fetch(self, url):
-    if _GITILES_URL_TO_COMMIT_PATTERN.match(url) is not None:
-      return json.dumps({'commit': '1' * 40})
-    path = _ExtractPathFromGitilesUrl(url)
-    chromium_path = ChromiumPath(path)
-    if self._IsDir(chromium_path):
-      jsn = {}
-      dir_stat = self._Stat(chromium_path)
-      jsn['id'] = dir_stat
-      jsn['entries'] = []
-      for f in self._ListDir(chromium_path):
-        if f.startswith('.'):
-          continue
-        f_path = os.path.join(chromium_path, f)
-        jsn['entries'].append({
-          'id': self._Stat(f_path),
-          'name': f,
-          'type': 'tree' if self._IsDir(f_path) else 'blob'
-        })
-      return json.dumps(jsn)
-    try:
-      return base64.b64encode(ReadFile(path))
-    except IOError:
-      return None
-
-
 class _FakeViewvcServer(_FakeFetcher):
   def fetch(self, url):
     path = ChromiumPath(_ExtractPathFromSvnUrl(url))
@@ -181,7 +139,7 @@
 def ConfigureFakeFetchers():
   '''Configure the fake fetcher paths relative to the docs directory.
   '''
-  appengine_wrappers.ConfigureFakeUrlFetch({
+  url_fetcher_fake.ConfigureFakeUrlFetch({
     url_constants.OMAHA_HISTORY: _FakeOmahaHistory(),
     url_constants.OMAHA_PROXY_URL: _FakeOmahaProxy(),
     '%s/.*' % url_constants.SVN_URL: _FakeSubversionServer(),
@@ -190,6 +148,4 @@
     '%s/.*/zipball' % url_constants.GITHUB_REPOS: _FakeGithubZip(),
     '%s/api/.*' % url_constants.CODEREVIEW_SERVER: _FakeRietveldAPI(),
     '%s/tarball/.*' % url_constants.CODEREVIEW_SERVER: _FakeRietveldTarball(),
-    '%s/.*' % _GITILES_BASE_RE: _FakeGitilesServer(),
-    '%s/.*' % _GITILES_BRANCH_BASE_RE: _FakeGitilesServer()
   })
diff --git a/chrome/common/extensions/docs/server2/gcs_file_system.py b/chrome/common/extensions/docs/server2/gcs_file_system.py
index 36f28fa..62c21be 100644
--- a/chrome/common/extensions/docs/server2/gcs_file_system.py
+++ b/chrome/common/extensions/docs/server2/gcs_file_system.py
@@ -2,19 +2,19 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from third_party.cloudstorage import cloudstorage_api
-from third_party.cloudstorage import common
-from third_party.cloudstorage import errors
+import json
+import logging
+import posixpath
+import traceback
+import urllib
 
 from docs_server_utils import StringIdentity
+from environment_wrappers import CreateUrlFetcher
 from file_system import FileSystem, FileNotFoundError, StatInfo
 from future import Future
 from path_util import (
     AssertIsDirectory, AssertIsFile, AssertIsValid, IsDirectory, Join)
 
-import logging
-import traceback
-
 
 # See gcs_file_system_provider.py for documentation on using Google Cloud
 # Storage as a filesystem.
@@ -25,76 +25,32 @@
 
 # Name of the file containing the Git hash of the latest commit sync'ed
 # to Cloud Storage. This file is generated by the Github->GCS sync script
-LAST_COMMIT_HASH_FILENAME = '.__lastcommit.txt'
+_LAST_COMMIT_HASH_FILENAME = '.__lastcommit.txt'
 
-def _ReadFile(filename):
-  AssertIsFile(filename)
-  try:
-    with cloudstorage_api.open('/' + filename, 'r') as f:
-      return f.read()
-  except errors.Error:
-    raise FileNotFoundError('Read failed for %s: %s' % (filename,
-        traceback.format_exc()))
 
-def _ListDir(dir_name, recursive=False):
-  AssertIsDirectory(dir_name)
-  try:
-    # The listbucket method uses a prefix approach to simulate hierarchy.
-    # Calling it with the "delimiter" argument set to '/' gets only files
-    # directly inside the directory, not all recursive content.
-    delimiter = None if recursive else '/'
-    files = cloudstorage_api.listbucket('/' + dir_name, delimiter=delimiter)
-    return [os_path.filename.lstrip('/')[len(dir_name):] for os_path in files]
-  except errors.Error:
-    raise FileNotFoundError('cloudstorage.listbucket failed for %s: %s' %
-                            (dir_name, traceback.format_exc()))
+# Base URL for GCS requests.
+_STORAGE_API_BASE = 'https://www.googleapis.com/storage/v1'
 
-def _CreateStatInfo(bucket, path):
-  full_path = Join(bucket, path)
-  last_commit_file = Join(bucket, LAST_COMMIT_HASH_FILENAME)
-  try:
-    last_commit = _ReadFile(last_commit_file)
-    if IsDirectory(full_path):
-      child_versions = dict((filename, last_commit) 
-                            for filename in _ListDir(full_path)) 
-    else:
-      child_versions = None
-    return StatInfo(last_commit, child_versions)
-  except (TypeError, errors.Error):
-    raise FileNotFoundError('cloudstorage.stat failed for %s: %s' % (path,
-                            traceback.format_exc()))
 
 class CloudStorageFileSystem(FileSystem):
   '''FileSystem implementation which fetches resources from Google Cloud
   Storage.
   '''
-  def __init__(self, bucket, debug_access_token=None, debug_bucket_prefix=None):
+  def __init__(self, bucket, debug_bucket_prefix=None):
     self._bucket = bucket
-    if debug_access_token:
-      logging.debug('gcs: using debug access token: %s' % debug_access_token)
-      common.set_access_token(debug_access_token)
-    if debug_bucket_prefix:
-      logging.debug('gcs: prefixing all bucket names with %s' %
-                    debug_bucket_prefix)
-      self._bucket = debug_bucket_prefix + self._bucket
+    self._access_token = None
+    self._last_commit_hash = None
     AssertIsValid(self._bucket)
 
   def Read(self, paths, skip_not_found=False):
     def resolve():
-      try:
-        result = {}
-        for path in paths:
-          full_path = Join(self._bucket, path)
-          logging.debug('gcs: requested path "%s", reading "%s"' %
-                        (path, full_path))
-          if IsDirectory(path):
-            result[path] = _ListDir(full_path)
-          else:
-            result[path] = _ReadFile(full_path)
-        return result
-      except errors.AuthorizationError:
-        self._warnAboutAuthError()
-        raise
+      result = {}
+      for path in paths:
+        if IsDirectory(path):
+          result[path] = self._ListDir(path)
+        else:
+          result[path] = self._ReadFile(path)
+      return result
 
     return Future(callback=resolve)
 
@@ -103,25 +59,62 @@
 
   def Stat(self, path):
     AssertIsValid(path)
-    try:
-      return _CreateStatInfo(self._bucket, path)
-    except errors.AuthorizationError:
-      self._warnAboutAuthError()
-      raise
+    return self._CreateStatInfo(path)
 
   def GetIdentity(self):
     return '@'.join((self.__class__.__name__, StringIdentity(self._bucket)))
 
+  def _CreateStatInfo(self, path):
+    if not self._last_commit_hash:
+      self._last_commit_hash = self._ReadFile(_LAST_COMMIT_HASH_FILENAME)
+    if IsDirectory(path):
+      child_versions = dict((filename, self._last_commit_hash)
+                            for filename in self._ListDir(path))
+    else:
+      child_versions = None
+    return StatInfo(self._last_commit_hash, child_versions)
+
+  def _ReadFile(self, path):
+    AssertIsFile(path)
+    return self._FetchObjectData(path)
+
+  def _ListDir(self, path, recursive=False):
+    AssertIsDirectory(path)
+    # The listbucket method uses a prefix approach to simulate hierarchy.
+    # Calling it with the "delimiter" argument set to '/' gets only files
+    # directly inside the directory, not all recursive content.
+
+    # Subdirectories are returned in the 'prefixes' property, but they are
+    # full paths from the root. This plucks off the name of the leaf with a
+    # trailing slash.
+    def path_from_prefix(prefix):
+      return posixpath.split(posixpath.split(prefix)[0])[1] + '/'
+
+    query = { 'prefix': path }
+    if not recursive:
+      query['delimiter'] = '/'
+    root_object = json.loads(self._FetchObject('', query=query))
+    files = [posixpath.basename(o['name'])
+             for o in root_object.get('items', [])]
+    dirs = [path_from_prefix(prefix)
+            for prefix in root_object.get('prefixes', [])]
+    return files + dirs
+
+  def _FetchObject(self, path, query={}):
+    # Escape the path, including slashes.
+    url_path = urllib.quote(path.lstrip('/'), safe='')
+    fetcher = CreateUrlFetcher()
+    object_url = '%s/b/%s/o/%s' % (_STORAGE_API_BASE, self._bucket, url_path)
+    response = fetcher.Fetch(object_url, query=query)
+    if response.status_code != 200:
+      raise FileNotFoundError(
+          'Path %s not found in GCS bucket %s' % (path, self._bucket))
+    return response.content
+
+  def _FetchObjectData(self, path, query={}):
+    q = query.copy()
+    q.update({ 'alt': 'media' })
+    return self._FetchObject(path, query=q)
+
   def __repr__(self):
     return 'CloudStorageFileSystem(%s)' % self._bucket
-
-  def _warnAboutAuthError(self):
-    logging.warn(('Authentication error on Cloud Storage. Check if your'
-                  ' appengine project has permissions to Read the GCS'
-                  ' buckets. If you are running a local appengine server,'
-                  ' you need to set an access_token in'
-                  ' local_debug/gcs_debug.conf.'
-                  ' Remember that this token expires in less than 10'
-                  ' minutes, so keep it updated. See'
-                  ' gcs_file_system_provider.py for instructions.'));
-    logging.debug(traceback.format_exc())
diff --git a/chrome/common/extensions/docs/server2/gcs_file_system_provider.py b/chrome/common/extensions/docs/server2/gcs_file_system_provider.py
index 22369ae2..f355e64c 100644
--- a/chrome/common/extensions/docs/server2/gcs_file_system_provider.py
+++ b/chrome/common/extensions/docs/server2/gcs_file_system_provider.py
@@ -4,12 +4,16 @@
 
 import os
 import environment
+import logging
 
 from caching_file_system import CachingFileSystem
 from empty_dir_file_system import EmptyDirFileSystem
+from environment import IsTest
 from extensions_paths import LOCAL_GCS_DIR, LOCAL_GCS_DEBUG_CONF
+from gcs_file_system import CloudStorageFileSystem
 from local_file_system import LocalFileSystem
-from path_util import IsDirectory, ToDirectory
+from path_util import ToDirectory
+
 
 class CloudStorageFileSystemProvider(object):
   '''Provides CloudStorageFileSystem bound to a GCS bucket.
@@ -25,66 +29,33 @@
 
     Optional configuration can be set in a local_debug/gcs_debug.conf file:
       use_local_fs=True|False
-      access_token=<token>
       remote_bucket_prefix=<prefix>
 
     If running in Preview mode or in Development mode with use_local_fs set to
-    True, buckets and files are looked inside the local_debug folder instead
-    of in the real GCS server. Preview server does not support direct GCS
-    access, so it is always forced to use a LocalFileSystem.
-
-    For real GCS access in the Development mode (dev_appserver.py),
-    access_token and remote_bucket_prefix options can be
-    used to change the way GCS files are accessed. Both are ignored in a real
-    appengine instance.
-
-    "access_token" is always REQUIRED on dev_appengine, otherwise you will
-    get 404 (auth) errors. You can get one access_token valid for a few minutes
-    by typing:
-      gsutil -d ls 2>&1 | grep "Bearer" |
-         sed "s/.*Bearer \(.*\).r.nUser-Agent.*/access_token=\1/" )"
-
-    A sample output would be:
-      access_token=ya29.1.AADtN_VW5ibbfLHV5cMIK5ss4bHtVzBXpa4byjd
-
-    Now add this line to the local_debug/gcs_debug.conf file and restart the
-    appengine development server.
-
-    Remember that you will need a new access_token every ten minutes or
-    so. If you get 404 errors on log, update it. Access token is not
-    used for a deployed appengine app, only if you use dev_appengine.py.
-
-    remote_bucket_prefix is useful if you want to test on your own GCS buckets
-    before using the real GCS buckets.
-
+    True, buckets and files are looked for inside the local_debug folder instead
+    of in the real GCS server.
     '''
-    if not environment.IsReleaseServer() and not environment.IsDevServer():
-      bucket_local_path = os.path.join(LOCAL_GCS_DIR, bucket)
-      if IsDirectory(bucket_local_path):
-        return LocalFileSystem(bucket_local_path)
-      else:
-        return EmptyDirFileSystem()
+    if IsTest():
+      return EmptyDirFileSystem()
 
-    debug_access_token = None
     debug_bucket_prefix = None
     use_local_fs = False
-
-    if environment.IsDevServer() and os.path.exists(LOCAL_GCS_DEBUG_CONF):
+    if os.path.exists(LOCAL_GCS_DEBUG_CONF):
       with open(LOCAL_GCS_DEBUG_CONF, "r") as token_file:
         properties = dict(line.strip().split('=', 1) for line in token_file)
       use_local_fs = properties.get('use_local_fs', 'False')=='True'
-      debug_access_token = properties.get('access_token', None)
       debug_bucket_prefix = properties.get('remote_bucket_prefix', None)
+      logging.debug('gcs: prefixing all bucket names with %s' %
+                    debug_bucket_prefix)
 
-    if environment.IsDevServer() and use_local_fs:
+    if use_local_fs:
       return LocalFileSystem(ToDirectory(os.path.join(LOCAL_GCS_DIR, bucket)))
 
-    # gcs_file_system has strong dependencies on runtime appengine APIs,
-    # so we only import it when we are sure we are not on preview.py or tests.
-    from gcs_file_system import CloudStorageFileSystem
-    return CachingFileSystem(CloudStorageFileSystem(bucket,
-        debug_access_token, debug_bucket_prefix),
-        self._object_store_creator)
+    if debug_bucket_prefix:
+      bucket = debug_bucket_prefix + bucket
+
+    return CachingFileSystem(CloudStorageFileSystem(bucket),
+                             self._object_store_creator)
 
   @staticmethod
   def ForEmpty():
diff --git a/chrome/common/extensions/docs/server2/gitiles_file_system.py b/chrome/common/extensions/docs/server2/gitiles_file_system.py
deleted file mode 100644
index ecfd78c9..0000000
--- a/chrome/common/extensions/docs/server2/gitiles_file_system.py
+++ /dev/null
@@ -1,251 +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.
-
-
-from base64 import b64decode
-from itertools import izip
-import json
-import logging
-import posixpath
-import time
-import traceback
-
-from appengine_url_fetcher import AppEngineUrlFetcher
-from appengine_wrappers import IsDownloadError, app_identity
-from docs_server_utils import StringIdentity
-from environment import IsDevServer
-from file_system import (FileNotFoundError,
-                         FileSystem,
-                         FileSystemError,
-                         FileSystemThrottledError,
-                         StatInfo)
-from future import All, Future
-from path_util import AssertIsValid, IsDirectory, ToDirectory
-from third_party.json_schema_compiler.memoize import memoize
-from url_constants import (GITILES_BASE,
-                           GITILES_SRC_ROOT,
-                           GITILES_BRANCHES_PATH,
-                           GITILES_OAUTH2_SCOPE)
-
-
-_JSON_FORMAT = '?format=JSON'
-_TEXT_FORMAT = '?format=TEXT'
-_AUTH_PATH_PREFIX = '/a'
-
-
-def _ParseGitilesJson(json_data):
-  '''json.loads with fix-up for non-executable JSON. Use this to parse any JSON
-  data coming from Gitiles views.
-  '''
-  return json.loads(json_data[json_data.find('{'):])
-
-
-def _CreateStatInfo(json_data):
-  '''Returns a StatInfo object comprised of the tree ID for |json_data|,
-  as well as the tree IDs for the entries in |json_data|.
-  '''
-  tree = _ParseGitilesJson(json_data)
-  return StatInfo(tree['id'],
-                  dict((e['name'], e['id']) for e in tree['entries']))
-
-
-class GitilesFileSystem(FileSystem):
-  '''Class to fetch filesystem data from the Chromium project's gitiles
-  service.
-  '''
-  _logged_tokens = set()
-
-  @classmethod
-  def Create(cls, branch='master', commit=None):
-    token, _ = app_identity.get_access_token(GITILES_OAUTH2_SCOPE)
-
-    # Log the access token (once per token) so that it can be sneakily re-used
-    # in development.
-    if token not in cls._logged_tokens:
-      logging.info('Got token %s for scope %s' % (token, GITILES_OAUTH2_SCOPE))
-      cls._logged_tokens.add(token)
-
-    # Only include forced-auth (/a/) in the Gitiles URL if we have a token and
-    # this is not the development server.
-    path_prefix = ('' if token is None or IsDevServer()
-                      else _AUTH_PATH_PREFIX)
-    if commit:
-      base_url = '%s%s/%s/%s' % (
-          GITILES_BASE, path_prefix, GITILES_SRC_ROOT, commit)
-    elif branch is 'master':
-      base_url = '%s%s/%s/master' % (
-          GITILES_BASE, path_prefix, GITILES_SRC_ROOT)
-    else:
-      base_url = '%s%s/%s/%s/%s' % (
-          GITILES_BASE, path_prefix, GITILES_SRC_ROOT,
-          GITILES_BRANCHES_PATH, branch)
-    return GitilesFileSystem(AppEngineUrlFetcher(), base_url, branch, commit)
-
-  def __init__(self, fetcher, base_url, branch, commit):
-    self._fetcher = fetcher
-    self._base_url = base_url
-    self._branch = branch
-    self._commit = commit
-
-  def _FetchAsync(self, url):
-    '''Convenience wrapper for fetcher.FetchAsync, so callers don't
-    need to use posixpath.join.
-    '''
-    AssertIsValid(url)
-    access_token, _ = app_identity.get_access_token(GITILES_OAUTH2_SCOPE)
-    return self._fetcher.FetchAsync('%s/%s' % (self._base_url, url),
-                                    access_token=access_token)
-
-  def _ResolveFetchContent(self, path, fetch_future, skip_not_found=False):
-    '''Returns a future to cleanly resolve |fetch_future|.
-    '''
-    def handle(e):
-      if skip_not_found and IsDownloadError(e):
-        return None
-      exc_type = FileNotFoundError if IsDownloadError(e) else FileSystemError
-      raise exc_type('%s fetching %s for Get from %s: %s' %
-          (type(e).__name__, path, self._base_url, traceback.format_exc()))
-
-    def get_content(result):
-      if result.status_code == 404:
-        if skip_not_found:
-          return None
-        raise FileNotFoundError('Got 404 when fetching %s for Get from %s' %
-                                (path, self._base_url))
-      if result.status_code == 429:
-        logging.warning('Access throttled when fetching %s for Get from %s' %
-            (path, self._base_url))
-        raise FileSystemThrottledError(
-            'Access throttled when fetching %s for Get from %s' %
-            (path, self._base_url))
-      if result.status_code != 200:
-        raise FileSystemError(
-            'Got %s when fetching %s for Get from %s, content %s' %
-            (result.status_code, path, self._base_url, result.content))
-      return result.content
-
-    return fetch_future.Then(get_content, handle)
-
-  def Read(self, paths, skip_not_found=False):
-    # Directory content is formatted in JSON in Gitiles as follows:
-    #
-    #   {
-    #     "id": "12a5464de48d2c46bc0b2dc78fafed75aab554fa", # The tree ID.
-    #     "entries": [
-    #       {
-    #         "mode": 33188,
-    #         "type": "blob",
-    #           "id": "ab971ca447bc4bce415ed4498369e00164d91cb6", # File ID.
-    #         "name": ".gitignore"
-    #       },
-    #       ...
-    #     ]
-    #   }
-    def list_dir(json_data):
-      entries = _ParseGitilesJson(json_data).get('entries', [])
-      return [e['name'] + ('/' if e['type'] == 'tree' else '') for e in entries]
-
-    def fixup_url_format(path):
-      # By default, Gitiles URLs display resources in HTML. To get resources
-      # suitable for our consumption, a '?format=' string must be appended to
-      # the URL. The format may be one of 'JSON' or 'TEXT' for directory or
-      # text resources, respectively.
-      return path + (_JSON_FORMAT if IsDirectory(path) else _TEXT_FORMAT)
-
-    # A list of tuples of the form (path, Future).
-    fetches = [(path, self._FetchAsync(fixup_url_format(path)))
-               for path in paths]
-
-    def parse_contents(results):
-      value = {}
-      for path, content in izip(paths, results):
-        if content is None:
-          continue
-        # Gitiles encodes text content in base64 (see
-        # http://tools.ietf.org/html/rfc4648 for info about base64).
-        value[path] = (list_dir if IsDirectory(path) else b64decode)(content)
-      return value
-
-    return All(self._ResolveFetchContent(path, future, skip_not_found)
-               for path, future in fetches).Then(parse_contents)
-
-  def Refresh(self):
-    return Future(value=())
-
-  @memoize
-  def _GetCommitInfo(self, key):
-    '''Gets the commit information specified by |key|.
-
-    The JSON view for commit info looks like:
-      {
-        "commit": "8fd578e1a7b142cd10a4387861f05fb9459b69e2", # Commit ID.
-        "tree": "3ade65d8a91eadd009a6c9feea8f87db2c528a53",   # Tree ID.
-        "parents": [
-          "a477c787fe847ae0482329f69b39ce0fde047359" # Previous commit ID.
-        ],
-        "author": {
-          "name": "...",
-          "email": "...",
-          "time": "Tue Aug 12 17:17:21 2014"
-        },
-        "committer": {
-          "name": "...",
-          "email": "...",
-          "time": "Tue Aug 12 17:18:28 2014"
-        },
-        "message": "...",
-        "tree_diff": [...]
-      }
-    '''
-    # Commit information for a branch is obtained by appending '?format=JSON'
-    # to the branch URL. Note that '<gitiles_url>/<branch>?format=JSON' is
-    # different from '<gitiles_url>/<branch>/?format=JSON': the latter serves
-    # the root directory JSON content, whereas the former serves the branch
-    # commit info JSON content.
-
-    access_token, _ = app_identity.get_access_token(GITILES_OAUTH2_SCOPE)
-    fetch_future = self._fetcher.FetchAsync(self._base_url + _JSON_FORMAT,
-                                            access_token=access_token)
-    content_future = self._ResolveFetchContent(self._base_url, fetch_future)
-    return content_future.Then(lambda json: _ParseGitilesJson(json)[key])
-
-  def GetCommitID(self):
-    '''Returns a future that resolves to the commit ID for this branch.
-    '''
-    return self._GetCommitInfo('commit')
-
-  def GetPreviousCommitID(self):
-    '''Returns a future that resolves to the previous commit ID for this branch.
-    '''
-    return self._GetCommitInfo('parents').Then(lambda parents: parents[0])
-
-  def StatAsync(self, path):
-    dir_, filename = posixpath.split(path)
-    def stat(content):
-      stat_info = _CreateStatInfo(content)
-      if stat_info.version is None:
-        raise FileSystemError('Failed to find version of dir %s' % dir_)
-      if IsDirectory(path):
-        return stat_info
-      if filename not in stat_info.child_versions:
-        raise FileNotFoundError(
-            '%s from %s was not in child versions for Stat' % (filename, path))
-      return StatInfo(stat_info.child_versions[filename])
-
-    fetch_future = self._FetchAsync(ToDirectory(dir_) + _JSON_FORMAT)
-    return self._ResolveFetchContent(path, fetch_future).Then(stat)
-
-  def GetIdentity(self):
-    if self._branch == 'master':
-      # A master FS always carries the same identity even if pinned to a commit.
-      str_id = 'master'
-    elif self._commit is not None:
-      str_id = self._commit
-    else:
-      str_id = '%s/%s' % (GITILES_BRANCHES_PATH, self._branch)
-    return '@'.join((self.__class__.__name__, StringIdentity(
-        '%s/%s/%s' % (GITILES_BASE, GITILES_SRC_ROOT, str_id))))
-
-  def GetVersion(self):
-    return self._commit
diff --git a/chrome/common/extensions/docs/server2/gitiles_file_system_test.py b/chrome/common/extensions/docs/server2/gitiles_file_system_test.py
deleted file mode 100755
index 3e2bdbc..0000000
--- a/chrome/common/extensions/docs/server2/gitiles_file_system_test.py
+++ /dev/null
@@ -1,163 +0,0 @@
-#!/usr/bin/env python
-# 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 base64
-import json
-import unittest
-
-from extensions_paths import SERVER2
-from file_system import StatInfo
-from future import Future
-from gitiles_file_system import (_CreateStatInfo,
-                                 _ParseGitilesJson,
-                                 GitilesFileSystem)
-from path_util import IsDirectory
-from test_file_system import TestFileSystem
-from test_util import ReadFile
-
-
-_BASE_URL = ''
-_REAL_DATA_DIR = 'chrome/common/extensions/docs/templates/public/extensions/'
-_TEST_DATA = (SERVER2, 'test_data', 'gitiles_file_system', 'public_extensions')
-# GitilesFileSystem expects file content to be encoded in base64.
-_TEST_FS = {
-  'test1.txt': base64.b64encode('test1'),
-  'dir1': {
-    'test2.txt': base64.b64encode('test2'),
-    'dir2': {
-      'test3.txt': base64.b64encode('test3')
-    }
-  }
-}
-
-
-class _Response(object):
-  def __init__(self, content=''):
-    self.content = content
-    self.status_code = 200
-
-
-class DownloadError(Exception):
-  pass
-
-
-class _FakeGitilesFetcher(object):
-  def __init__(self, fs):
-    self._fs = fs
-
-  def FetchAsync(self, url, access_token=None):
-    def resolve():
-      assert '?' in url
-      if url == _BASE_URL + '?format=JSON':
-        return _Response(json.dumps({'commit': 'a_commit'}))
-      path, fmt = url.split('?')
-      # Fetch urls are of the form <base_url>/<path>. We only want <path>.
-      path = path.split('/', 1)[1]
-      if path == _REAL_DATA_DIR:
-        return _Response(ReadFile(*_TEST_DATA))
-      # ALWAYS skip not found here.
-      content = self._fs.Read((path,),
-                              skip_not_found=True).Get().get(path, None)
-      if content is None:
-        # GitilesFS expects a DownloadError if the file wasn't found.
-        raise DownloadError
-      # GitilesFS expects directory content as a JSON string.
-      if 'JSON' in fmt:
-        content = json.dumps({
-          'entries': [{
-            # GitilesFS expects directory names to not have a trailing '/'.
-            'name': name.rstrip('/'),
-            'type': 'tree' if IsDirectory(name) else 'blob'
-          } for name in content]
-        })
-      return _Response(content)
-    return Future(callback=resolve)
-
-
-class GitilesFileSystemTest(unittest.TestCase):
-  def setUp(self):
-    fetcher = _FakeGitilesFetcher(TestFileSystem(_TEST_FS))
-    self._gitiles_fs = GitilesFileSystem(fetcher, _BASE_URL, 'master', None)
-
-  def testParseGitilesJson(self):
-    test_json = '\n'.join([
-      ')]}\'',
-      json.dumps({'commit': 'blah'})
-    ])
-    self.assertEqual(_ParseGitilesJson(test_json), {'commit': 'blah'})
-
-  def testCreateStatInfo(self):
-    test_json = '\n'.join([
-      ')]}\'',
-      json.dumps({
-        'id': 'some_long_string',
-        'entries': [
-          {
-            'mode': 33188,
-            'type': 'blob',
-              'id': 'long_id',
-            'name': '.gitignore'
-          },
-          {
-            'mode': 33188,
-            'type': 'blob',
-              'id': 'another_long_id',
-            'name': 'PRESUBMIT.py'
-          },
-          {
-            'mode': 33188,
-            'type': 'blob',
-              'id': 'yali',
-            'name': 'README'
-          }
-        ]
-      })
-    ])
-    expected_stat_info = StatInfo('some_long_string', {
-      '.gitignore': 'long_id',
-      'PRESUBMIT.py': 'another_long_id',
-      'README': 'yali'
-    })
-    self.assertEqual(_CreateStatInfo(test_json), expected_stat_info)
-
-  def testRead(self):
-    # Read a top-level file.
-    f = self._gitiles_fs.Read(['test1.txt'])
-    self.assertEqual(f.Get(), {'test1.txt': 'test1'})
-    # Read a top-level directory.
-    f = self._gitiles_fs.Read(['dir1/'])
-    self.assertEqual(f.Get(), {'dir1/': sorted(['test2.txt', 'dir2/'])})
-    # Read a nested file.
-    f = self._gitiles_fs.Read(['dir1/test2.txt'])
-    self.assertEqual(f.Get(), {'dir1/test2.txt': 'test2'})
-    # Read a nested directory.
-    f = self._gitiles_fs.Read(['dir1/dir2/'])
-    self.assertEqual(f.Get(), {'dir1/dir2/': ['test3.txt']})
-    # Read multiple paths.
-    f = self._gitiles_fs.Read(['test1.txt', 'dir1/test2.txt'])
-    self.assertEqual(f.Get(), {'test1.txt': 'test1', 'dir1/test2.txt': 'test2'})
-    # Test skip not found.
-    f = self._gitiles_fs.Read(['fakefile'], skip_not_found=True)
-    self.assertEqual(f.Get(), {})
-
-  def testGetCommitID(self):
-    self.assertEqual(self._gitiles_fs.GetCommitID().Get(), 'a_commit')
-
-  def testStat(self):
-    self.assertEqual(self._gitiles_fs.Stat(_REAL_DATA_DIR).version,
-                     'ec21e736a3f00db2c0580e3cf71d91951656caec')
-
-  def testGetIdentity(self):
-    # Test that file systems at different commits still have the same identity.
-    other_gitiles_fs = GitilesFileSystem.Create(commit='abcdefghijklmnop')
-    self.assertEqual(self._gitiles_fs.GetIdentity(),
-                     other_gitiles_fs.GetIdentity())
-
-    yet_another_gitiles_fs = GitilesFileSystem.Create(branch='different')
-    self.assertNotEqual(self._gitiles_fs.GetIdentity(),
-                        yet_another_gitiles_fs.GetIdentity())
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/chrome/common/extensions/docs/server2/handler.py b/chrome/common/extensions/docs/server2/handler.py
index c6a2eed..736e352 100644
--- a/chrome/common/extensions/docs/server2/handler.py
+++ b/chrome/common/extensions/docs/server2/handler.py
@@ -4,12 +4,10 @@
 
 import time
 
-from admin_servlets import (DumpRefreshServlet, EnqueueServlet,
-    QueryCommitServlet, ResetCommitServlet)
-from cron_servlet import CronServlet
+from admin_servlets import (QueryCommitServlet, FlushMemcacheServlet,
+                            UpdateCacheServlet)
 from instance_servlet import InstanceServlet
 from patch_servlet import PatchServlet
-from refresh_servlet import RefreshServlet
 from servlet import Servlet, Request, Response
 from test_servlet import TestServlet
 
@@ -18,14 +16,11 @@
 
 
 _SERVLETS = {
-  'cron': CronServlet,
-  'enqueue': EnqueueServlet,
   'patch': PatchServlet,
   'query_commit': QueryCommitServlet,
-  'refresh': RefreshServlet,
-  'reset_commit': ResetCommitServlet,
+  'flush_memcache': FlushMemcacheServlet,
+  'update_cache': UpdateCacheServlet,
   'test': TestServlet,
-  'dump_refresh': DumpRefreshServlet,
 }
 
 
diff --git a/chrome/common/extensions/docs/server2/host_file_system_provider.py b/chrome/common/extensions/docs/server2/host_file_system_provider.py
index 3231c771..32fbacb 100644
--- a/chrome/common/extensions/docs/server2/host_file_system_provider.py
+++ b/chrome/common/extensions/docs/server2/host_file_system_provider.py
@@ -3,8 +3,8 @@
 # found in the LICENSE file.
 
 from caching_file_system import CachingFileSystem
-from gitiles_file_system import GitilesFileSystem
 from local_file_system import LocalFileSystem
+from local_git_file_system import LocalGitFileSystem
 from offline_file_system import OfflineFileSystem
 from third_party.json_schema_compiler.memoize import memoize
 
@@ -35,7 +35,7 @@
     |offline|
       If True all provided file systems will be wrapped in an OfflineFileSystem.
     |constructor_for_test|
-      Provides a custom constructor rather than creating GitilesFileSystems.
+      Provides a custom constructor rather than creating LocalGitFileSystems.
     |cache_only|
       If True, all provided file systems will be cache-only, meaning that cache
       misses will result in errors rather than cache updates.
@@ -81,7 +81,7 @@
     return self._Create(branch)
 
   def _Create(self, branch, commit=None):
-    '''Creates Gitiles file systems (or if in a test, potentially whatever
+    '''Creates local git file systems (or if in a test, potentially whatever
     |self._constructor_for_test specifies). Wraps the resulting file system in
     an Offline file system if the offline flag is set, and finally wraps it in
     a Caching file system.
@@ -89,7 +89,7 @@
     if self._constructor_for_test is not None:
       file_system = self._constructor_for_test(branch=branch, commit=commit)
     else:
-      file_system = GitilesFileSystem.Create(branch=branch, commit=commit)
+      file_system = LocalGitFileSystem.Create(branch=branch, commit=commit)
     if self._offline:
       file_system = OfflineFileSystem(file_system)
     return CachingFileSystem(file_system, self._object_store_creator,
diff --git a/chrome/common/extensions/docs/server2/instance_servlet.py b/chrome/common/extensions/docs/server2/instance_servlet.py
index 482199b..6528aa7 100644
--- a/chrome/common/extensions/docs/server2/instance_servlet.py
+++ b/chrome/common/extensions/docs/server2/instance_servlet.py
@@ -6,7 +6,6 @@
 from commit_tracker import CommitTracker
 from compiled_file_system import CompiledFileSystem
 from environment import IsDevServer, IsReleaseServer
-from github_file_system_provider import GithubFileSystemProvider
 from host_file_system_provider import HostFileSystemProvider
 from third_party.json_schema_compiler.memoize import memoize
 from render_servlet import RenderServlet
@@ -47,13 +46,10 @@
         offline=not (IsDevServer() or IsReleaseServer()),
         pinned_commit=commit_tracker.Get('master').Get(),
         cache_only=True)
-    github_file_system_provider = self._delegate.CreateGithubFileSystemProvider(
-        object_store_creator)
     return ServerInstance(object_store_creator,
                           CompiledFileSystem.Factory(object_store_creator),
                           branch_utility,
                           host_file_system_provider,
-                          github_file_system_provider,
                           CloudStorageFileSystemProvider(object_store_creator))
 
 class InstanceServlet(object):
diff --git a/chrome/common/extensions/docs/server2/instance_servlet_test.py b/chrome/common/extensions/docs/server2/instance_servlet_test.py
index f857ed6e..52e6063c 100755
--- a/chrome/common/extensions/docs/server2/instance_servlet_test.py
+++ b/chrome/common/extensions/docs/server2/instance_servlet_test.py
@@ -5,7 +5,6 @@
 
 import unittest
 
-from github_file_system_provider import GithubFileSystemProvider
 from instance_servlet import InstanceServlet
 from servlet import Request
 from fail_on_access_file_system import FailOnAccessFileSystem
diff --git a/chrome/common/extensions/docs/server2/integration_test.py b/chrome/common/extensions/docs/server2/integration_test.py
index c6484293..33fa87f 100755
--- a/chrome/common/extensions/docs/server2/integration_test.py
+++ b/chrome/common/extensions/docs/server2/integration_test.py
@@ -15,8 +15,8 @@
 import sys
 import time
 import unittest
+import update_cache
 
-from appengine_wrappers import SetTaskRunnerForTest
 from branch_utility import BranchUtility
 from chroot_file_system import ChrootFileSystem
 from extensions_paths import (
@@ -86,29 +86,17 @@
     ConfigureFakeFetchers()
 
   @EnableLogging('info')
-  def testCronAndPublicFiles(self):
-    '''Runs cron then requests every public file. Cron needs to be run first
+  def testUpdateAndPublicFiles(self):
+    '''Runs update then requests every public file. Update needs to be run first
     because the public file requests are offline.
     '''
     if _EXPLICIT_TEST_FILES is not None:
       return
 
-
-    def task_runner(url, commit=None):
-      arguments = { 'commit': commit } if commit else {}
-      Handler(Request.ForTest(url, arguments=arguments)).Get()
-
-    SetTaskRunnerForTest(task_runner)
-
-    print('Running cron...')
+    print('Running update...')
     start_time = time.time()
     try:
-      response = Handler(Request.ForTest('/_cron')).Get()
-      if response:
-        self.assertEqual(200, response.status)
-        self.assertEqual('Success', response.content.ToString())
-      else:
-        self.fail('No response for _cron')
+      update_cache.UpdateCache()
     finally:
       print('Took %s seconds' % (time.time() - start_time))
 
diff --git a/chrome/common/extensions/docs/server2/local_git_file_system.py b/chrome/common/extensions/docs/server2/local_git_file_system.py
new file mode 100644
index 0000000..2e988f8
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/local_git_file_system.py
@@ -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.
+
+
+import local_git_util
+import posixpath
+
+from environment import IsTest
+from file_system import FileNotFoundError, FileSystem, StatInfo
+from future import Future
+from local_file_system import LocalFileSystem
+from path_util import IsDirectory
+
+
+class LocalGitFileSystem(FileSystem):
+  '''Class to fetch filesystem data from this script's local git repository.
+  '''
+  @classmethod
+  def Create(cls, branch='master', commit=None):
+    if IsTest():
+      return LocalFileSystem.Create('')
+    return LocalGitFileSystem(branch, commit)
+
+  def __init__(self, branch, pinned_commit):
+    self._branch = branch
+    self._pinned_commit = pinned_commit
+    if self._pinned_commit:
+      commit = self._pinned_commit
+    else:
+      if branch != 'master':
+        commit = 'branch-heads/%s' % branch
+      else:
+        commit = 'origin/master'
+    try:
+      self._commit = local_git_util.ParseRevision(commit)
+    except ImportError:
+      # We ignore ImportErrors here. It means we're running in AppEngine, so
+      # this doesn't need to work anyway.
+      pass
+
+  def Read(self, paths, skip_not_found=False):
+
+    def get_entry_name(entry):
+      if entry['type'] == 'tree':
+        return entry['name'] + '/'
+      return entry['name']
+
+    def read_path(path):
+      try:
+        if IsDirectory(path):
+          return [get_entry_name(e)
+                  for e in local_git_util.ListDir(path, self._commit)]
+        else:
+          return local_git_util.ReadFile(path, self._commit)
+      except FileNotFoundError as e:
+        if skip_not_found:
+          return None
+        raise e
+
+    results = dict((path, read_path(path)) for path in paths)
+    return Future(value=dict((k, v) for k, v in results.iteritems()
+                             if v is not None))
+
+  def Refresh(self):
+    return Future(value=())
+
+  def GetCommitID(self):
+    '''Returns a future that resolves to the commit ID for this file system's
+    revision.
+    '''
+    return Future(value=self._commit)
+
+  def GetPreviousCommitID(self):
+    '''Returns a future that resolves to the parent commit ID of this file
+    system's revision.
+    '''
+    return Future(value=local_git_util.GetParentRevision(self._commit))
+
+  def StatAsync(self, path):
+
+    def get_child_versions(path):
+      return dict((e['name'], e['id'])
+                  for e in local_git_util.ListDir(path, self._commit))
+
+    def get_file_version(dir, filename):
+      try:
+        return next(e['id'] for e in local_git_util.ListDir(dir, self._commit)
+                    if e['name'] == filename)
+      except StopIteration:
+        raise FileNotFoundError('%s not found in revision %s' %
+                                (path, self._commit))
+
+    dir, filename = posixpath.split(path)
+    if path == '':
+      version = local_git_util.GetRootTree(self._commit)
+      child_versions = get_child_versions('')
+    elif IsDirectory(path):
+      parent_dir, stat_dir = posixpath.split(dir)
+      version = get_file_version(parent_dir, stat_dir)
+      child_versions = get_child_versions(dir)
+    else:
+      version = get_file_version(dir, filename)
+      child_versions = None
+
+    #print 'Accessing local git for stat on %s (%s)' % (path, version)
+    return Future(value=StatInfo(version, child_versions))
+
+  def GetIdentity(self):
+    if self._branch == 'master':
+      # A master FS always carries the same identity even if pinned to a commit.
+      str_id = 'master'
+    elif self._pinned_commit is not None:
+      str_id = self._pinned_commit
+    else:
+      str_id = 'branch-heads/%s' % self._branch
+    return '@'.join((self.__class__.__name__, str_id))
+
+  def GetVersion(self):
+    return self._pinned_commit
diff --git a/chrome/common/extensions/docs/server2/local_git_util.py b/chrome/common/extensions/docs/server2/local_git_util.py
new file mode 100644
index 0000000..47b351c0
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/local_git_util.py
@@ -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.
+
+import os
+import re
+
+from file_system import FileNotFoundError
+
+
+# This provides utilities for extracting information from the local git
+# repository to which it belongs.
+
+
+# Regex to match ls-tree output.
+_LS_TREE_REGEX = re.compile(
+    '\d+\s(?P<type>\w+)\s(?P<id>[0-9a-f]{40})\s(?P<name>.*)')
+
+
+def _GetRoot():
+  return os.path.join(os.path.dirname(os.path.realpath(__file__)),
+                      os.pardir, os.pardir, os.pardir, os.pardir, os.pardir)
+
+
+def _RelativePath(path):
+  return os.path.join(_GetRoot(), path)
+
+
+def RunGit(command, args=[]):
+  # We import subprocess symbols lazily because they aren't available on
+  # AppEngine, and the frontend may load (but should never execute) this module.
+  from subprocess import check_output
+  with open(os.devnull, 'w') as dev_null:
+    return check_output(['git', command] + args, stderr=dev_null,
+        cwd=_GetRoot())
+
+
+def ParseRevision(name):
+  return RunGit('rev-parse', [name]).rstrip()
+
+
+def GetParentRevision(revision):
+  return RunGit('show', ['-s', '--format=%P', revision]).rstrip()
+
+
+def GetRootTree(revision):
+  return RunGit('show', ['-s', '--format=%T', revision]).rstrip()
+
+
+def ListDir(path, revision='HEAD'):
+  '''Retrieves a directory listing for the specified path and optional revision
+  (default is HEAD.) Returns a list of objects with the following properties:
+
+    |type|: the type of entry; 'blob' (file) or 'tree' (directory)
+    |id|: the hash of the directory entry. This is either tree hash or blob hash
+    |name|: the name of the directory entry.
+  '''
+  from subprocess import CalledProcessError
+  try:
+    ref = '%s:%s' % (ParseRevision(revision), path.lstrip('/'))
+    listing = RunGit('ls-tree', [ref]).rstrip().splitlines()
+  except CalledProcessError:
+    raise FileNotFoundError('%s not found in revision %s' % (path, revision))
+
+  def parse_line(line):
+    return re.match(_LS_TREE_REGEX, line).groupdict()
+
+  return map(parse_line, listing)
+
+
+def ReadFile(path, revision='HEAD'):
+  '''Retrieves the contents of a file at the specified path and optional
+  revision (default is HEAD.) Returns its contents as a string.
+  '''
+  from subprocess import CalledProcessError
+  try:
+    return RunGit('show', ['%s:%s' % (ParseRevision(revision), path)])
+  except CalledProcessError:
+    raise FileNotFoundError('%s not found in revision %s' % (path, revision))
diff --git a/chrome/common/extensions/docs/server2/manifest_data_source.py b/chrome/common/extensions/docs/server2/manifest_data_source.py
index 635cf802..56da852 100644
--- a/chrome/common/extensions/docs/server2/manifest_data_source.py
+++ b/chrome/common/extensions/docs/server2/manifest_data_source.py
@@ -138,5 +138,5 @@
   def get(self, key):
     return self._GetCachedManifestData().get(key)
 
-  def Refresh(self, path):
+  def Refresh(self):
     return self._CreateManifestData()
diff --git a/chrome/common/extensions/docs/server2/object_store_creator.py b/chrome/common/extensions/docs/server2/object_store_creator.py
index 554912f3..91bc034e 100644
--- a/chrome/common/extensions/docs/server2/object_store_creator.py
+++ b/chrome/common/extensions/docs/server2/object_store_creator.py
@@ -4,9 +4,9 @@
 
 from cache_chain_object_store import CacheChainObjectStore
 from environment import GetAppVersion
+from environment_wrappers import CreatePersistentObjectStore
 from memcache_object_store import MemcacheObjectStore
 from test_object_store import TestObjectStore
-from persistent_object_store import PersistentObjectStore
 
 _unspecified = object()
 
@@ -76,5 +76,6 @@
     if self._store_type is not None:
       chain = (self._store_type(namespace),)
     else:
-      chain = (MemcacheObjectStore(namespace), PersistentObjectStore(namespace))
+      chain = (MemcacheObjectStore(namespace),
+               CreatePersistentObjectStore(namespace))
     return CacheChainObjectStore(chain, start_empty=start_empty)
diff --git a/chrome/common/extensions/docs/server2/owners_data_source.py b/chrome/common/extensions/docs/server2/owners_data_source.py
index 13cfc1e..21d19bf 100644
--- a/chrome/common/extensions/docs/server2/owners_data_source.py
+++ b/chrome/common/extensions/docs/server2/owners_data_source.py
@@ -102,5 +102,5 @@
       'apis': self._CollectOwnersData()
     }.get(key).Get()
 
-  def Refresh(self, path):
+  def Refresh(self):
     return self._CollectOwnersData()
diff --git a/chrome/common/extensions/docs/server2/patch_servlet.py b/chrome/common/extensions/docs/server2/patch_servlet.py
index 67eda9a..1dfb4d7 100644
--- a/chrome/common/extensions/docs/server2/patch_servlet.py
+++ b/chrome/common/extensions/docs/server2/patch_servlet.py
@@ -5,10 +5,10 @@
 from fnmatch import fnmatch
 import logging
 
-from appengine_url_fetcher import AppEngineUrlFetcher
 from caching_rietveld_patcher import CachingRietveldPatcher
 from chained_compiled_file_system import ChainedCompiledFileSystem
 from environment import IsDevServer
+from environment_wrappers import CreateUrlFetcher
 from extensions_paths import CONTENT_PROVIDERS
 from instance_servlet import InstanceServlet
 from render_servlet import RenderServlet
@@ -37,7 +37,7 @@
 
     rietveld_patcher = CachingRietveldPatcher(
         RietveldPatcher(self._issue,
-                        AppEngineUrlFetcher(url_constants.CODEREVIEW_SERVER)),
+                        CreateUrlFetcher(url_constants.CODEREVIEW_SERVER)),
         object_store_creator)
 
     patched_file_system = PatchedFileSystem(unpatched_file_system,
@@ -62,7 +62,6 @@
         combined_compiled_fs_factory,
         branch_utility,
         patched_host_file_system_provider,
-        self._delegate.CreateGithubFileSystemProvider(object_store_creator),
         CloudStorageFileSystemProvider(object_store_creator),
         base_path='/_patch/%s/' % self._issue)
 
diff --git a/chrome/common/extensions/docs/server2/patch_servlet_test.py b/chrome/common/extensions/docs/server2/patch_servlet_test.py
index 357b1d8..214cbf2 100755
--- a/chrome/common/extensions/docs/server2/patch_servlet_test.py
+++ b/chrome/common/extensions/docs/server2/patch_servlet_test.py
@@ -7,7 +7,6 @@
 import unittest
 
 from fake_fetchers import ConfigureFakeFetchers
-from github_file_system_provider import GithubFileSystemProvider
 from host_file_system_provider import HostFileSystemProvider
 from patch_servlet import PatchServlet
 from render_servlet import RenderServlet
diff --git a/chrome/common/extensions/docs/server2/permissions_data_source.py b/chrome/common/extensions/docs/server2/permissions_data_source.py
index 39bbb869..91621c4 100644
--- a/chrome/common/extensions/docs/server2/permissions_data_source.py
+++ b/chrome/common/extensions/docs/server2/permissions_data_source.py
@@ -93,5 +93,5 @@
   def get(self, key):
     return self._GetCachedPermissionsData().get(key)
 
-  def Refresh(self, path):
+  def Refresh(self):
     return self._CreatePermissionsData()
diff --git a/chrome/common/extensions/docs/server2/persistent_object_store.py b/chrome/common/extensions/docs/server2/persistent_object_store_appengine.py
similarity index 66%
rename from chrome/common/extensions/docs/server2/persistent_object_store.py
rename to chrome/common/extensions/docs/server2/persistent_object_store_appengine.py
index c0ae873..a2d0d5c 100644
--- a/chrome/common/extensions/docs/server2/persistent_object_store.py
+++ b/chrome/common/extensions/docs/server2/persistent_object_store_appengine.py
@@ -2,23 +2,26 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from appengine_wrappers import db
+import google.appengine.ext.db as db
+
 from datastore_models import PersistentObjectStoreItem
 from environment import IsDevServer
 from future import All, Future
 from object_store import ObjectStore
 
 
-class PersistentObjectStore(ObjectStore):
-  '''Stores data persistently using the AppEngine Datastore API.
+class PersistentObjectStoreAppengine(ObjectStore):
+  '''Stores or retrieves persistent data using the AppEngine Datastore API.
   '''
   def __init__(self, namespace):
     self._namespace = namespace
 
   def SetMulti(self, mapping):
-    rpcs = [db.put_async(
-        PersistentObjectStoreItem.CreateItem(self._namespace, key, value))
-        for key, value in mapping.iteritems()]
+    entities = [PersistentObjectStoreItem.CreateItem(
+                    self._namespace, key, value)
+                for key, value in mapping.iteritems()]
+    # Some entites may be None if they were too large to insert. Skip those.
+    rpcs = [db.put_async(entity for entity in entities if entity)]
     # If running the dev server, the futures don't complete until the server is
     # *quitting*. This is annoying. Flush now.
     if IsDevServer():
@@ -26,9 +29,8 @@
     return All(Future(callback=lambda: rpc.get_result()) for rpc in rpcs)
 
   def GetMulti(self, keys):
-    db_futures = dict(
-        (k, db.get_async(
-            PersistentObjectStoreItem.CreateKey(self._namespace, k)))
+    db_futures = dict((k, db.get_async(
+        PersistentObjectStoreItem.CreateKey(self._namespace, k)))
         for k in keys)
     def resolve():
       return dict((key, future.get_result().GetValue())
@@ -40,7 +42,7 @@
     futures = []
     for key in keys:
       futures.append(db.delete_async(
-        PersistentObjectStoreItem.CreateKey(self._namespace, key)))
+          PersistentObjectStoreItem.CreateKey(self._namespace, key)))
     # If running the dev server, the futures don't complete until the server is
     # *quitting*. This is annoying. Flush now.
     if IsDevServer():
diff --git a/chrome/common/extensions/docs/server2/persistent_object_store_fake.py b/chrome/common/extensions/docs/server2/persistent_object_store_fake.py
new file mode 100644
index 0000000..6d244ba
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/persistent_object_store_fake.py
@@ -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.
+
+import cPickle
+import logging
+
+from future import Future
+from object_store import ObjectStore
+
+
+class PersistentObjectStoreFake(ObjectStore):
+  '''Stores or retrieves data in memory. Not really persistent.
+  '''
+  # Static storage shared across all fake object stores.
+  DATA = {}
+
+  def __init__(self, namespace):
+    if namespace not in PersistentObjectStoreFake.DATA:
+      PersistentObjectStoreFake.DATA[namespace] = {}
+    self._data = PersistentObjectStoreFake.DATA[namespace]
+
+  def SetMulti(self, mapping):
+    self._data.update(mapping)
+    return Future(value=True)
+
+  def GetMulti(self, keys):
+    result = dict((key, self._data[key]) for key in keys if key in self._data)
+    return Future(value=result)
+
+  def DelMulti(self, keys):
+    for key in keys:
+      del self._data[key]
+
+  @classmethod
+  def LoadFromFile(cls, filename):
+    with open(filename, 'r') as f:
+      cls.DATA = cPickle.load(f)
+    for k, v in cls.DATA.iteritems():
+      cls.DATA[k] = cPickle.loads(v)
+    logging.info('Loaded %s keys from %s.' % (len(cls.DATA), filename))
+
+  @classmethod
+  def SaveToFile(cls, filename):
+    data = dict((k, cPickle.dumps(v)) for k, v, in cls.DATA.iteritems())
+    with open(filename, 'w') as f:
+      cPickle.dump(data, f)
+    logging.info('Saved %s keys to %s.' % (len(cls.DATA), filename))
diff --git a/chrome/common/extensions/docs/server2/persistent_object_store_test.py b/chrome/common/extensions/docs/server2/persistent_object_store_test.py
index 0b83aba..73b7f1f 100755
--- a/chrome/common/extensions/docs/server2/persistent_object_store_test.py
+++ b/chrome/common/extensions/docs/server2/persistent_object_store_test.py
@@ -3,7 +3,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from persistent_object_store import PersistentObjectStore
+from environment_wrappers import CreatePersistentObjectStore
 import unittest
 
 class PersistentObjectStoreTest(unittest.TestCase):
@@ -13,11 +13,11 @@
   '''
   def testPersistence(self):
     # First object store.
-    object_store = PersistentObjectStore('test')
+    object_store = CreatePersistentObjectStore('test')
     object_store.Set('key', 'value')
     self.assertEqual('value', object_store.Get('key').Get())
     # Other object store should have it too.
-    another_object_store = PersistentObjectStore('test')
+    another_object_store = CreatePersistentObjectStore('test')
     self.assertEqual('value', another_object_store.Get('key').Get())
     # Setting in the other store should set in both.
     mapping = {'key2': 'value2', 'key3': 'value3'}
@@ -31,8 +31,8 @@
     self.assertEqual({}, another_object_store.GetMulti(mapping.keys()).Get())
 
   def testNamespaceIsolation(self):
-    object_store = PersistentObjectStore('test')
-    another_object_store = PersistentObjectStore('another')
+    object_store = CreatePersistentObjectStore('test')
+    another_object_store = CreatePersistentObjectStore('another')
     object_store.Set('key', 'value')
     self.assertEqual(None, another_object_store.Get('key').Get())
 
diff --git a/chrome/common/extensions/docs/server2/platform_bundle.py b/chrome/common/extensions/docs/server2/platform_bundle.py
index d19b2f29..0316c00 100644
--- a/chrome/common/extensions/docs/server2/platform_bundle.py
+++ b/chrome/common/extensions/docs/server2/platform_bundle.py
@@ -126,11 +126,9 @@
           platform)
     return self._platform_data[platform].api_categorizer
 
-  def GetRefreshPaths(self):
-    return [platform for platform in self._platform_data.keys()]
-
-  def Refresh(self, platform):
-    return self.GetAPIModels(platform).Refresh()
+  def Refresh(self):
+    return All(self.GetAPIModels(platform).Refresh()
+               for platform in self._platform_data.keys())
 
   def GetIdentity(self):
     return self._host_fs_at_master.GetIdentity()
diff --git a/chrome/common/extensions/docs/server2/queue.yaml b/chrome/common/extensions/docs/server2/queue.yaml
deleted file mode 100644
index 3a95d696..0000000
--- a/chrome/common/extensions/docs/server2/queue.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-queue:
-  - name: default
-    rate: 4/s
-    bucket_size: 4
-    max_concurrent_requests: 4
diff --git a/chrome/common/extensions/docs/server2/refresh_servlet.py b/chrome/common/extensions/docs/server2/refresh_servlet.py
deleted file mode 100644
index 3c8d4e3..0000000
--- a/chrome/common/extensions/docs/server2/refresh_servlet.py
+++ /dev/null
@@ -1,163 +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 traceback
-
-from app_yaml_helper import AppYamlHelper
-from appengine_wrappers import IsDeadlineExceededError, logservice, taskqueue
-from branch_utility import BranchUtility
-from commit_tracker import CommitTracker
-from compiled_file_system import CompiledFileSystem
-from custom_logger import CustomLogger
-from data_source_registry import CreateDataSource
-from environment import GetAppVersion
-from file_system import IsFileSystemThrottledError
-from future import Future
-from gcs_file_system_provider import CloudStorageFileSystemProvider
-from github_file_system_provider import GithubFileSystemProvider
-from host_file_system_provider import HostFileSystemProvider
-from object_store_creator import ObjectStoreCreator
-from refresh_tracker import RefreshTracker
-from server_instance import ServerInstance
-from servlet import Servlet, Request, Response
-from timer import Timer, TimerClosure
-
-
-_log = CustomLogger('refresh')
-
-
-class RefreshServlet(Servlet):
-  '''Servlet which refreshes a single data source.
-  '''
-  def __init__(self, request, delegate_for_test=None):
-    Servlet.__init__(self, request)
-    self._delegate = delegate_for_test or RefreshServlet.Delegate()
-
-  class Delegate(object):
-    '''RefreshServlet's runtime dependencies. Override for testing.
-    '''
-    def CreateBranchUtility(self, object_store_creator):
-      return BranchUtility.Create(object_store_creator)
-
-    def CreateHostFileSystemProvider(self,
-                                     object_store_creator,
-                                     pinned_commit=None):
-      return HostFileSystemProvider(object_store_creator,
-                                    pinned_commit=pinned_commit)
-
-    def CreateGithubFileSystemProvider(self, object_store_creator):
-      return GithubFileSystemProvider(object_store_creator)
-
-    def CreateGCSFileSystemProvider(self, object_store_creator):
-      return CloudStorageFileSystemProvider(object_store_creator)
-
-    def GetAppVersion(self):
-      return GetAppVersion()
-
-  def Get(self):
-    # Manually flush logs at the end of the run. However, sometimes
-    # even that isn't enough, which is why in this file we use the
-    # custom logger and make it flush the log every time its used.
-    logservice.AUTOFLUSH_ENABLED = False
-    try:
-      return self._GetImpl()
-    except BaseException:
-      _log.error('Caught top-level exception! %s', traceback.format_exc())
-    finally:
-      logservice.flush()
-
-  def _GetImpl(self):
-    path = self._request.path.strip('/')
-    parts = self._request.path.split('/', 1)
-    source_name = parts[0]
-    if len(parts) == 2:
-      source_path = parts[1]
-    else:
-      source_path = None
-
-    _log.info('starting refresh of %s DataSource %s' %
-        (source_name, '' if source_path is None else '[%s]' % source_path))
-
-    if 'commit' in self._request.arguments:
-      commit = self._request.arguments['commit']
-    else:
-      _log.warning('No commit given; refreshing from master. '
-                   'This is probably NOT what you want.')
-      commit = None
-
-    server_instance = self._CreateServerInstance(commit)
-    commit_tracker = CommitTracker(server_instance.object_store_creator)
-    refresh_tracker = RefreshTracker(server_instance.object_store_creator)
-
-    # If no commit was given, use the ID of the last cached master commit.
-    # This allows sources external to the chromium repository to be updated
-    # independently from individual refresh cycles.
-    if commit is None:
-      commit = commit_tracker.Get('master').Get()
-
-    success = True
-    try:
-      if source_name == 'platform_bundle':
-        data_source = server_instance.platform_bundle
-      elif source_name == 'content_providers':
-        data_source = server_instance.content_providers
-      else:
-        data_source = CreateDataSource(source_name, server_instance)
-
-      class_name = data_source.__class__.__name__
-      refresh_future = data_source.Refresh(source_path)
-      assert isinstance(refresh_future, Future), (
-          '%s.Refresh() did not return a Future' % class_name)
-      timer = Timer()
-      try:
-        refresh_future.Get()
-
-        # Mark this (commit, task) pair as completed and then see if this
-        # concludes the full cache refresh. The list of tasks required to
-        # complete a cache refresh is registered (and keyed on commit ID) by the
-        # CronServlet before kicking off all the refresh tasks.
-        (refresh_tracker.MarkTaskComplete(commit, path)
-          .Then(lambda _: refresh_tracker.GetRefreshComplete(commit))
-          .Then(lambda is_complete:
-                  commit_tracker.Set('master', commit) if is_complete else None)
-          .Get())
-      except Exception as e:
-        _log.error('%s: error %s' % (class_name, traceback.format_exc()))
-        success = False
-        if IsFileSystemThrottledError(e):
-          return Response.ThrottledError('Throttled')
-        raise
-      finally:
-        _log.info('Refreshing %s took %s' %
-            (class_name, timer.Stop().FormatElapsed()))
-
-    except:
-      success = False
-      # This should never actually happen.
-      _log.error('uncaught error: %s' % traceback.format_exc())
-      raise
-    finally:
-      _log.info('finished (%s)', 'success' if success else 'FAILED')
-      return (Response.Ok('Success') if success else
-              Response.InternalError('Failure'))
-
-  def _CreateServerInstance(self, commit):
-    '''Creates a ServerInstance pinned to |commit|, or HEAD if None.
-    NOTE: If passed None it's likely that during the cron run patches will be
-    submitted at HEAD, which may change data underneath the cron run.
-    '''
-    object_store_creator = ObjectStoreCreator(start_empty=True)
-    branch_utility = self._delegate.CreateBranchUtility(object_store_creator)
-    host_file_system_provider = self._delegate.CreateHostFileSystemProvider(
-        object_store_creator, pinned_commit=commit)
-    github_file_system_provider = self._delegate.CreateGithubFileSystemProvider(
-        object_store_creator)
-    gcs_file_system_provider = self._delegate.CreateGCSFileSystemProvider(
-        object_store_creator)
-    return ServerInstance(object_store_creator,
-                          CompiledFileSystem.Factory(object_store_creator),
-                          branch_utility,
-                          host_file_system_provider,
-                          github_file_system_provider,
-                          gcs_file_system_provider)
diff --git a/chrome/common/extensions/docs/server2/refresh_tracker.py b/chrome/common/extensions/docs/server2/refresh_tracker.py
deleted file mode 100644
index e7144481..0000000
--- a/chrome/common/extensions/docs/server2/refresh_tracker.py
+++ /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.
-
-from future import All, Future
-
-
-class _RefreshWorkOrder(object):
-  '''A set of tasks that must be completed in a refresh cycle.'''
-  def __init__(self, tasks):
-    self.tasks = set(tasks)
-
-
-class _RefreshTaskCompletion(object):
-  '''Marks the completion of a single named task for some refresh cycle.'''
-  def __init__(self, task):
-    self.task = task
-
-
-def _TaskKey(refresh_id, task):
-  return '%s@%s' % (refresh_id, task)
-
-
-class RefreshTracker(object):
-  '''Manages and tracks the progress of data refresh cycles.'''
-  def __init__(self, object_store_creator):
-    # These object stores should never be created empty since they are strictly
-    # used to persist state across requests.
-    self._work_orders = object_store_creator.Create(_RefreshWorkOrder,
-        start_empty=False)
-    self._task_completions = object_store_creator.Create(_RefreshTaskCompletion,
-        start_empty=False)
-
-  def _GetWorkOrder(self, refresh_id):
-    '''Retrieves the work order for a refresh cycle identified by |id|.'''
-    return self._work_orders.Get(refresh_id)
-
-  def StartRefresh(self, refresh_id, tasks):
-    work_order = _RefreshWorkOrder(tasks)
-    return self._work_orders.Set(refresh_id, work_order)
-
-  def GetRefreshComplete(self, refresh_id):
-    '''Determines if a refresh cycle identified by |id| is complete. Returns
-    a |Future| which resolves to either |True| or |False|.'''
-    def is_work_order_complete(work_order):
-      # If the identified refresh cycle is not known, always return False.
-      if work_order is None:
-        return False
-      return (self._task_completions.GetMulti(
-                _TaskKey(refresh_id, task) for task in work_order.tasks)
-              .Then(lambda tasks: len(tasks) == len(work_order.tasks)))
-    return self._GetWorkOrder(refresh_id).Then(is_work_order_complete)
-
-  def MarkTaskComplete(self, refresh_id, task):
-    return self._task_completions.Set(_TaskKey(refresh_id, task),
-        _RefreshTaskCompletion(task))
diff --git a/chrome/common/extensions/docs/server2/refresh_tracker_test.py b/chrome/common/extensions/docs/server2/refresh_tracker_test.py
deleted file mode 100755
index f1f596f1..0000000
--- a/chrome/common/extensions/docs/server2/refresh_tracker_test.py
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env python
-# 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 unittest
-
-from object_store_creator import ObjectStoreCreator
-from refresh_tracker import RefreshTracker
-
-
-class RefreshTrackerTest(unittest.TestCase):
-  def setUp(self):
-    self._refresh_tracker = RefreshTracker(ObjectStoreCreator.ForTest())
-
-  def testNonExistentRefreshIsIncomplete(self):
-    self.assertFalse(self._refresh_tracker.GetRefreshComplete('unicorns').Get())
-
-  def testEmptyRefreshIsComplete(self):
-    refresh_id = 'abcdefghijklmnopqrstuvwxyz'
-    self._refresh_tracker.StartRefresh(refresh_id, []).Get()
-    self.assertTrue(self._refresh_tracker.GetRefreshComplete(refresh_id).Get())
-
-  def testRefreshCompletion(self):
-    refresh_id = 'this is fun'
-    self._refresh_tracker.StartRefresh(refresh_id, ['/do/foo', '/do/bar']).Get()
-    self._refresh_tracker.MarkTaskComplete(refresh_id, '/do/foo').Get()
-    self.assertFalse(self._refresh_tracker.GetRefreshComplete(refresh_id).Get())
-    self._refresh_tracker.MarkTaskComplete(refresh_id, '/do/bar').Get()
-    self.assertTrue(self._refresh_tracker.GetRefreshComplete(refresh_id).Get())
-
-  def testUnknownTasksAreIrrelevant(self):
-    refresh_id = 'i am a banana'
-    self._refresh_tracker.StartRefresh(refresh_id, ['a', 'b', 'c', 'd']).Get()
-    self._refresh_tracker.MarkTaskComplete(refresh_id, 'a').Get()
-    self._refresh_tracker.MarkTaskComplete(refresh_id, 'b').Get()
-    self._refresh_tracker.MarkTaskComplete(refresh_id, 'c').Get()
-    self._refresh_tracker.MarkTaskComplete(refresh_id, 'q').Get()
-    self.assertFalse(self._refresh_tracker.GetRefreshComplete(refresh_id).Get())
-    self._refresh_tracker.MarkTaskComplete(refresh_id, 'd').Get()
-    self.assertTrue(self._refresh_tracker.GetRefreshComplete(refresh_id).Get())
-
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/chrome/common/extensions/docs/server2/render_refresher.py b/chrome/common/extensions/docs/server2/render_refresher.py
index 0bf1978..bbad6eaf 100644
--- a/chrome/common/extensions/docs/server2/render_refresher.py
+++ b/chrome/common/extensions/docs/server2/render_refresher.py
@@ -8,7 +8,7 @@
 from custom_logger import CustomLogger
 from extensions_paths import EXAMPLES
 from file_system_util import CreateURLsFromPaths
-from future import Future
+from future import All, Future
 from render_servlet import RenderServlet
 from special_paths import SITE_VERIFICATION_FILE
 from timer import Timer
@@ -69,10 +69,7 @@
     self._server_instance = server_instance
     self._request = request
 
-  def GetRefreshPaths(self):
-    return _SUPPORTED_TARGETS.keys()
-
-  def Refresh(self, path):
+  def Refresh(self):
     def render(path):
       request = Request(path, self._request.host, self._request.headers)
       delegate = _SingletonRenderServletDelegate(self._server_instance)
@@ -92,10 +89,6 @@
                for name, _ in CreateURLsFromPaths(master_fs, path, prefix)]
       return _RequestEachItem(path, files, render)
 
-    # Only support examples for now.
-    if path not in _SUPPORTED_TARGETS:
-      return Future(callback=lambda: False)
+    return All(request_files_in_dir(dir, prefix=prefix)
+               for dir, prefix in _SUPPORTED_TARGETS.itervalues())
 
-    dir = _SUPPORTED_TARGETS[path][0]
-    prefix = _SUPPORTED_TARGETS[path][1]
-    return request_files_in_dir(dir, prefix=prefix)
diff --git a/chrome/common/extensions/docs/server2/rietveld_patcher_test.py b/chrome/common/extensions/docs/server2/rietveld_patcher_test.py
index ca0dfaf8..2dfc035d 100755
--- a/chrome/common/extensions/docs/server2/rietveld_patcher_test.py
+++ b/chrome/common/extensions/docs/server2/rietveld_patcher_test.py
@@ -7,7 +7,7 @@
 import posixpath
 import sys
 import unittest
-from appengine_url_fetcher import AppEngineUrlFetcher
+from environment_wrappers import CreateUrlFetcher
 from extensions_paths import (
     ARTICLES_TEMPLATES, CHROME_EXTENSIONS, DOCS, JSON_TEMPLATES,
     PUBLIC_TEMPLATES)
@@ -27,7 +27,7 @@
     ConfigureFakeFetchers()
     self._patcher = RietveldPatcher(
         '14096030',
-        AppEngineUrlFetcher(url_constants.CODEREVIEW_SERVER))
+        CreateUrlFetcher(url_constants.CODEREVIEW_SERVER))
 
   def _ReadLocalFile(self, filename):
     with open(Server2Path('test_data',
diff --git a/chrome/common/extensions/docs/server2/samples_data_source.py b/chrome/common/extensions/docs/server2/samples_data_source.py
index e171d79a..a259861 100644
--- a/chrome/common/extensions/docs/server2/samples_data_source.py
+++ b/chrome/common/extensions/docs/server2/samples_data_source.py
@@ -28,8 +28,5 @@
   def get(self, platform):
     return self._GetImpl(platform).Get()
 
-  def GetRefreshPaths(self):
-    return [platform for platform in GetPlatforms()]
-
-  def Refresh(self, path):
-    return self._GetImpl(path)
+  def Refresh(self):
+    return All(self._GetImpl(platform) for platform in GetPlatforms())
diff --git a/chrome/common/extensions/docs/server2/server_instance.py b/chrome/common/extensions/docs/server2/server_instance.py
index c61d875..0c1d42e 100644
--- a/chrome/common/extensions/docs/server2/server_instance.py
+++ b/chrome/common/extensions/docs/server2/server_instance.py
@@ -10,7 +10,6 @@
 from empty_dir_file_system import EmptyDirFileSystem
 from environment import IsDevServer
 from gcs_file_system_provider import CloudStorageFileSystemProvider
-from github_file_system_provider import GithubFileSystemProvider
 from host_file_system_iterator import HostFileSystemIterator
 from host_file_system_provider import HostFileSystemProvider
 from object_store_creator import ObjectStoreCreator
@@ -29,7 +28,6 @@
                compiled_fs_factory,
                branch_utility,
                host_file_system_provider,
-               github_file_system_provider,
                gcs_file_system_provider,
                base_path='/'):
     '''
@@ -45,8 +43,6 @@
     |host_file_system_provider|
         Creates FileSystem instances which host the server at alternative
         revisions.
-    |github_file_system_provider|
-        Creates FileSystem instances backed by GitHub.
     |base_path|
         The path which all HTML is generated relative to. Usually this is /
         but some servlets need to override this.
@@ -58,7 +54,6 @@
     self.host_file_system_provider = host_file_system_provider
     host_fs_at_master = host_file_system_provider.GetMaster()
 
-    self.github_file_system_provider = github_file_system_provider
     self.gcs_file_system_provider = gcs_file_system_provider
 
     assert base_path.startswith('/') and base_path.endswith('/')
@@ -80,7 +75,6 @@
         object_store_creator,
         self.compiled_fs_factory,
         host_fs_at_master,
-        self.github_file_system_provider,
         self.gcs_file_system_provider)
 
     # TODO(kalman): Move all the remaining DataSources into DataSourceRegistry,
@@ -114,7 +108,6 @@
                           CompiledFileSystem.Factory(object_store_creator),
                           TestBranchUtility.CreateWithCannedData(),
                           file_system_provider,
-                          GithubFileSystemProvider.ForEmpty(),
                           CloudStorageFileSystemProvider(object_store_creator),
                           base_path=base_path)
 
@@ -129,5 +122,4 @@
         CompiledFileSystem.Factory(object_store_creator),
         TestBranchUtility.CreateWithCannedData(),
         host_file_system_provider,
-        GithubFileSystemProvider.ForEmpty(),
         CloudStorageFileSystemProvider(object_store_creator))
diff --git a/chrome/common/extensions/docs/server2/servlet.py b/chrome/common/extensions/docs/server2/servlet.py
index 3a674123..c9ac5683 100644
--- a/chrome/common/extensions/docs/server2/servlet.py
+++ b/chrome/common/extensions/docs/server2/servlet.py
@@ -103,6 +103,21 @@
     return Response(content=content, headers=headers, status=400)
 
   @staticmethod
+  def Unauthorized(content, method, realm, headers={}):
+    '''Returns an unauthorized (401) response.
+    '''
+    new_headers = headers.copy()
+    new_headers.update({
+      'WWW-Authentication': '%s realm="%s"' % (method, realm)})
+    return Response(content=content, headers=headers, status=401)
+
+  @staticmethod
+  def Forbidden(content, headers=None):
+    '''Returns an forbidden (403) response.
+    '''
+    return Response(content=content, headers=headers, status=403)
+
+  @staticmethod
   def NotFound(content, headers=None):
     '''Returns a not found (404) response.
     '''
diff --git a/chrome/common/extensions/docs/server2/sidenav_data_source.py b/chrome/common/extensions/docs/server2/sidenav_data_source.py
index ca51aec..fd06d40 100644
--- a/chrome/common/extensions/docs/server2/sidenav_data_source.py
+++ b/chrome/common/extensions/docs/server2/sidenav_data_source.py
@@ -92,7 +92,7 @@
           href = href.lstrip('/')
         item['href'] = self._server_instance.base_path + href
 
-  def Refresh(self, path=None):
+  def Refresh(self):
     return self._cache.GetFromFile(
         posixpath.join(JSON_TEMPLATES, 'chrome_sidenav.json'))
 
diff --git a/chrome/common/extensions/docs/server2/strings_data_source.py b/chrome/common/extensions/docs/server2/strings_data_source.py
index 28b1e1f..0742f0aa 100644
--- a/chrome/common/extensions/docs/server2/strings_data_source.py
+++ b/chrome/common/extensions/docs/server2/strings_data_source.py
@@ -19,7 +19,7 @@
   def _GetStringsData(self):
     return self._cache.GetFromFile('%sstrings.json' % JSON_TEMPLATES)
 
-  def Refresh(self, path):
+  def Refresh(self):
     return self._GetStringsData()
 
   def get(self, key):
diff --git a/chrome/common/extensions/docs/server2/subversion_file_system.py b/chrome/common/extensions/docs/server2/subversion_file_system.py
deleted file mode 100644
index 949bca9..0000000
--- a/chrome/common/extensions/docs/server2/subversion_file_system.py
+++ /dev/null
@@ -1,209 +0,0 @@
-# Copyright (c) 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.
-
-import posixpath
-import traceback
-import xml.dom.minidom as xml
-from xml.parsers.expat import ExpatError
-
-from appengine_url_fetcher import AppEngineUrlFetcher
-from appengine_wrappers import IsDownloadError
-from docs_server_utils import StringIdentity
-from file_system import (
-    FileNotFoundError, FileSystem, FileSystemError, StatInfo)
-from future import Future
-import url_constants
-
-
-def _ParseHTML(html):
-  '''Unfortunately, the viewvc page has a stray </div> tag, so this takes care
-  of all mismatched tags.
-  '''
-  try:
-    return xml.parseString(html)
-  except ExpatError as e:
-    return _ParseHTML('\n'.join(
-        line for (i, line) in enumerate(html.split('\n'))
-        if e.lineno != i + 1))
-
-def _InnerText(node):
-  '''Like node.innerText in JS DOM, but strips surrounding whitespace.
-  '''
-  text = []
-  if node.nodeValue:
-    text.append(node.nodeValue)
-  if hasattr(node, 'childNodes'):
-    for child_node in node.childNodes:
-      text.append(_InnerText(child_node))
-  return ''.join(text).strip()
-
-def _CreateStatInfo(html):
-  parent_version = None
-  child_versions = {}
-
-  # Try all of the tables until we find the ones that contain the data (the
-  # directory and file versions are in different tables).
-  for table in _ParseHTML(html).getElementsByTagName('table'):
-    # Within the table there is a list of files. However, there may be some
-    # things beforehand; a header, "parent directory" list, etc. We will deal
-    # with that below by being generous and just ignoring such rows.
-    rows = table.getElementsByTagName('tr')
-
-    for row in rows:
-      cells = row.getElementsByTagName('td')
-
-      # The version of the directory will eventually appear in the soup of
-      # table rows, like this:
-      #
-      # <tr>
-      #   <td>Directory revision:</td>
-      #   <td><a href=... title="Revision 214692">214692</a> (of...)</td>
-      # </tr>
-      #
-      # So look out for that.
-      if len(cells) == 2 and _InnerText(cells[0]) == 'Directory revision:':
-        links = cells[1].getElementsByTagName('a')
-        if len(links) != 2:
-          raise FileSystemError('ViewVC assumption invalid: directory ' +
-                                'revision content did not have 2 <a> ' +
-                                ' elements, instead %s' % _InnerText(cells[1]))
-        this_parent_version = _InnerText(links[0])
-        int(this_parent_version)  # sanity check
-        if parent_version is not None:
-          raise FileSystemError('There was already a parent version %s, and ' +
-                                ' we just found a second at %s' %
-                                (parent_version, this_parent_version))
-        parent_version = this_parent_version
-
-      # The version of each file is a list of rows with 5 cells: name, version,
-      # age, author, and last log entry. Maybe the columns will change; we're
-      # at the mercy viewvc, but this constant can be easily updated.
-      if len(cells) != 5:
-        continue
-      name_element, version_element, _, __, ___ = cells
-
-      name = _InnerText(name_element)  # note: will end in / for directories
-      try:
-        version = int(_InnerText(version_element))
-      except StandardError:
-        continue
-      child_versions[name] = str(version)
-
-    if parent_version and child_versions:
-      break
-
-  return StatInfo(parent_version, child_versions)
-
-
-class SubversionFileSystem(FileSystem):
-  '''Class to fetch resources from src.chromium.org.
-  '''
-  @staticmethod
-  def Create(branch='trunk', revision=None):
-    if branch == 'trunk':
-      svn_path = 'trunk/src'
-    else:
-      svn_path = 'branches/%s/src' % branch
-    return SubversionFileSystem(
-        AppEngineUrlFetcher('%s/%s' % (url_constants.SVN_URL, svn_path)),
-        AppEngineUrlFetcher('%s/%s' % (url_constants.VIEWVC_URL, svn_path)),
-        svn_path,
-        revision=revision)
-
-  def __init__(self, file_fetcher, stat_fetcher, svn_path, revision=None):
-    self._file_fetcher = file_fetcher
-    self._stat_fetcher = stat_fetcher
-    self._svn_path = svn_path
-    self._revision = revision
-
-  def Read(self, paths, skip_not_found=False):
-    args = None
-    if self._revision is not None:
-      # |fetcher| gets from svn.chromium.org which uses p= for version.
-      args = 'p=%s' % self._revision
-
-    def apply_args(path):
-      return path if args is None else '%s?%s' % (path, args)
-
-    def list_dir(directory):
-      dom = xml.parseString(directory)
-      files = [elem.childNodes[0].data
-               for elem in dom.getElementsByTagName('a')]
-      if '..' in files:
-        files.remove('..')
-      return files
-
-    # A list of tuples of the form (path, Future).
-    fetches = [(path, self._file_fetcher.FetchAsync(apply_args(path)))
-               for path in paths]
-
-    def resolve():
-      value = {}
-      for path, future in fetches:
-        try:
-          result = future.Get()
-        except Exception as e:
-          if skip_not_found and IsDownloadError(e): continue
-          exc_type = (FileNotFoundError if IsDownloadError(e)
-                                       else FileSystemError)
-          raise exc_type('%s fetching %s for Get: %s' %
-                         (type(e).__name__, path, traceback.format_exc()))
-        if result.status_code == 404:
-          if skip_not_found: continue
-          raise FileNotFoundError(
-              'Got 404 when fetching %s for Get, content %s' %
-              (path, result.content))
-        if result.status_code != 200:
-          raise FileSystemError('Got %s when fetching %s for Get, content %s' %
-              (result.status_code, path, result.content))
-        if path.endswith('/'):
-          value[path] = list_dir(result.content)
-        else:
-          value[path] = result.content
-      return value
-    return Future(callback=resolve)
-
-  def Refresh(self):
-    return Future(value=())
-
-  def StatAsync(self, path):
-    directory, filename = posixpath.split(path)
-    if self._revision is not None:
-      # |stat_fetch| uses viewvc which uses pathrev= for version.
-      directory += '?pathrev=%s' % self._revision
-
-    result_future = self._stat_fetcher.FetchAsync(directory)
-    def resolve():
-      try:
-        result = result_future.Get()
-      except Exception as e:
-        exc_type = FileNotFoundError if IsDownloadError(e) else FileSystemError
-        raise exc_type('%s fetching %s for Stat: %s' %
-                       (type(e).__name__, path, traceback.format_exc()))
-
-      if result.status_code == 404:
-        raise FileNotFoundError('Got 404 when fetching %s for Stat, '
-                                'content %s' % (path, result.content))
-      if result.status_code != 200:
-        raise FileNotFoundError('Got %s when fetching %s for Stat, content %s' %
-                                (result.status_code, path, result.content))
-
-      stat_info = _CreateStatInfo(result.content)
-      if stat_info.version is None:
-        raise FileSystemError('Failed to find version of dir %s' % directory)
-      if path == '' or path.endswith('/'):
-        return stat_info
-      if filename not in stat_info.child_versions:
-        raise FileNotFoundError(
-            '%s from %s was not in child versions for Stat' % (filename, path))
-      return StatInfo(stat_info.child_versions[filename])
-
-    return Future(callback=resolve)
-
-  def GetIdentity(self):
-    # NOTE: no revision here, since it would mess up the caching of reads. It
-    # probably doesn't matter since all the caching classes will use the result
-    # of Stat to decide whether to re-read - and Stat has a ceiling of the
-    # revision - so when the revision changes, so might Stat. That is enough.
-    return '@'.join((self.__class__.__name__, StringIdentity(self._svn_path)))
diff --git a/chrome/common/extensions/docs/server2/subversion_file_system_test.py b/chrome/common/extensions/docs/server2/subversion_file_system_test.py
deleted file mode 100755
index edc32df..0000000
--- a/chrome/common/extensions/docs/server2/subversion_file_system_test.py
+++ /dev/null
@@ -1,143 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 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.
-
-import json
-import os
-import unittest
-
-from extensions_paths import SERVER2
-from fake_url_fetcher import FakeUrlFetcher
-from file_system import FileSystemError, StatInfo
-from subversion_file_system import SubversionFileSystem
-from test_util import ReadFile, Server2Path
-
-
-_SHARED_FILE_SYSTEM_TEST_DATA = Server2Path('test_data', 'file_system')
-_SUBVERSION_FILE_SYSTEM_TEST_DATA = Server2Path(
-    'test_data', 'subversion_file_system')
-
-
-def _CreateSubversionFileSystem(path):
-  fetcher = FakeUrlFetcher(path)
-  return SubversionFileSystem(fetcher, fetcher, path), fetcher
-
-
-class SubversionFileSystemTest(unittest.TestCase):
-  def testReadFiles(self):
-    expected = {
-      'test1.txt': 'test1\n',
-      'test2.txt': 'test2\n',
-      'test3.txt': 'test3\n',
-    }
-    file_system, fetcher = _CreateSubversionFileSystem(
-        _SHARED_FILE_SYSTEM_TEST_DATA)
-    read_future = file_system.Read(['test1.txt', 'test2.txt', 'test3.txt'])
-    self.assertTrue(*fetcher.CheckAndReset(async_count=3))
-    self.assertEqual(expected, read_future.Get())
-    self.assertTrue(*fetcher.CheckAndReset(async_resolve_count=3))
-
-  def testListDir(self):
-    expected = ['dir/'] + ['file%d.html' % i for i in range(7)]
-    file_system, fetcher = _CreateSubversionFileSystem(
-        _SHARED_FILE_SYSTEM_TEST_DATA)
-    list_future = file_system.ReadSingle('list/')
-    self.assertTrue(*fetcher.CheckAndReset(async_count=1))
-    self.assertEqual(expected, sorted(list_future.Get()))
-    self.assertTrue(*fetcher.CheckAndReset(async_resolve_count=1))
-
-  def testListSubDir(self):
-    expected = ['empty.txt'] + ['file%d.html' % i for i in range(3)]
-    file_system, fetcher = _CreateSubversionFileSystem(
-        _SHARED_FILE_SYSTEM_TEST_DATA)
-    list_future = file_system.ReadSingle('list/dir/')
-    self.assertTrue(*fetcher.CheckAndReset(async_count=1))
-    self.assertEqual(expected, sorted(list_future.Get()))
-    self.assertTrue(*fetcher.CheckAndReset(async_resolve_count=1))
-
-  def testDirStat(self):
-    file_system, fetcher = _CreateSubversionFileSystem(
-        _SHARED_FILE_SYSTEM_TEST_DATA)
-    stat_info = file_system.Stat('stat/')
-    self.assertTrue(*fetcher.CheckAndReset(async_count=1,
-                                           async_resolve_count=1))
-    expected = StatInfo(
-      '151113',
-      child_versions=json.loads(ReadFile(
-          SERVER2, 'test_data', 'file_system', 'stat_result.json')))
-    self.assertEqual(expected, stat_info)
-
-  def testFileStat(self):
-    file_system, fetcher = _CreateSubversionFileSystem(
-        _SHARED_FILE_SYSTEM_TEST_DATA)
-    stat_info = file_system.Stat('stat/extension_api.h')
-    self.assertTrue(*fetcher.CheckAndReset(async_count=1,
-                                           async_resolve_count=1))
-    self.assertEqual(StatInfo('146163'), stat_info)
-
-  def testRevisions(self):
-    # This is a super hacky test. Record the path that was fetched then exit the
-    # test. Compare.
-    class ValueErrorFetcher(object):
-      def __init__(self):
-        self.last_fetched = None
-
-      def FetchAsync(self, path):
-        class ThrowsValueError(object):
-          def Get(self): raise ValueError()
-        self.last_fetched = path
-        return ThrowsValueError()
-
-      def Fetch(self, path, **kwargs):
-        self.last_fetched = path
-        raise ValueError()
-
-    file_fetcher = ValueErrorFetcher()
-    stat_fetcher = ValueErrorFetcher()
-    svn_path = 'svn:'
-
-    svn_file_system = SubversionFileSystem(file_fetcher,
-                                           stat_fetcher,
-                                           svn_path,
-                                           revision=42)
-
-    self.assertRaises(FileSystemError,
-                      svn_file_system.ReadSingle('dir/file').Get)
-    self.assertEqual('dir/file?p=42', file_fetcher.last_fetched)
-    # Stat() will always stat directories.
-    self.assertRaises(FileSystemError, svn_file_system.Stat, 'dir/file')
-    self.assertEqual('dir?pathrev=42', stat_fetcher.last_fetched)
-
-    self.assertRaises(FileSystemError,
-                      svn_file_system.ReadSingle('dir/').Get)
-    self.assertEqual('dir/?p=42', file_fetcher.last_fetched)
-    self.assertRaises(FileSystemError, svn_file_system.Stat, 'dir/')
-    self.assertEqual('dir?pathrev=42', stat_fetcher.last_fetched)
-
-  def testDirectoryVersionOnDeletion(self):
-    '''Tests the case when the most recent operation on a directory is the
-    deletion of a file. Here it is not enough to take the maximum version of all
-    files in the directory, as we used to, for obvious reasons.
-    '''
-    file_system, _ = _CreateSubversionFileSystem(
-        _SUBVERSION_FILE_SYSTEM_TEST_DATA)
-    dir_stat = file_system.Stat('docs_public_extensions_214898/')
-    self.assertEqual('214692', dir_stat.version)
-
-  def testEmptyDirectory(self):
-    file_system, _ = _CreateSubversionFileSystem(
-        _SUBVERSION_FILE_SYSTEM_TEST_DATA)
-    dir_stat = file_system.Stat('api_icons_214898/')
-    self.assertEqual('193838', dir_stat.version)
-    self.assertEqual({}, dir_stat.child_versions)
-
-    def testSkipNotFound(self):
-      file_system, _ = _CreateSubversionFileSystem(
-          _SUBVERSION_FILE_SYSTEM_TEST_DATA)
-      self.assertEqual({}, file_system.Read(('fakefile',),
-                                            skip_not_found=True).Get())
-
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/chrome/common/extensions/docs/server2/template_data_source.py b/chrome/common/extensions/docs/server2/template_data_source.py
index 1010bf21..0fdad5c 100644
--- a/chrome/common/extensions/docs/server2/template_data_source.py
+++ b/chrome/common/extensions/docs/server2/template_data_source.py
@@ -34,7 +34,7 @@
       logging.warning(traceback.format_exc())
       return None
 
-  def Refresh(self, path):
+  def Refresh(self):
     futures = []
     for root, _, files in self._file_system.Walk(self._dir):
       futures += [self._template_cache.GetFromFile(
diff --git a/chrome/common/extensions/docs/server2/update_cache.py b/chrome/common/extensions/docs/server2/update_cache.py
new file mode 100644
index 0000000..40aace3f
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/update_cache.py
@@ -0,0 +1,206 @@
+# 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 cPickle
+import copy
+import getopt
+import json
+import logging
+import os.path
+import sys
+import traceback
+
+from branch_utility import BranchUtility
+from commit_tracker import CommitTracker
+from compiled_file_system import CompiledFileSystem
+from data_source_registry import CreateDataSources
+from environment import GetAppVersion
+from environment_wrappers import CreateUrlFetcher, GetAccessToken
+from future import All
+from gcs_file_system_provider import CloudStorageFileSystemProvider
+from host_file_system_provider import HostFileSystemProvider
+from local_git_util import ParseRevision
+from object_store_creator import ObjectStoreCreator
+from persistent_object_store_fake import PersistentObjectStoreFake
+from render_refresher import RenderRefresher
+from server_instance import ServerInstance
+from timer import Timer
+
+
+# The path template to use for flushing the memcached. Should be formatted with
+# with the app version.
+_FLUSH_MEMCACHE_PATH = ('https://%s-dot-chrome-apps-doc.appspot.com/'
+                        '_flush_memcache')
+
+
+def _UpdateCommitId(commit_name, commit_id):
+  '''Sets the commit ID for a named commit. This is the final step performed
+  during update. Once all the appropriate datastore entries have been populated
+  for a new commit ID, the 'master' commit entry is updated to that ID and the
+  frontend will begin serving the new data.
+
+  Note that this requires an access token identifying the main service account
+  for the chrome-apps-doc project. VM instances will get this automatically
+  from their environment, but if you want to do a local push to prod you will
+  need to set the DOCSERVER_ACCESS_TOKEN environment variable appropriately.
+  '''
+  commit_tracker = CommitTracker(
+      ObjectStoreCreator(store_type=PersistentObjectStoreFake,
+                         start_empty=False))
+  commit_tracker.Set(commit_name, commit_id).Get()
+  logging.info('Commit "%s" updated to %s.' % (commit_name, commit_id))
+
+
+def _GetCachedCommitId(commit_name):
+  '''Determines which commit ID was last cached.
+  '''
+  commit_tracker = CommitTracker(
+      ObjectStoreCreator(store_type=PersistentObjectStoreFake,
+                         start_empty=False))
+  return commit_tracker.Get(commit_name).Get()
+
+
+def _FlushMemcache():
+  '''Requests that the frontend flush its memcached to avoid serving stale data.
+  '''
+  flush_url = _FLUSH_MEMCACHE_PATH % GetAppVersion()
+  headers = { 'Authorization': 'Bearer %s' % GetAccessToken() }
+  response = CreateUrlFetcher().Fetch(flush_url, headers)
+  if response.status_code != 200:
+    logging.error('Unable to flush memcache: HTTP %s (%s)' %
+                  (response.status_code, response.content))
+  else:
+    logging.info('Memcache flushed.')
+
+
+def _CreateServerInstance(commit):
+  '''Creates a ServerInstance based on origin/master.
+  '''
+  object_store_creator = ObjectStoreCreator(
+      start_empty=False, store_type=PersistentObjectStoreFake)
+  branch_utility = BranchUtility.Create(object_store_creator)
+  host_file_system_provider = HostFileSystemProvider(object_store_creator,
+                                                     pinned_commit=commit)
+  gcs_file_system_provider = CloudStorageFileSystemProvider(
+      object_store_creator)
+  return ServerInstance(object_store_creator,
+                        CompiledFileSystem.Factory(object_store_creator),
+                        branch_utility,
+                        host_file_system_provider,
+                        gcs_file_system_provider)
+
+
+def _UpdateDataSource(name, data_source):
+  try:
+    class_name = data_source.__class__.__name__
+    timer = Timer()
+    logging.info('Updating %s...' % name)
+    data_source.Refresh().Get()
+  except Exception as e:
+    logging.error('%s: error %s' % (class_name, traceback.format_exc()))
+    raise e
+  finally:
+    logging.info('Updating %s took %s' % (name, timer.Stop().FormatElapsed()))
+
+
+def UpdateCache(single_data_source=None, commit=None):
+  '''Attempts to populate the datastore with a bunch of information derived from
+  a given commit.
+  '''
+  server_instance = _CreateServerInstance(commit)
+
+  # This is the guy that would be responsible for refreshing the cache of
+  # examples. Here for posterity, hopefully it will be added to the targets
+  # below someday.
+  # render_refresher = RenderRefresher(server_instance, self._request)
+
+  data_sources = CreateDataSources(server_instance)
+  data_sources['content_providers'] = server_instance.content_providers
+  data_sources['platform_bundle'] = server_instance.platform_bundle
+  if single_data_source:
+    _UpdateDataSource(single_data_source, data_sources[single_data_source])
+  else:
+    for name, source in data_sources.iteritems():
+      _UpdateDataSource(name, source)
+
+
+def _Main(argv):
+  try:
+    opts = dict((name[2:], value) for name, value in
+                getopt.getopt(argv, '',
+                              ['load-file=', 'data-source=', 'commit=',
+                               'no-refresh', 'no-push', 'save-file=',
+                               'no-master-update', 'push-all', 'force'])[0])
+  except getopt.GetoptError as e:
+    print '%s\n' % e
+    print (
+    'Usage: update_cache.py [options]\n\n'
+    'Options:\n'
+    '  --data-source=NAME        Limit update to a single data source.\n'
+    '  --load-file=FILE          Load object store data from FILE before\n'
+    '                            starting the update.\n'
+    '  --save-file=FILE          Save object store data to FILE after running\n'
+    '                            the update.\n'
+    '  --no-refresh              Do not attempt to update any data sources.\n'
+    '  --no-push                 Do not push to Datastore.\n'
+    '  --commit=REV              Commit ID to use for master update.\n'
+    '  --no-master-update        Do not update the master commit ID.\n'
+    '  --push-all                Push all entities to the Datastore even if\n'
+    '                            they do not differ from the loaded cache.\n\n'
+    '  --force                   Force an update even if the latest commit is'
+    '                            already cached.\n')
+    exit(1)
+
+  logging.getLogger().setLevel(logging.INFO)
+
+  data_source = opts.get('data-source', None)
+  load_file = opts.get('load-file', None)
+  save_file = opts.get('save-file', None)
+  do_refresh = 'no-refresh' not in opts
+  do_push = 'no-push' not in opts
+  do_master_update = 'no-master-update' not in opts
+  push_all = do_push and ('push-all' in opts)
+  commit = ParseRevision(opts.get('commit', 'origin/HEAD'))
+  force_update = 'force' in opts
+
+  original_data = {}
+  if load_file:
+    logging.info('Loading cache...')
+    PersistentObjectStoreFake.LoadFromFile(load_file)
+    if not push_all:
+      original_data = copy.deepcopy(PersistentObjectStoreFake.DATA)
+
+  last_commit = _GetCachedCommitId('master')
+  if ParseRevision(commit) == last_commit and not force_update:
+    logging.info('Latest cache (revision %s) is up to date. Bye.' % commit)
+    exit(0)
+
+  timer = Timer()
+  if do_refresh:
+    logging.info('Starting refresh from commit %s...' % ParseRevision(commit))
+    if data_source:
+      UpdateCache(single_data_source=data_source,
+                   commit=commit)
+    else:
+      UpdateCache(commit=commit)
+
+  if do_push:
+    from datastore_util import PushData
+    if do_master_update:
+      _UpdateCommitId('master', commit)
+    push_timer = Timer()
+    logging.info('Pushing data into datastore...')
+    PushData(PersistentObjectStoreFake.DATA, original_data=original_data)
+    logging.info('Done. Datastore push took %s' %
+                 push_timer.Stop().FormatElapsed())
+    _FlushMemcache()
+  if save_file:
+    PersistentObjectStoreFake.SaveToFile(save_file)
+
+  logging.info('Update completed in %s' % timer.Stop().FormatElapsed())
+
+
+if __name__ == '__main__':
+  _Main(sys.argv[1:])
+
diff --git a/chrome/common/extensions/docs/server2/url_constants.py b/chrome/common/extensions/docs/server2/url_constants.py
index 9fc3061..f45a369 100644
--- a/chrome/common/extensions/docs/server2/url_constants.py
+++ b/chrome/common/extensions/docs/server2/url_constants.py
@@ -2,11 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-GITILES_BASE = 'https://chromium.googlesource.com'
-GITILES_SRC_ROOT = 'chromium/src/+'
-GITILES_BRANCHES_PATH = 'refs/branch-heads'
-GITILES_OAUTH2_SCOPE = 'https://www.googleapis.com/auth/gerritcodereview'
-
 GITHUB_REPOS = 'https://api.github.com/repos'
 GITHUB_BASE = 'https://github.com/GoogleChrome/chrome-app-samples/tree/master/samples'
 RAW_GITHUB_BASE = ('https://github.com/GoogleChrome/chrome-app-samples/raw/'
diff --git a/chrome/common/extensions/docs/server2/url_fetcher.py b/chrome/common/extensions/docs/server2/url_fetcher.py
new file mode 100644
index 0000000..9daa5fa
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/url_fetcher.py
@@ -0,0 +1,60 @@
+# 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 posixpath
+
+from environment import GetAppVersion
+from future import Future
+from urllib import urlencode
+from urlparse import urlparse, parse_qs
+
+def _MakeHeaders(headers={}):
+  headers['User-Agent'] = 'Chomium docserver %s' % GetAppVersion()
+  headers['Cache-Control'] = 'max-age=0'
+  return headers
+
+
+def _AddQueryToUrl(url, new_query):
+  """Adds query paramters to a URL. This merges the given set of query params
+  with any that were already a part of the URL.
+  """
+  parsed_url = urlparse(url)
+  query = parse_qs(parsed_url.query)
+  query.update(new_query)
+  query_string = urlencode(query, True)
+  return '%s://%s%s?%s#%s' % (parsed_url.scheme, parsed_url.netloc,
+      parsed_url.path, query_string, parsed_url.fragment)
+
+
+class UrlFetcher(object):
+  def __init__(self):
+    self._base_path = None
+
+  def SetBasePath(self, base_path):
+    assert base_path is None or not base_path.endswith('/'), base_path
+    self._base_path = base_path
+
+  def Fetch(self, url, headers={}, query={}):
+    return self.FetchImpl(_AddQueryToUrl(self._FromBasePath(url), query),
+        _MakeHeaders(headers))
+
+  def FetchAsync(self, url, headers={}, query={}):
+    return self.FetchAsyncImpl(_AddQueryToUrl(self._FromBasePath(url), query),
+        _MakeHeaders(headers))
+
+  def FetchImpl(self, url, headers):
+    """Fetches a URL synchronously.
+    """
+    raise NotImplementedError(self.__class__)
+
+  def FetchAsyncImpl(self, url, headers):
+    """Fetches a URL asynchronously and returns a Future with the result.
+    """
+    raise NotImplementedError(self.__class__)
+
+  def _FromBasePath(self, url):
+    assert not url.startswith('/'), url
+    if self._base_path is not None:
+      url = posixpath.join(self._base_path, url) if url else self._base_path
+    return url
diff --git a/chrome/common/extensions/docs/server2/url_fetcher_appengine.py b/chrome/common/extensions/docs/server2/url_fetcher_appengine.py
new file mode 100644
index 0000000..f5080aeb
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/url_fetcher_appengine.py
@@ -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.
+
+import google.appengine.api.urlfetch as urlfetch
+import logging
+import time
+import traceback
+
+from future import Future
+from url_fetcher import UrlFetcher
+
+
+_MAX_RETRIES = 5
+_RETRY_DELAY_SECONDS = 30
+
+
+class UrlFetcherAppengine(UrlFetcher):
+  """An implementation of UrlFetcher which uses the GAE urlfetch API to
+  execute URL fetches.
+  """
+  def __init__(self):
+    self._retries_left = _MAX_RETRIES
+
+  def FetchImpl(self, url, headers):
+    return urlfetch.fetch(url, deadline=20, headers=headers)
+
+  def FetchAsyncImpl(self, url, headers):
+    def process_result(result):
+      if result.status_code == 429:
+        if self._retries_left == 0:
+          logging.error('Still throttled. Giving up.')
+          return result
+        self._retries_left -= 1
+        logging.info('Throttled. Trying again in %s seconds.' %
+                     _RETRY_DELAY_SECONDS)
+        time.sleep(_RETRY_DELAY_SECONDS)
+        return self.FetchAsync(url, username, password, access_token).Get()
+      return result
+
+    rpc = urlfetch.create_rpc(deadline=20)
+    urlfetch.make_fetch_call(rpc, url, headers=headers)
+    return Future(callback=lambda: process_result(rpc.get_result()))
diff --git a/chrome/common/extensions/docs/server2/url_fetcher_fake.py b/chrome/common/extensions/docs/server2/url_fetcher_fake.py
new file mode 100644
index 0000000..0365e3f
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/url_fetcher_fake.py
@@ -0,0 +1,62 @@
+# 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 logging
+import re
+import time
+
+from environment import IsAppEngine
+from future import Future
+from url_fetcher import UrlFetcher
+
+
+FAKE_URL_FETCHER_CONFIGURATION = None
+
+
+def ConfigureFakeUrlFetch(configuration):
+  """|configuration| is a dictionary mapping strings to fake urlfetch classes.
+  A fake urlfetch class just needs to have a fetch method. The keys of the
+  dictionary are treated as regex, and they are matched with the URL to
+  determine which fake urlfetch is used.
+  """
+  global FAKE_URL_FETCHER_CONFIGURATION
+  FAKE_URL_FETCHER_CONFIGURATION = dict(
+      (re.compile(k), v) for k, v in configuration.iteritems())
+
+
+def _GetConfiguration(key):
+  if not FAKE_URL_FETCHER_CONFIGURATION:
+    raise ValueError('No fake fetch paths have been configured. '
+                     'See ConfigureFakeUrlFetch in url_fetcher_fake.py.')
+  for k, v in FAKE_URL_FETCHER_CONFIGURATION.iteritems():
+    if k.match(key):
+      return v
+  raise ValueError('No configuration found for %s' % key)
+
+
+class UrlFetcherFake(UrlFetcher):
+  """A fake UrlFetcher implementation which may be configured with manual URL
+  overrides for testing. By default this 404s on everything.
+  """
+  class DownloadError(Exception):
+    pass
+
+  class _Response(object):
+    def __init__(self, content):
+      self.content = content
+      self.headers = {'Content-Type': 'none'}
+      self.status_code = 200
+
+  def FetchImpl(self, url, headers):
+    if IsAppEngine():
+      raise ValueError('Attempted to fetch URL from AppEngine: %s' % url)
+
+    url = url.split('?', 1)[0]
+    response = self._Response(_GetConfiguration(url).fetch(url))
+    if response.content is None:
+      response.status_code = 404
+    return response
+
+  def FetchAsyncImpl(self, url, headers):
+    return Future(callback=lambda: self.FetchImpl(url, headers))
diff --git a/chrome/common/extensions/docs/server2/url_fetcher_urllib2.py b/chrome/common/extensions/docs/server2/url_fetcher_urllib2.py
new file mode 100644
index 0000000..211deaa1
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/url_fetcher_urllib2.py
@@ -0,0 +1,35 @@
+# 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 logging
+import time
+
+from future import Future
+from url_fetcher import UrlFetcher
+from urllib2 import urlopen, Request, HTTPError
+
+
+class UrlFetcherUrllib2(UrlFetcher):
+  """UrlFetcher implementation for use outside of AppEngine. Does NOT support
+  async fetching, so FetchAsync calls are still blocking.
+  """
+  class _Response(object):
+    def __init__(self, code, content=None, headers={}):
+      self.status_code = code
+      self.content = content
+      self.headers = headers
+
+  def FetchImpl(self, url, headers):
+    request = Request(url, headers=headers)
+    try:
+      urlresponse = urlopen(request)
+      response = self._Response(urlresponse.code, urlresponse.read(),
+                                urlresponse.headers.dict)
+      urlresponse.close()
+      return response
+    except HTTPError as e:
+      return self._Response(e.code, e.reason, e.headers.dict)
+
+  def FetchAsyncImpl(self, url, headers):
+    return Future(callback=lambda: self.FetchImpl(url, headers))
diff --git a/chrome/common/extensions/docs/server2/whats_new_data_source.py b/chrome/common/extensions/docs/server2/whats_new_data_source.py
index 67834a9..1ab75b4 100644
--- a/chrome/common/extensions/docs/server2/whats_new_data_source.py
+++ b/chrome/common/extensions/docs/server2/whats_new_data_source.py
@@ -96,5 +96,5 @@
   def get(self, key):
     return self._GetCachedWhatsNewData().get(key)
 
-  def Refresh(self, path):
+  def Refresh(self):
     return self._GenerateWhatsNewDict()
diff --git a/chrome/common/extensions/docs/templates/public/apps/inform_users.html b/chrome/common/extensions/docs/templates/public/apps/inform_users.html
deleted file mode 100644
index eb80665..0000000
--- a/chrome/common/extensions/docs/templates/public/apps/inform_users.html
+++ /dev/null
@@ -1 +0,0 @@
-{{+partials.standard_apps_article article:articles.inform_users/}}
diff --git a/chrome/common/extensions/docs/templates/public/apps/mdns.html b/chrome/common/extensions/docs/templates/public/apps/mdns.html
new file mode 100644
index 0000000..1fdc2aa9
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/public/apps/mdns.html
@@ -0,0 +1 @@
+{{+partials.standard_apps_api api:apis.apps.mdns/}}
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 341814db..b944852 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -59,8 +59,7 @@
 const char kChromeVoxExtensionId[] =
     "mndnfokpggljbaajbnioimlmbfngpief";
 const char kChromeVoxExtensionPath[] = "chromeos/chromevox";
-const char kChromeVoxManifestFilename[] = "manifest.json";
-const char kChromeVoxGuestManifestFilename[] = "manifest_guest.json";
+const char kGuestManifestFilename[] = "manifest_guest.json";
 const char kBrailleImeExtensionId[] =
     "jddehjeebkoimngcbdkaahpobgicbffp";
 const char kBrailleImeExtensionPath[] =
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index 42d3d17..3d66f8da 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/basictypes.h"
+#include "base/files/file_path.h"
 #include "url/gurl.h"
 
 namespace extension_urls {
@@ -192,10 +193,9 @@
 // Path to preinstalled ChromeVox screen reader extension (relative to
 // |chrome::DIR_RESOURCES|).
 extern const char kChromeVoxExtensionPath[];
-// Name of ChromeVox manifest file.
-extern const char kChromeVoxManifestFilename[];
-// Name of ChromeVox guest manifest file.
-extern const char kChromeVoxGuestManifestFilename[];
+// Name of the manifest file in an extension when a special manifest is used
+// for guest mode.
+extern const char kGuestManifestFilename[];
 // Extension id, path (relative to |chrome::DIR_RESOURCES|) and IME engine
 // id for the builtin-in Braille IME extension.
 extern const char kBrailleImeExtensionId[];
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
index 6b22aad..56b3768 100644
--- a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
+++ b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
@@ -302,6 +302,9 @@
            IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_UNKNOWN_PRODUCT),
        {APIPermission::kUsbDeviceUnknownProduct},
        {}},
+      {IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_UNKNOWN_VENDOR,
+       {APIPermission::kUsbDeviceUnknownVendor},
+       {}},
       {new SimpleListFormatter(IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_LIST),
        {APIPermission::kUsbDeviceList},
        {}},
@@ -535,17 +538,6 @@
        {APIPermission::kInterceptAllKeys},
        {}},
 
-      // Settings override permission messages.
-      {IDS_EXTENSION_PROMPT_WARNING_HOME_PAGE_SETTING_OVERRIDE,
-       {APIPermission::kHomepage},
-       {}},
-      {IDS_EXTENSION_PROMPT_WARNING_SEARCH_SETTINGS_OVERRIDE,
-       {APIPermission::kSearchProvider},
-       {}},
-      {IDS_EXTENSION_PROMPT_WARNING_START_PAGE_SETTING_OVERRIDE,
-       {APIPermission::kStartupPages},
-       {}},
-
       {IDS_EXTENSION_PROMPT_WARNING_AUDIO_AND_VIDEO_CAPTURE,
        {APIPermission::kAudioCapture, APIPermission::kVideoCapture},
        {}},
@@ -595,19 +587,17 @@
 
       // API permission rules:
       // SettingsOverrideAPIPermission:
-      {IDS_EXTENSION_PROMPT_WARNING_HOME_PAGE_SETTING_OVERRIDE,
+      {new SingleParameterFormatter(
+           IDS_EXTENSION_PROMPT_WARNING_HOME_PAGE_SETTING_OVERRIDE),
        {APIPermission::kHomepage},
        {}},
-      {IDS_EXTENSION_PROMPT_WARNING_START_PAGE_SETTING_OVERRIDE,
-       {APIPermission::kStartupPages},
-       {}},
-      {IDS_EXTENSION_PROMPT_WARNING_SEARCH_SETTINGS_OVERRIDE,
+      {new SingleParameterFormatter(
+           IDS_EXTENSION_PROMPT_WARNING_SEARCH_SETTINGS_OVERRIDE),
        {APIPermission::kSearchProvider},
        {}},
-
-      // USBDevicePermission:
-      {IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_UNKNOWN_VENDOR,
-       {APIPermission::kUsbDeviceUnknownVendor},
+      {new SingleParameterFormatter(
+           IDS_EXTENSION_PROMPT_WARNING_START_PAGE_SETTING_OVERRIDE),
+       {APIPermission::kStartupPages},
        {}},
 
       // Other rules:
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index f9a56b3..0547b3f 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -2279,4 +2279,6 @@
 const char kAnimationPolicy[] = "settings.a11y.animation_policy";
 #endif
 
+const char kBackgroundTracingLastUpload[] = "background_tracing.last_upload";
+
 }  // namespace prefs
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 0b334cfd..785cb69 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -832,6 +832,8 @@
 extern const char kAnimationPolicy[];
 #endif
 
+extern const char kBackgroundTracingLastUpload[];
+
 }  // namespace prefs
 
 #endif  // CHROME_COMMON_PREF_NAMES_H_
diff --git a/chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py b/chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py
index acb98bb..dfca9a6 100755
--- a/chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py
+++ b/chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py
@@ -29,19 +29,23 @@
 URL_PREFIX = 'http://storage.googleapis.com'
 URL_PATH = 'chrome-linux-sysroot/toolchain'
 REVISION_AMD64 = 'a2d45701cb21244b9514e420950ba6ba687fb655'
-REVISION_I386 = 'a2d45701cb21244b9514e420950ba6ba687fb655'
 REVISION_ARM = 'a2d45701cb21244b9514e420950ba6ba687fb655'
+REVISION_I386 = 'a2d45701cb21244b9514e420950ba6ba687fb655'
+REVISION_MIPS = '7749d2957387abf225b6d45154c3ddad142148dc'
 TARBALL_AMD64 = 'debian_wheezy_amd64_sysroot.tgz'
-TARBALL_I386 = 'debian_wheezy_i386_sysroot.tgz'
 TARBALL_ARM = 'debian_wheezy_arm_sysroot.tgz'
+TARBALL_I386 = 'debian_wheezy_i386_sysroot.tgz'
+TARBALL_MIPS = 'debian_wheezy_mips_sysroot.tgz'
 TARBALL_AMD64_SHA1SUM = '601216c0f980e798e7131635f3dd8171b3dcbcde'
-TARBALL_I386_SHA1SUM = '0090e5a4b56ab9ffb5d557da6a520195ab59b446'
 TARBALL_ARM_SHA1SUM = '6289593b36616526562a4d85ae9c92b694b8ce7e'
+TARBALL_I386_SHA1SUM = '0090e5a4b56ab9ffb5d557da6a520195ab59b446'
+TARBALL_MIPS_SHA1SUM = '3b4d782a237db4aac185a638572a7747c1a21825'
 SYSROOT_DIR_AMD64 = 'debian_wheezy_amd64-sysroot'
-SYSROOT_DIR_I386 = 'debian_wheezy_i386-sysroot'
 SYSROOT_DIR_ARM = 'debian_wheezy_arm-sysroot'
+SYSROOT_DIR_I386 = 'debian_wheezy_i386-sysroot'
+SYSROOT_DIR_MIPS = 'debian_wheezy_mips-sysroot'
 
-valid_archs = ('arm', 'i386', 'amd64')
+valid_archs = ('arm', 'i386', 'amd64', 'mips')
 
 
 def GetSha1(filename):
@@ -66,6 +70,8 @@
     return 'i386'
   elif 'target_arch=arm' in gyp_defines:
     return 'arm'
+  elif 'target_arch=mipsel' in gyp_defines:
+    return 'mips'
 
   # Figure out host arch using build/detect_host_arch.py and
   # set target_arch to host arch
@@ -81,6 +87,8 @@
     return 'i386'
   elif detected_host_arch == 'arm':
     return 'arm'
+  elif detected_host_arch == 'mips':
+    return 'mips'
   else:
     print "Unknown host arch: %s" % detected_host_arch
 
@@ -101,7 +109,7 @@
       print 'Unable to detect host architecture'
       return 1
 
-  if options.running_as_hook and target_arch != 'arm':
+  if options.running_as_hook and target_arch != 'arm' and target_arch != 'mips':
     # When run from runhooks, only install the sysroot for an Official Chrome
     # Linux build, except on ARM where we always use a sysroot.
     skip_if_defined = ['branding=Chrome', 'buildtype=Official']
@@ -132,6 +140,11 @@
     tarball_filename = TARBALL_I386
     tarball_sha1sum = TARBALL_I386_SHA1SUM
     revision = REVISION_I386
+  elif target_arch == 'mips':
+    sysroot = os.path.join(linux_dir, SYSROOT_DIR_MIPS)
+    tarball_filename = TARBALL_MIPS
+    tarball_sha1sum = TARBALL_MIPS_SHA1SUM
+    revision = REVISION_MIPS
   else:
     print 'Unknown architecture: %s' % target_arch
     assert(False)
diff --git a/chrome/installer/linux/sysroot_scripts/packagelist.wheezy.mipsel b/chrome/installer/linux/sysroot_scripts/packagelist.wheezy.mipsel
new file mode 100644
index 0000000..9531805b
--- /dev/null
+++ b/chrome/installer/linux/sysroot_scripts/packagelist.wheezy.mipsel
@@ -0,0 +1,156 @@
+main/a/alsa-lib/libasound2_1.0.25-4_mipsel.deb
+main/a/alsa-lib/libasound2-dev_1.0.25-4_mipsel.deb
+main/a/atk1.0/libatk1.0-0_2.4.0-2_mipsel.deb
+main/a/atk1.0/libatk1.0-dev_2.4.0-2_mipsel.deb
+main/a/attr/libattr1_2.4.46-8_mipsel.deb
+main/a/avahi/libavahi-client3_0.6.31-2_mipsel.deb
+main/a/avahi/libavahi-common3_0.6.31-2_mipsel.deb
+main/c/cairo/libcairo2_1.12.2-3_mipsel.deb
+main/c/cairo/libcairo2-dev_1.12.2-3_mipsel.deb
+main/c/cairo/libcairo-gobject2_1.12.2-3_mipsel.deb
+main/c/cairo/libcairo-script-interpreter2_1.12.2-3_mipsel.deb
+main/c/cups/libcups2_1.5.3-5+deb7u4_mipsel.deb
+main/c/cups/libcups2-dev_1.5.3-5+deb7u4_mipsel.deb
+main/d/dbus-glib/libdbus-glib-1-2_0.100.2-1_mipsel.deb
+main/d/dbus/libdbus-1-3_1.6.8-1+deb7u5_mipsel.deb
+main/d/dbus/libdbus-1-dev_1.6.8-1+deb7u5_mipsel.deb
+main/e/e2fsprogs/comerr-dev_2.1-1.42.5-1.1_mipsel.deb
+main/e/e2fsprogs/libcomerr2_1.42.5-1.1_mipsel.deb
+main/e/eglibc/libc6_2.13-38+deb7u6_mipsel.deb
+main/e/eglibc/libc6-dev_2.13-38+deb7u6_mipsel.deb
+main/e/elfutils/libelf1_0.152-1+wheezy1_mipsel.deb
+main/e/elfutils/libelf-dev_0.152-1+wheezy1_mipsel.deb
+main/e/expat/libexpat1_2.1.0-1+deb7u1_mipsel.deb
+main/e/expat/libexpat1-dev_2.1.0-1+deb7u1_mipsel.deb
+main/f/fontconfig/libfontconfig1_2.9.0-7.1_mipsel.deb
+main/f/fontconfig/libfontconfig1-dev_2.9.0-7.1_mipsel.deb
+main/f/freetype/libfreetype6_2.4.9-1.1_mipsel.deb
+main/f/freetype/libfreetype6-dev_2.4.9-1.1_mipsel.deb
+main/g/gcc-4.6/gcc-4.6_4.6.3-14_mipsel.deb
+main/g/gcc-4.6/libstdc++6-4.6-dev_4.6.3-14_mipsel.deb
+main/g/gcc-4.7/libgcc1_4.7.2-5_mipsel.deb
+main/g/gcc-4.7/libgomp1_4.7.2-5_mipsel.deb
+main/g/gcc-4.7/libstdc++6_4.7.2-5_mipsel.deb
+main/g/gconf/libgconf2-4_3.2.5-1+build1_mipsel.deb
+main/g/gconf/libgconf-2-4_3.2.5-1+build1_mipsel.deb
+main/g/gconf/libgconf2-dev_3.2.5-1+build1_mipsel.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-0_2.26.1-1_mipsel.deb
+main/g/gdk-pixbuf/libgdk-pixbuf2.0-dev_2.26.1-1_mipsel.deb
+main/g/glib2.0/libglib2.0-0_2.33.12+really2.32.4-5_mipsel.deb
+main/g/glib2.0/libglib2.0-dev_2.33.12+really2.32.4-5_mipsel.deb
+main/g/gnutls26/libgnutls26_2.12.20-8+deb7u2_mipsel.deb
+main/g/gnutls26/libgnutls-dev_2.12.20-8+deb7u2_mipsel.deb
+main/g/gnutls26/libgnutls-openssl27_2.12.20-8+deb7u2_mipsel.deb
+main/g/gnutls26/libgnutlsxx27_2.12.20-8+deb7u2_mipsel.deb
+main/g/gtk+2.0/libgtk2.0-0_2.24.10-2_mipsel.deb
+main/g/gtk+2.0/libgtk2.0-dev_2.24.10-2_mipsel.deb
+main/k/keyutils/libkeyutils1_1.5.5-3+deb7u1_mipsel.deb
+main/k/krb5/krb5-multidev_1.10.1+dfsg-5+deb7u2_mipsel.deb
+main/k/krb5/libgssapi-krb5-2_1.10.1+dfsg-5+deb7u2_mipsel.deb
+main/k/krb5/libgssrpc4_1.10.1+dfsg-5+deb7u2_mipsel.deb
+main/k/krb5/libk5crypto3_1.10.1+dfsg-5+deb7u2_mipsel.deb
+main/k/krb5/libkadm5clnt-mit8_1.10.1+dfsg-5+deb7u2_mipsel.deb
+main/k/krb5/libkadm5srv-mit8_1.10.1+dfsg-5+deb7u2_mipsel.deb
+main/k/krb5/libkdb5-6_1.10.1+dfsg-5+deb7u2_mipsel.deb
+main/k/krb5/libkrb5-3_1.10.1+dfsg-5+deb7u2_mipsel.deb
+main/k/krb5/libkrb5-dev_1.10.1+dfsg-5+deb7u2_mipsel.deb
+main/k/krb5/libkrb5support0_1.10.1+dfsg-5+deb7u2_mipsel.deb
+main/libc/libcap2/libcap2_2.22-1.2_mipsel.deb
+main/libc/libcap2/libcap-dev_2.22-1.2_mipsel.deb
+main/libd/libdrm/libdrm2_2.4.40-1~deb7u2_mipsel.deb
+main/libe/libexif/libexif12_0.6.20-3_mipsel.deb
+main/libe/libexif/libexif-dev_0.6.20-3_mipsel.deb
+main/libf/libffi/libffi5_3.0.10-3_mipsel.deb
+main/libg/libgcrypt11/libgcrypt11_1.5.0-5+deb7u2_mipsel.deb
+main/libg/libgcrypt11/libgcrypt11-dev_1.5.0-5+deb7u2_mipsel.deb
+main/libg/libgnome-keyring/libgnome-keyring0_3.4.1-1_mipsel.deb
+main/libg/libgnome-keyring/libgnome-keyring-dev_3.4.1-1_mipsel.deb
+main/libg/libgpg-error/libgpg-error0_1.10-3.1_mipsel.deb
+main/libg/libgpg-error/libgpg-error-dev_1.10-3.1_mipsel.deb
+main/libn/libnss-db/libnss-db_2.2.3pre1-4_mipsel.deb
+main/libp/libp11/libp11-2_0.2.8-2_mipsel.deb
+main/libp/libpng/libpng12-0_1.2.49-1_mipsel.deb
+main/libp/libpng/libpng12-dev_1.2.49-1_mipsel.deb
+main/libs/libselinux/libselinux1_2.1.9-5_mipsel.deb
+main/libt/libtasn1-3/libtasn1-3_2.13-2+deb7u1_mipsel.deb
+main/libx/libx11/libx11-6_1.5.0-1+deb7u1_mipsel.deb
+main/libx/libx11/libx11-dev_1.5.0-1+deb7u1_mipsel.deb
+main/libx/libx11/libx11-xcb1_1.5.0-1+deb7u1_mipsel.deb
+main/libx/libxau/libxau6_1.0.7-1_mipsel.deb
+main/libx/libxau/libxau-dev_1.0.7-1_mipsel.deb
+main/libx/libxcb/libxcb1_1.8.1-2+deb7u1_mipsel.deb
+main/libx/libxcb/libxcb1-dev_1.8.1-2+deb7u1_mipsel.deb
+main/libx/libxcb/libxcb-glx0_1.8.1-2+deb7u1_mipsel.deb
+main/libx/libxcb/libxcb-render0_1.8.1-2+deb7u1_mipsel.deb
+main/libx/libxcb/libxcb-render0-dev_1.8.1-2+deb7u1_mipsel.deb
+main/libx/libxcb/libxcb-shm0_1.8.1-2+deb7u1_mipsel.deb
+main/libx/libxcb/libxcb-shm0-dev_1.8.1-2+deb7u1_mipsel.deb
+main/libx/libxcomposite/libxcomposite1_0.4.3-2_mipsel.deb
+main/libx/libxcomposite/libxcomposite-dev_0.4.3-2_mipsel.deb
+main/libx/libxcursor/libxcursor1_1.1.13-1+deb7u1_mipsel.deb
+main/libx/libxcursor/libxcursor-dev_1.1.13-1+deb7u1_mipsel.deb
+main/libx/libxdamage/libxdamage1_1.1.3-2_mipsel.deb
+main/libx/libxdamage/libxdamage-dev_1.1.3-2_mipsel.deb
+main/libx/libxdmcp/libxdmcp6_1.1.1-1_mipsel.deb
+main/libx/libxext/libxext6_1.3.1-2+deb7u1_mipsel.deb
+main/libx/libxext/libxext-dev_1.3.1-2+deb7u1_mipsel.deb
+main/libx/libxfixes/libxfixes3_5.0-4+deb7u1_mipsel.deb
+main/libx/libxfixes/libxfixes-dev_5.0-4+deb7u1_mipsel.deb
+main/libx/libxi/libxi6_1.6.1-1+deb7u1_mipsel.deb
+main/libx/libxi/libxi-dev_1.6.1-1+deb7u1_mipsel.deb
+main/libx/libxinerama/libxinerama1_1.1.2-1+deb7u1_mipsel.deb
+main/libx/libxinerama/libxinerama-dev_1.1.2-1+deb7u1_mipsel.deb
+main/libx/libxrandr/libxrandr2_1.3.2-2+deb7u1_mipsel.deb
+main/libx/libxrandr/libxrandr-dev_1.3.2-2+deb7u1_mipsel.deb
+main/libx/libxrender/libxrender1_0.9.7-1+deb7u1_mipsel.deb
+main/libx/libxrender/libxrender-dev_0.9.7-1+deb7u1_mipsel.deb
+main/libx/libxss/libxss1_1.2.2-1_mipsel.deb
+main/libx/libxss/libxss-dev_1.2.2-1_mipsel.deb
+main/libx/libxt/libxt6_1.1.3-1+deb7u1_mipsel.deb
+main/libx/libxt/libxt-dev_1.1.3-1+deb7u1_mipsel.deb
+main/libx/libxtst/libxtst6_1.2.1-1+deb7u1_mipsel.deb
+main/libx/libxtst/libxtst-dev_1.2.1-1+deb7u1_mipsel.deb
+main/libx/libxxf86vm/libxxf86vm1_1.1.2-1+deb7u1_mipsel.deb
+main/l/linux/linux-libc-dev_3.2.65-1_mipsel.deb
+main/m/mesa/libgl1-mesa-dev_8.0.5-4+deb7u2_mipsel.deb
+main/m/mesa/libgl1-mesa-glx_8.0.5-4+deb7u2_mipsel.deb
+main/m/mesa/libglapi-mesa_8.0.5-4+deb7u2_mipsel.deb
+main/m/mesa/mesa-common-dev_8.0.5-4+deb7u2_mipsel.deb
+main/n/nspr/libnspr4_4.9.2-1+deb7u2_mipsel.deb
+main/n/nspr/libnspr4-dev_4.9.2-1+deb7u2_mipsel.deb
+main/n/nss/libnss3_3.14.5-1+deb7u3_mipsel.deb
+main/n/nss/libnss3-dev_3.14.5-1+deb7u3_mipsel.deb
+main/o/openssl/libssl1.0.0_1.0.1e-2+deb7u13_mipsel.deb
+main/o/openssl/libssl-dev_1.0.1e-2+deb7u13_mipsel.deb
+main/o/orbit2/liborbit2_2.14.19-0.1_mipsel.deb
+main/p/p11-kit/libp11-kit0_0.12-3_mipsel.deb
+main/p/pam/libpam0g_1.1.3-7.1_mipsel.deb
+main/p/pam/libpam0g-dev_1.1.3-7.1_mipsel.deb
+main/p/pango1.0/libpango1.0-0_1.30.0-1_mipsel.deb
+main/p/pango1.0/libpango1.0-dev_1.30.0-1_mipsel.deb
+main/p/pciutils/libpci3_3.1.9-6_mipsel.deb
+main/p/pciutils/libpci-dev_3.1.9-6_mipsel.deb
+main/p/pcre3/libpcre3_8.30-5_mipsel.deb
+main/p/pcre3/libpcre3-dev_8.30-5_mipsel.deb
+main/p/pcre3/libpcrecpp0_8.30-5_mipsel.deb
+main/p/pixman/libpixman-1-0_0.26.0-4+deb7u1_mipsel.deb
+main/p/pixman/libpixman-1-dev_0.26.0-4+deb7u1_mipsel.deb
+main/p/pulseaudio/libpulse0_2.0-6.1_mipsel.deb
+main/p/pulseaudio/libpulse-dev_2.0-6.1_mipsel.deb
+main/p/pulseaudio/libpulse-mainloop-glib0_2.0-6.1_mipsel.deb
+main/s/speech-dispatcher/libspeechd2_0.7.1-6.2_mipsel.deb
+main/s/speech-dispatcher/libspeechd-dev_0.7.1-6.2_mipsel.deb
+main/s/speech-dispatcher/speech-dispatcher_0.7.1-6.2_mipsel.deb
+main/x/x11proto-composite/x11proto-composite-dev_0.4.2-2_all.deb
+main/x/x11proto-core/x11proto-core-dev_7.0.23-1_all.deb
+main/x/x11proto-damage/x11proto-damage-dev_1.2.1-2_all.deb
+main/x/x11proto-fixes/x11proto-fixes-dev_5.0-2_all.deb
+main/x/x11proto-input/x11proto-input-dev_2.2-1_all.deb
+main/x/x11proto-kb/x11proto-kb-dev_1.0.6-2_all.deb
+main/x/x11proto-randr/x11proto-randr-dev_1.3.2-2_all.deb
+main/x/x11proto-record/x11proto-record-dev_1.14.2-1_all.deb
+main/x/x11proto-render/x11proto-render-dev_0.11.1-2_all.deb
+main/x/x11proto-scrnsaver/x11proto-scrnsaver-dev_1.2.2-1_all.deb
+main/x/x11proto-xext/x11proto-xext-dev_7.2.1-1_all.deb
+main/z/zlib/zlib1g_1.2.7.dfsg-13_mipsel.deb
+main/z/zlib/zlib1g-dev_1.2.7.dfsg-13_mipsel.deb
diff --git a/chrome/installer/linux/sysroot_scripts/sysroot-creator.sh b/chrome/installer/linux/sysroot_scripts/sysroot-creator.sh
index 1356367..822a5e8 100644
--- a/chrome/installer/linux/sysroot_scripts/sysroot-creator.sh
+++ b/chrome/installer/linux/sysroot_scripts/sysroot-creator.sh
@@ -63,13 +63,16 @@
 readonly PACKAGE_FILE_AMD64="main/binary-amd64/Packages.bz2"
 readonly PACKAGE_FILE_I386="main/binary-i386/Packages.bz2"
 readonly PACKAGE_FILE_ARM="main/binary-armhf/Packages.bz2"
+readonly PACKAGE_FILE_MIPS="main/binary-mipsel/Packages.bz2"
 readonly PACKAGE_LIST_AMD64="${REPO_BASEDIR}/${PACKAGE_FILE_AMD64}"
 readonly PACKAGE_LIST_I386="${REPO_BASEDIR}/${PACKAGE_FILE_I386}"
 readonly PACKAGE_LIST_ARM="${REPO_BASEDIR}/${PACKAGE_FILE_ARM}"
+readonly PACKAGE_LIST_MIPS="${REPO_BASEDIR}/${PACKAGE_FILE_MIPS}"
 
 readonly DEBIAN_DEP_LIST_AMD64="packagelist.${DIST}.amd64"
 readonly DEBIAN_DEP_LIST_I386="packagelist.${DIST}.i386"
 readonly DEBIAN_DEP_LIST_ARM="packagelist.${DIST}.arm"
+readonly DEBIAN_DEP_LIST_MIPS="packagelist.${DIST}.mipsel"
 
 ######################################################################
 # Helper
@@ -120,6 +123,9 @@
     echo $1 | grep -qs I386$ && ARCH=I386
   fi
   if [ -z "$ARCH" ]; then
+    echo $1 | grep -qs Mips$ && ARCH=MIPS
+  fi
+  if [ -z "$ARCH" ]; then
     echo $1 | grep -qs ARM$ && ARCH=ARM
   fi
   if [ -z "${ARCH}" ]; then
@@ -212,6 +218,16 @@
   GeneratePackageList "$tmp_package_list" "$output_file" "${DEBIAN_PACKAGES}"
 }
 
+GeneratePackageListMips() {
+  local output_file="$1"
+  local package_list="${BUILD_DIR}/Packages.${DIST}_mips.bz2"
+  local tmp_package_list="${BUILD_DIR}/Packages.${DIST}_mips"
+  DownloadOrCopy "${PACKAGE_LIST_MIPS}" "${package_list}"
+  VerifyPackageListing "${PACKAGE_FILE_MIPS}" "${package_list}"
+  ExtractPackageBz2 "$package_list" "$tmp_package_list"
+  GeneratePackageList "$tmp_package_list" "$output_file" "${DEBIAN_PACKAGES}"
+}
+
 StripChecksumsFromPackageList() {
   local package_file="$1"
   sed -i 's/ [a-f0-9]\{64\}$//' "$package_file"
@@ -239,7 +255,7 @@
   lscripts="${INSTALL_ROOT}/usr/lib/x86_64-linux-gnu/libpthread.so \
             ${INSTALL_ROOT}/usr/lib/x86_64-linux-gnu/libc.so"
 
-  #SubBanner "Rewriting Linker Scripts"
+  # Rewrite linker scripts
   sed -i -e 's|/usr/lib/x86_64-linux-gnu/||g'  ${lscripts}
   sed -i -e 's|/lib/x86_64-linux-gnu/||g' ${lscripts}
 
@@ -263,7 +279,7 @@
   lscripts="${INSTALL_ROOT}/usr/lib/i386-linux-gnu/libpthread.so \
             ${INSTALL_ROOT}/usr/lib/i386-linux-gnu/libc.so"
 
-  #SubBanner "Rewriting Linker Scripts"
+  # Rewrite linker scripts
   sed -i -e 's|/usr/lib/i386-linux-gnu/||g'  ${lscripts}
   sed -i -e 's|/lib/i386-linux-gnu/||g' ${lscripts}
 
@@ -287,7 +303,7 @@
   lscripts="${INSTALL_ROOT}/usr/lib/arm-linux-gnueabihf/libpthread.so \
             ${INSTALL_ROOT}/usr/lib/arm-linux-gnueabihf/libc.so"
 
-  #SubBanner "Rewriting Linker Scripts"
+  # Rewrite linker scripts
   sed -i -e 's|/usr/lib/arm-linux-gnueabihf/||g' ${lscripts}
   sed -i -e 's|/lib/arm-linux-gnueabihf/||g' ${lscripts}
 
@@ -299,6 +315,25 @@
 }
 
 
+HacksAndPatchesMips() {
+  Banner "Misc Hacks & Patches"
+  # these are linker scripts with absolute pathnames in them
+  # which we rewrite here
+  lscripts="${INSTALL_ROOT}/usr/lib/mipsel-linux-gnu/libpthread.so \
+            ${INSTALL_ROOT}/usr/lib/mipsel-linux-gnu/libc.so"
+
+  # Rewrite linker scripts
+  sed -i -e 's|/usr/lib/mipsel-linux-gnu/||g' ${lscripts}
+  sed -i -e 's|/lib/mipsel-linux-gnu/||g' ${lscripts}
+
+  # This is for chrome's ./build/linux/pkg-config-wrapper
+  # which overwrites PKG_CONFIG_PATH internally
+  SubBanner "Package Configs Symlink"
+  mkdir -p ${INSTALL_ROOT}/usr/share
+  ln -s ../lib/mipsel-linux-gnu/pkgconfig ${INSTALL_ROOT}/usr/share/pkgconfig
+}
+
+
 InstallIntoSysroot() {
   Banner "Install Libs And Headers Into Jail"
 
@@ -336,18 +371,23 @@
 
   SAVEDPWD=$(pwd)
   cd ${INSTALL_ROOT}
-  find lib lib64 usr/lib -type l -printf '%p %l\n' | while read link target; do
+  local libdirs="lib usr/lib"
+  if [ "${ARCH}" != "MIPS" ]; then
+    libdirs+=" lib64"
+  fi
+  find $libdirs -type l -printf '%p %l\n' | while read link target; do
     # skip links with non-absolute paths
     echo "${target}" | grep -qs ^/ || continue
     echo "${link}: ${target}"
     case "${link}" in
       usr/lib/gcc/x86_64-linux-gnu/4.*/* | usr/lib/gcc/i486-linux-gnu/4.*/* | \
-      usr/lib/gcc/arm-linux-gnueabihf/4.*/*)
+      usr/lib/gcc/arm-linux-gnueabihf/4.*/* | \
+      usr/lib/gcc/mipsel-linux-gnu/4.*/*)
         # Relativize the symlink.
         ln -snfv "../../../../..${target}" "${link}"
         ;;
       usr/lib/x86_64-linux-gnu/* | usr/lib/i386-linux-gnu/* | \
-      usr/lib/arm-linux-gnueabihf/*)
+      usr/lib/arm-linux-gnueabihf/* | usr/lib/mipsel-linux-gnu/* )
         # Relativize the symlink.
         ln -snfv "../../..${target}" "${link}"
         ;;
@@ -362,7 +402,7 @@
     esac
   done
 
-  find lib lib64 usr/lib -type l -printf '%p %l\n' | while read link target; do
+  find $libdirs -type l -printf '%p %l\n' | while read link target; do
     # Make sure we catch new bad links.
     if [ ! -r "${link}" ]; then
       echo "ERROR: FOUND BAD LINK ${link}"
@@ -426,6 +466,24 @@
 }
 
 #@
+#@ BuildSysrootMips
+#@
+#@    Build everything and package it
+BuildSysrootMips() {
+  ClearInstallDir
+  local package_file="$BUILD_DIR/package_with_sha256sum_arm"
+  GeneratePackageListMips "$package_file"
+  local files_and_sha256sums="$(cat ${package_file})"
+  StripChecksumsFromPackageList "$package_file"
+  VerifyPackageFilesMatch "$package_file" "$DEBIAN_DEP_LIST_MIPS"
+  APT_REPO=${APR_REPO_MIPS:=$APT_REPO}
+  InstallIntoSysroot ${files_and_sha256sums}
+  CleanupJailSymlinks
+  HacksAndPatchesMips
+  CreateTarBall
+}
+
+#@
 #@ BuildSysrootAll
 #@
 #@    Build sysroot images for all architectures
@@ -433,6 +491,7 @@
   RunCommand BuildSysrootAmd64
   RunCommand BuildSysrootI386
   RunCommand BuildSysrootARM
+  RunCommand BuildSysrootMips
 }
 
 UploadSysroot() {
@@ -469,6 +528,13 @@
 }
 
 #@
+#@ UploadSysrootMips <revision>
+#@
+UploadSysrootMips() {
+  UploadSysroot "$@"
+}
+
+#@
 #@ UploadSysrootAll <revision>
 #@
 #@    Upload sysroot image for all architectures
@@ -476,6 +542,7 @@
   RunCommand UploadSysrootAmd64 "$@"
   RunCommand UploadSysrootI386 "$@"
   RunCommand UploadSysrootARM "$@"
+  RunCommand UploadSysrootMips "$@"
 }
 
 #
@@ -587,6 +654,16 @@
 }
 
 #@
+#@ UpdatePackageListsMips
+#@
+#@     Regenerate the package lists such that they contain an up-to-date
+#@     list of URLs within the Debian archive. (For arm)
+UpdatePackageListsMips() {
+  GeneratePackageListMips "$DEBIAN_DEP_LIST_MIPS"
+  StripChecksumsFromPackageList "$DEBIAN_DEP_LIST_MIPS"
+}
+
+#@
 #@ UpdatePackageListsAll
 #@
 #@    Regenerate the package lists for all architectures.
@@ -594,6 +671,7 @@
   RunCommand UpdatePackageListsAmd64
   RunCommand UpdatePackageListsI386
   RunCommand UpdatePackageListsARM
+  RunCommand UpdatePackageListsMips
 }
 
 RunCommand() {
diff --git a/chrome/installer/test/alternate_version_generator.cc b/chrome/installer/test/alternate_version_generator.cc
index 039c1ef..41ecf11 100644
--- a/chrome/installer/test/alternate_version_generator.cc
+++ b/chrome/installer/test/alternate_version_generator.cc
@@ -245,8 +245,10 @@
   std::pair<const uint8*, DWORD> version_info_data;
 
   if (pe_file_loader.Initialize(pe_file) &&
-      pe_file_loader.Load(VS_VERSION_INFO, reinterpret_cast<WORD>(RT_VERSION),
-                          &version_info_data)) {
+      pe_file_loader.Load(
+          VS_VERSION_INFO,
+          static_cast<WORD>(reinterpret_cast<uintptr_t>(RT_VERSION)),
+          &version_info_data)) {
     const VS_FIXEDFILEINFO* fixed_file_info;
     UINT ver_info_len;
     if (VerQueryValue(version_info_data.first, L"\\",
diff --git a/chrome/plugin/chrome_content_plugin_client.cc b/chrome/plugin/chrome_content_plugin_client.cc
index 3cfce28..d54e0c4 100644
--- a/chrome/plugin/chrome_content_plugin_client.cc
+++ b/chrome/plugin/chrome_content_plugin_client.cc
@@ -26,6 +26,7 @@
 void ChromeContentPluginClient::PreSandboxInitialization() {
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
   gin::V8Initializer::LoadV8Snapshot();
+  gin::V8Initializer::LoadV8Natives();
 #endif
 
 #if defined(ENABLE_REMOTING)
diff --git a/chrome/policy_templates.gypi b/chrome/policy_templates.gypi
index 3747f23..c577f8f 100644
--- a/chrome/policy_templates.gypi
+++ b/chrome/policy_templates.gypi
@@ -53,6 +53,9 @@
                 '<(version_path)',
                 '<@(template_files)',
                 '<(zip_script)',
+                '<!@pymod_do_main(grit_info <@(grit_defines) '
+                    '--inputs "<(grit_grd_file)" '
+                    '-f "<(DEPTH)/tools/gritsettings/resource_ids")',
               ],
               'outputs': [
                 '<(PRODUCT_DIR)/policy_templates.zip',
diff --git a/chrome/renderer/content_settings_observer.cc b/chrome/renderer/content_settings_observer.cc
index 3769a85cc..332e29a 100644
--- a/chrome/renderer/content_settings_observer.cc
+++ b/chrome/renderer/content_settings_observer.cc
@@ -170,11 +170,15 @@
   ClearBlockedContentSettings();
   render_frame->GetWebFrame()->setContentSettingsClient(this);
 
-  if (render_frame->GetRenderView()->GetMainRenderFrame() != render_frame) {
+  content::RenderFrame* main_frame =
+      render_frame->GetRenderView()->GetMainRenderFrame();
+  // TODO(nasko): The main frame is not guaranteed to be in the same process
+  // with this frame with --site-per-process. This code needs to be updated
+  // to handle this case. See https://crbug.com/496670.
+  if (main_frame && main_frame != render_frame) {
     // Copy all the settings from the main render frame to avoid race conditions
-    // when initializing this data. See http://crbug.com/333308.
-    ContentSettingsObserver* parent = ContentSettingsObserver::Get(
-        render_frame->GetRenderView()->GetMainRenderFrame());
+    // when initializing this data. See https://crbug.com/333308.
+    ContentSettingsObserver* parent = ContentSettingsObserver::Get(main_frame);
     allow_displaying_insecure_content_ =
         parent->allow_displaying_insecure_content_;
     allow_running_insecure_content_ = parent->allow_running_insecure_content_;
diff --git a/chrome/renderer/page_load_histograms.cc b/chrome/renderer/page_load_histograms.cc
index 2b93a7a..0723709 100644
--- a/chrome/renderer/page_load_histograms.cc
+++ b/chrome/renderer/page_load_histograms.cc
@@ -213,7 +213,7 @@
 void DumpHistograms(const WebPerformance& performance,
                     DocumentState* document_state,
                     bool data_reduction_proxy_was_used,
-                    data_reduction_proxy::AutoLoFiStatus auto_lofi_status,
+                    data_reduction_proxy::LoFiStatus lofi_status,
                     bool came_from_websearch,
                     int websearch_chrome_joint_experiment_id,
                     bool is_preview,
@@ -414,7 +414,7 @@
                       load_event_end - navigation_start);
         PLT_HISTOGRAM("PLT.PT_StartToFinish_DataReductionProxy",
                       load_event_end - request_start);
-        if (auto_lofi_status == data_reduction_proxy::AUTO_LOFI_STATUS_ON) {
+        if (lofi_status == data_reduction_proxy::LOFI_STATUS_ACTIVE) {
           PLT_HISTOGRAM("PLT.PT_BeginToFinish_DataReductionProxy_AutoLoFiOn",
                         load_event_end - begin);
           PLT_HISTOGRAM("PLT.PT_CommitToFinish_DataReductionProxy_AutoLoFiOn",
@@ -427,8 +427,8 @@
             PLT_HISTOGRAM("PLT.BeginToFirstPaint_DataReductionProxy_AutoLoFiOn",
                           first_paint - begin);
           }
-        } else if (auto_lofi_status ==
-                   data_reduction_proxy::AUTO_LOFI_STATUS_OFF) {
+        } else if (lofi_status ==
+                   data_reduction_proxy::LOFI_STATUS_ACTIVE_CONTROL) {
           PLT_HISTOGRAM("PLT.PT_BeginToFinish_DataReductionProxy_AutoLoFiOff",
                         load_event_end - begin);
           PLT_HISTOGRAM("PLT.PT_CommitToFinish_DataReductionProxy_AutoLoFiOff",
@@ -452,7 +452,7 @@
                       load_event_end - navigation_start);
         PLT_HISTOGRAM("PLT.PT_StartToFinish_HTTPS_DataReductionProxy",
                       load_event_end - request_start);
-        if (auto_lofi_status == data_reduction_proxy::AUTO_LOFI_STATUS_ON) {
+        if (lofi_status == data_reduction_proxy::LOFI_STATUS_ACTIVE) {
           PLT_HISTOGRAM(
               "PLT.PT_BeginToFinish_HTTPS_DataReductionProxy_AutoLoFiOn",
               load_event_end - begin);
@@ -470,8 +470,8 @@
                 "PLT.BeginToFirstPaint_HTTPS_DataReductionProxy_AutoLoFiOn",
                 first_paint - begin);
           }
-        } else if (auto_lofi_status ==
-                   data_reduction_proxy::AUTO_LOFI_STATUS_OFF) {
+        } else if (lofi_status ==
+                   data_reduction_proxy::LOFI_STATUS_ACTIVE_CONTROL) {
           PLT_HISTOGRAM(
               "PLT.PT_BeginToFinish_HTTPS_DataReductionProxy_AutoLoFiOff",
               load_event_end - begin);
@@ -521,12 +521,12 @@
       if ((scheme_type & URLPattern::SCHEME_HTTPS) == 0) {
         PLT_HISTOGRAM("PLT.PT_RequestToDomContentLoaded_DataReductionProxy",
                       dom_content_loaded_start - navigation_start);
-        if (auto_lofi_status == data_reduction_proxy::AUTO_LOFI_STATUS_ON) {
+        if (lofi_status == data_reduction_proxy::LOFI_STATUS_ACTIVE) {
           PLT_HISTOGRAM(
               "PLT.PT_RequestToDomContentLoaded_DataReductionProxy_AutoLoFiOn",
               dom_content_loaded_start - navigation_start);
-        } else if (auto_lofi_status ==
-                   data_reduction_proxy::AUTO_LOFI_STATUS_OFF) {
+        } else if (lofi_status ==
+                   data_reduction_proxy::LOFI_STATUS_ACTIVE_CONTROL) {
           PLT_HISTOGRAM(
               "PLT.PT_RequestToDomContentLoaded_DataReductionProxy_AutoLoFiOff",
               dom_content_loaded_start - navigation_start);
@@ -535,13 +535,13 @@
         PLT_HISTOGRAM(
             "PLT.PT_RequestToDomContentLoaded_HTTPS_DataReductionProxy",
             dom_content_loaded_start - navigation_start);
-        if (auto_lofi_status == data_reduction_proxy::AUTO_LOFI_STATUS_ON) {
+        if (lofi_status == data_reduction_proxy::LOFI_STATUS_ACTIVE) {
           PLT_HISTOGRAM(
               "PLT.PT_RequestToDomContentLoaded_HTTPS_DataReductionProxy_"
               "AutoLoFiOn",
               dom_content_loaded_start - navigation_start);
-        } else if (auto_lofi_status ==
-                   data_reduction_proxy::AUTO_LOFI_STATUS_OFF) {
+        } else if (lofi_status ==
+                   data_reduction_proxy::LOFI_STATUS_ACTIVE_CONTROL) {
           PLT_HISTOGRAM(
               "PLT.PT_RequestToDomContentLoaded_HTTPS_DataReductionProxy_"
               "AutoLoFiOff",
@@ -843,12 +843,12 @@
       DocumentState::FromDataSource(frame->dataSource());
 
   bool data_reduction_proxy_was_used = false;
-  data_reduction_proxy::AutoLoFiStatus auto_lofi_status =
-      data_reduction_proxy::AUTO_LOFI_STATUS_DISABLED;
+  data_reduction_proxy::LoFiStatus lofi_status =
+      data_reduction_proxy::LOFI_STATUS_TEMPORARILY_OFF;
   if (!document_state->proxy_server().IsEmpty()) {
     Send(new DataReductionProxyViewHostMsg_DataReductionProxyStatus(
         document_state->proxy_server(), &data_reduction_proxy_was_used,
-        &auto_lofi_status));
+        &lofi_status));
   }
 
   bool came_from_websearch =
@@ -865,7 +865,7 @@
   // Metrics based on the timing information recorded for the Navigation Timing
   // API - http://www.w3.org/TR/navigation-timing/.
   DumpHistograms(frame->performance(), document_state,
-                 data_reduction_proxy_was_used, auto_lofi_status,
+                 data_reduction_proxy_was_used, lofi_status,
                  came_from_websearch, websearch_chrome_joint_experiment_id,
                  is_preview, scheme_type);
 
diff --git a/chrome/renderer/resources/extensions/automation/automation_node.js b/chrome/renderer/resources/extensions/automation/automation_node.js
index 4cae916..3f348a3 100644
--- a/chrome/renderer/resources/extensions/automation/automation_node.js
+++ b/chrome/renderer/resources/extensions/automation/automation_node.js
@@ -96,6 +96,10 @@
                           endIndex: endIndex });
   },
 
+  showContextMenu: function() {
+    this.performAction_('showContextMenu');
+  },
+
   domQuerySelector: function(selector, callback) {
     automationInternal.querySelector(
       { treeID: this.rootImpl.treeID,
@@ -379,8 +383,7 @@
 };
 
 function defaultStringAttribute(opt_defaultVal) {
-  var defaultVal = (opt_defaultVal !== undefined) ? opt_defaultVal : '';
-  return { default: defaultVal, reflectFrom: 'stringAttributes' };
+  return { default: undefined, reflectFrom: 'stringAttributes' };
 }
 
 function defaultIntAttribute(opt_defaultVal) {
@@ -431,11 +434,15 @@
   help: defaultStringAttribute(),
   name: defaultStringAttribute(),
   value: defaultStringAttribute(),
+  htmlTag: defaultStringAttribute(),
+  hierarchicalLevel: defaultIntAttribute(),
   controls: defaultNodeRefListAttribute('controlsIds'),
   describedby: defaultNodeRefListAttribute('describedbyIds'),
   flowto: defaultNodeRefListAttribute('flowtoIds'),
   labelledby: defaultNodeRefListAttribute('labelledbyIds'),
-  owns: defaultNodeRefListAttribute('ownsIds')
+  owns: defaultNodeRefListAttribute('ownsIds'),
+  wordStarts: defaultIntListAttribute(),
+  wordEnds: defaultIntListAttribute()
 };
 
 var ActiveDescendantMixinAttribute = {
@@ -464,7 +471,8 @@
 
 var EditableTextMixinAttributes = {
   textSelStart: defaultIntAttribute(-1),
-  textSelEnd: defaultIntAttribute(-1)
+  textSelEnd: defaultIntAttribute(-1),
+  textInputType: defaultStringAttribute()
 };
 
 var RangeMixinAttributes = {
@@ -826,7 +834,8 @@
     }
 
     // If this is an editable text area, set editable text attributes.
-    if (nodeData.role == schema.RoleType.textField) {
+    if (nodeData.role == schema.RoleType.textField ||
+        nodeData.role == schema.RoleType.spinButton) {
       this.mixinAttributes_(nodeImpl, EditableTextMixinAttributes, nodeData);
     }
 
@@ -1018,6 +1027,7 @@
                                                 'makeVisible',
                                                 'matches',
                                                 'setSelection',
+                                                'showContextMenu',
                                                 'addEventListener',
                                                 'removeEventListener',
                                                 'domQuerySelector',
diff --git a/chrome/renderer/safe_browsing/features.cc b/chrome/renderer/safe_browsing/features.cc
index 29675db..4eabef6 100644
--- a/chrome/renderer/safe_browsing/features.cc
+++ b/chrome/renderer/safe_browsing/features.cc
@@ -63,6 +63,7 @@
 // DOM HTML form features
 const char kPageHasForms[] = "PageHasForms";
 const char kPageActionOtherDomainFreq[] = "PageActionOtherDomainFreq";
+const char kPageActionURL[] = "PageActionURL=";
 const char kPageHasTextInputs[] = "PageHasTextInputs";
 const char kPageHasPswdInputs[] = "PageHasPswdInputs";
 const char kPageHasRadioInputs[] = "PageHasRadioInputs";
diff --git a/chrome/renderer/safe_browsing/features.h b/chrome/renderer/safe_browsing/features.h
index 1a1888d..0b55f968 100644
--- a/chrome/renderer/safe_browsing/features.h
+++ b/chrome/renderer/safe_browsing/features.h
@@ -121,7 +121,9 @@
 // The fraction of form elements whose |action| attribute points to a
 // URL on a different domain from the document URL.
 extern const char kPageActionOtherDomainFreq[];
-
+// Token feature containing each URL that an |action| attribute
+// points to.
+extern const char kPageActionURL[];
 // Set if the page has any <input type="text"> elements
 // (includes inputs with missing or unknown types).
 extern const char kPageHasTextInputs[];
@@ -172,6 +174,6 @@
 extern const char kPageTerm[];
 
 }  // namespace features
-}  // namepsace safe_browsing
+}  // namespace safe_browsing
 
 #endif  // CHROME_RENDERER_SAFE_BROWSING_FEATURES_H_
diff --git a/chrome/renderer/safe_browsing/phishing_dom_feature_extractor.cc b/chrome/renderer/safe_browsing/phishing_dom_feature_extractor.cc
index ae5ad65..9c92c9a 100644
--- a/chrome/renderer/safe_browsing/phishing_dom_feature_extractor.cc
+++ b/chrome/renderer/safe_browsing/phishing_dom_feature_extractor.cc
@@ -54,6 +54,7 @@
   int num_check_inputs;
   int action_other_domain;
   int total_actions;
+  base::hash_set<std::string> page_action_urls;
 
   // Image related features
   int img_other_domain;
@@ -279,6 +280,8 @@
   blink::WebURL full_url = element.document().completeURL(
       element.getAttribute("action"));
 
+  page_feature_state_->page_action_urls.insert(full_url.string().utf8());
+
   std::string domain;
   bool is_external = IsExternalDomain(full_url, &domain);
   if (domain.empty()) {
@@ -440,10 +443,8 @@
     features_->AddRealFeature(features::kPageExternalLinksFreq, link_freq);
 
     // Add a feature for each unique domain that we're linking to
-    for (base::hash_set<std::string>::iterator it =
-             page_feature_state_->external_domains.begin();
-         it != page_feature_state_->external_domains.end(); ++it) {
-      features_->AddBooleanFeature(features::kPageLinkDomain + *it);
+    for (const auto& domain : page_feature_state_->external_domains) {
+      features_->AddBooleanFeature(features::kPageLinkDomain + domain);
     }
 
     // Fraction of links that use https.
@@ -478,6 +479,11 @@
                               action_freq);
   }
 
+  // Add a feature for each unique external action url.
+  for (const auto& url : page_feature_state_->page_action_urls) {
+    features_->AddBooleanFeature(features::kPageActionURL + url);
+  }
+
   // Record how many image src attributes point to a different domain.
   if (page_feature_state_->total_imgs > 0) {
     double img_freq = static_cast<double>(
diff --git a/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc b/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc
index 3d1814fc..83746a0 100644
--- a/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc
+++ b/chrome/renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc
@@ -195,6 +195,14 @@
   expected_features.AddRealFeature(features::kPageActionOtherDomainFreq, 0.25);
   expected_features.AddBooleanFeature(features::kPageHasTextInputs);
   expected_features.AddBooleanFeature(features::kPageHasCheckInputs);
+  expected_features.AddBooleanFeature(features::kPageActionURL +
+      std::string("http://cgi.host.com/submit"));
+  expected_features.AddBooleanFeature(features::kPageActionURL +
+      std::string("http://other.com/"));
+  expected_features.AddBooleanFeature(features::kPageActionURL +
+      std::string("http://host.com:") +
+      base::IntToString(embedded_test_server_->port()) +
+      std::string("/query"));
 
   FeatureMap features;
   LoadHtml(
@@ -383,6 +391,10 @@
   expected_features.AddRealFeature(features::kPageSecureLinksFreq, 0.25);
   expected_features.AddBooleanFeature(features::kPageNumScriptTagsGTOne);
   expected_features.AddRealFeature(features::kPageImgOtherDomainFreq, 1.0);
+  expected_features.AddBooleanFeature(features::kPageActionURL +
+      std::string("http://host2.com/submit"));
+  expected_features.AddBooleanFeature(features::kPageActionURL +
+      std::string("http://host4.com/"));
 
   FeatureMap features;
   std::string html(
@@ -456,6 +468,12 @@
   FeatureMap expected_features;
   expected_features.AddBooleanFeature(features::kPageHasForms);
   expected_features.AddRealFeature(features::kPageActionOtherDomainFreq, 0.5);
+  expected_features.AddBooleanFeature(features::kPageActionURL +
+      std::string("http://host.com:") +
+      base::IntToString(embedded_test_server_->port()) +
+      std::string("/ondomain"));
+  expected_features.AddBooleanFeature(features::kPageActionURL +
+      std::string("http://host2.com/"));
 
   FeatureMap features;
   LoadHtml("host.com", response);
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 1b9397d..490b8a1c 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1523,6 +1523,9 @@
                       ".",
                       "//chrome")
       deps += [ "//chrome/browser/media/router:test_support" ]
+      if (!toolkit_views) {
+        sources -= [ "../browser/ui/views/media_router/media_router_ui_browsertest.cc" ]
+      }
     }
     if (enable_webrtc) {
       sources += rebase_path(unit_gypi_values.chrome_unit_tests_webrtc_sources,
diff --git a/chrome/test/android/javatests_staging/src/org/chromium/chrome/test/util/ChromeTabUtils.java b/chrome/test/android/javatests_staging/src/org/chromium/chrome/test/util/ChromeTabUtils.java
index e64dafd4..458b6343 100644
--- a/chrome/test/android/javatests_staging/src/org/chromium/chrome/test/util/ChromeTabUtils.java
+++ b/chrome/test/android/javatests_staging/src/org/chromium/chrome/test/util/ChromeTabUtils.java
@@ -148,7 +148,7 @@
             public void run() {
                 tab.addObserver(new EmptyTabObserver() {
                     @Override
-                    public void onPageLoadStarted(Tab tab) {
+                    public void onPageLoadStarted(Tab tab, String url) {
                         startedCallback.notifyCalled();
                         tab.removeObserver(this);
                     }
diff --git a/chrome/test/chromedriver/VERSION b/chrome/test/chromedriver/VERSION
index e3d06964..6d28a11 100644
--- a/chrome/test/chromedriver/VERSION
+++ b/chrome/test/chromedriver/VERSION
@@ -1 +1 @@
-2.15
+2.16
diff --git a/chrome/test/chromedriver/chrome/browser_info.cc b/chrome/test/chromedriver/chrome/browser_info.cc
index b5bfeb5..23782f2 100644
--- a/chrome/test/chromedriver/chrome/browser_info.cc
+++ b/chrome/test/chromedriver/chrome/browser_info.cc
@@ -21,17 +21,20 @@
     : browser_name(std::string()),
       browser_version(std::string()),
       build_no(kToTBuildNo),
-      blink_revision(kToTBlinkRevision) {
+      blink_revision(kToTBlinkRevision),
+      is_android(false) {
 }
 
 BrowserInfo::BrowserInfo(std::string browser_name,
                          std::string browser_version,
                          int build_no,
-                         int blink_revision)
+                         int blink_revision,
+                         bool is_android)
     : browser_name(browser_name),
       browser_version(browser_version),
       build_no(build_no),
-      blink_revision(blink_revision) {
+      blink_revision(blink_revision),
+      is_android(is_android) {
 }
 
 Status ParseBrowserInfo(const std::string& data, BrowserInfo* browser_info) {
@@ -43,13 +46,13 @@
   if (!value->GetAsDictionary(&dict))
     return Status(kUnknownError, "version info not a dictionary");
 
-  browser_info->is_android = dict->HasKey("Android-Package");
-
+  bool has_android_package = dict->HasKey("Android-Package");
   std::string browser_string;
   if (!dict->GetString("Browser", &browser_string))
     return Status(kUnknownError, "version doesn't include 'Browser'");
 
-  Status status = ParseBrowserString(browser_string, browser_info);
+  Status status =
+      ParseBrowserString(has_android_package, browser_string, browser_info);
   if (status.IsError())
     return status;
 
@@ -60,8 +63,12 @@
   return ParseBlinkVersionString(blink_version, &browser_info->blink_revision);
 }
 
-Status ParseBrowserString(const std::string& browser_string,
+Status ParseBrowserString(bool has_android_package,
+                          const std::string& browser_string,
                           BrowserInfo* browser_info) {
+  if (has_android_package)
+    browser_info->is_android = true;
+
   if (browser_string.empty()) {
     browser_info->browser_name = "content shell";
     return Status(kOk);
@@ -87,13 +94,14 @@
     }
   }
 
-  if (browser_string.find("Version/") == 0u ||        // KitKat
-      (browser_info->is_android && build_no == 0)) {  // Lollipop
+  if (browser_string.find("Version/") == 0u ||   // KitKat
+      (has_android_package && build_no == 0)) {  // Lollipop
     size_t pos = browser_string.find(kVersionPrefix);
     if (pos != std::string::npos) {
       browser_info->browser_name = "webview";
       browser_info->browser_version =
           browser_string.substr(pos + kVersionPrefix.length());
+      browser_info->is_android = true;
     }
     return Status(kOk);
   }
diff --git a/chrome/test/chromedriver/chrome/browser_info.h b/chrome/test/chromedriver/chrome/browser_info.h
index 89afdf5..ce32850 100644
--- a/chrome/test/chromedriver/chrome/browser_info.h
+++ b/chrome/test/chromedriver/chrome/browser_info.h
@@ -20,7 +20,8 @@
   BrowserInfo(std::string browser_name_,
               std::string browser_version_,
               int build_no_,
-              int blink_revision_);
+              int blink_revision_,
+              bool is_android_);
 
   std::string browser_name;
   std::string browser_version;
@@ -32,7 +33,8 @@
 Status ParseBrowserInfo(const std::string& data,
                         BrowserInfo* browser_info);
 
-Status ParseBrowserString(const std::string& browser_string,
+Status ParseBrowserString(bool has_android_package,
+                          const std::string& browser_string,
                           BrowserInfo* browser_info);
 
 Status ParseBlinkVersionString(const std::string& blink_version,
diff --git a/chrome/test/chromedriver/chrome/browser_info_unittest.cc b/chrome/test/chromedriver/chrome/browser_info_unittest.cc
index f6dc5a8..04236a1 100644
--- a/chrome/test/chromedriver/chrome/browser_info_unittest.cc
+++ b/chrome/test/chromedriver/chrome/browser_info_unittest.cc
@@ -56,43 +56,45 @@
 
 TEST(ParseBrowserString, KitKatWebView) {
   BrowserInfo browser_info;
-  browser_info.is_android = true;
   Status status =
-      ParseBrowserString("Version/4.0 Chrome/30.0.0.0", &browser_info);
+      ParseBrowserString(false, "Version/4.0 Chrome/30.0.0.0", &browser_info);
   ASSERT_TRUE(status.IsOk());
   ASSERT_EQ("webview", browser_info.browser_name);
   ASSERT_EQ("30.0.0.0", browser_info.browser_version);
   ASSERT_EQ(kToTBuildNo, browser_info.build_no);
+  ASSERT_TRUE(browser_info.is_android);
 }
 
 TEST(ParseBrowserString, LollipopWebView) {
   BrowserInfo browser_info;
-  browser_info.is_android = true;
-  Status status = ParseBrowserString("Chrome/37.0.0.0", &browser_info);
+  Status status = ParseBrowserString(true, "Chrome/37.0.0.0", &browser_info);
   ASSERT_TRUE(status.IsOk());
   ASSERT_EQ("webview", browser_info.browser_name);
   ASSERT_EQ("37.0.0.0", browser_info.browser_version);
   ASSERT_EQ(kToTBuildNo, browser_info.build_no);
+  ASSERT_TRUE(browser_info.is_android);
 }
 
 TEST(ParseBrowserString, AndroidChrome) {
   BrowserInfo browser_info;
-  browser_info.is_android = true;
-  Status status = ParseBrowserString("Chrome/39.0.2171.59", &browser_info);
+  Status status =
+      ParseBrowserString(true, "Chrome/39.0.2171.59", &browser_info);
   ASSERT_TRUE(status.IsOk());
   ASSERT_EQ("chrome", browser_info.browser_name);
   ASSERT_EQ("39.0.2171.59", browser_info.browser_version);
   ASSERT_EQ(2171, browser_info.build_no);
+  ASSERT_TRUE(browser_info.is_android);
 }
 
 TEST(ParseBrowserString, DesktopChrome) {
   BrowserInfo browser_info;
-  browser_info.is_android = false;
-  Status status = ParseBrowserString("Chrome/39.0.2171.59", &browser_info);
+  Status status =
+      ParseBrowserString(false, "Chrome/39.0.2171.59", &browser_info);
   ASSERT_TRUE(status.IsOk());
   ASSERT_EQ("chrome", browser_info.browser_name);
   ASSERT_EQ("39.0.2171.59", browser_info.browser_version);
   ASSERT_EQ(2171, browser_info.build_no);
+  ASSERT_FALSE(browser_info.is_android);
 }
 
 TEST(ParseBlinkVersionString, GitHash) {
diff --git a/chrome/test/chromedriver/chrome/chrome_impl.cc b/chrome/test/chromedriver/chrome/chrome_impl.cc
index 97225aa..aedea8d 100644
--- a/chrome/test/chromedriver/chrome/chrome_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_impl.cc
@@ -55,7 +55,8 @@
     if (view.type == WebViewInfo::kPage ||
         view.type == WebViewInfo::kApp ||
         (view.type == WebViewInfo::kOther &&
-         view.url.find("chrome-extension://") == 0)) {
+         (view.url.find("chrome-extension://") == 0 ||
+          view.url == "chrome://print/"))) {
       bool found = false;
       for (WebViewList::const_iterator web_view_iter = web_views_.begin();
            web_view_iter != web_views_.end(); ++web_view_iter) {
diff --git a/chrome/test/chromedriver/chrome/navigation_tracker.cc b/chrome/test/chromedriver/chrome/navigation_tracker.cc
index ed9ad87..540e83d 100644
--- a/chrome/test/chromedriver/chrome/navigation_tracker.cc
+++ b/chrome/test/chromedriver/chrome/navigation_tracker.cc
@@ -181,7 +181,8 @@
 
 Status NavigationTracker::OnCommandSuccess(DevToolsClient* client,
                                            const std::string& method) {
-  if (method == "Page.navigate" && loading_state_ != kLoading) {
+  if ((method == "Page.navigate" || method == "Page.navigateToHistoryEntry") &&
+      loading_state_ != kLoading) {
     // At this point the browser has initiated the navigation, but besides that,
     // it is unknown what will happen.
     //
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc
index 85e51d2..17f7e4f 100644
--- a/chrome/test/chromedriver/chrome_launcher.cc
+++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -381,6 +381,9 @@
           termination_reason = "exited abnormally";
           break;
         case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
+#if defined(OS_CHROMEOS)
+        case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
+#endif
           termination_reason = "was killed";
           break;
         case base::TERMINATION_STATUS_PROCESS_CRASHED:
diff --git a/chrome/test/chromedriver/element_commands.cc b/chrome/test/chromedriver/element_commands.cc
index b414cf7..49df717 100644
--- a/chrome/test/chromedriver/element_commands.cc
+++ b/chrome/test/chromedriver/element_commands.cc
@@ -16,7 +16,6 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/test/chromedriver/basic_types.h"
-#include "chrome/test/chromedriver/chrome/browser_info.h"
 #include "chrome/test/chromedriver/chrome/chrome.h"
 #include "chrome/test/chromedriver/chrome/js.h"
 #include "chrome/test/chromedriver/chrome/status.h"
@@ -192,7 +191,7 @@
       session, web_view, element_id, &location);
   if (status.IsError())
     return status;
-  if (session->chrome->GetBrowserInfo()->build_no < 2388) {
+  if (!session->chrome->HasTouchScreen()) {
     // TODO(samuong): remove this once we stop supporting M44.
     std::list<TouchEvent> events;
     events.push_back(
@@ -210,7 +209,7 @@
     const std::string& element_id,
     const base::DictionaryValue& params,
     scoped_ptr<base::Value>* value) {
-  if (session->chrome->GetBrowserInfo()->build_no < 2388) {
+  if (!session->chrome->HasTouchScreen()) {
     // TODO(samuong): remove this once we stop supporting M44.
     return Status(kUnknownCommand, "Double tap command requires Chrome 44+");
   }
@@ -228,7 +227,7 @@
     const std::string& element_id,
     const base::DictionaryValue& params,
     scoped_ptr<base::Value>* value) {
-  if (session->chrome->GetBrowserInfo()->build_no < 2388) {
+  if (!session->chrome->HasTouchScreen()) {
     // TODO(samuong): remove this once we stop supporting M44.
     return Status(kUnknownCommand, "Long press command requires Chrome 44+");
   }
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index b63b926a..9b0c008 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -1045,9 +1045,7 @@
     if _ANDROID_PACKAGE_KEY:
       packages = ['chrome_stable', 'chrome_beta', 'chromedriver_webview_shell']
       if _ANDROID_PACKAGE_KEY in packages:
-        self.assertRaisesRegexp(RuntimeError,
-                                'Server returned error: Not Implemented',
-                                self._driver.TouchPinch, 1, 2, 3.0)
+        self.assertFalse(self._driver.capabilities['hasTouchScreen'])
 
   def testHasTouchScreen(self):
     self.assertIn('hasTouchScreen', self._driver.capabilities)
@@ -1081,6 +1079,15 @@
     p = self._driver.FindElement('tag name', 'p')
     self.assertEquals('Two', p.GetText())
 
+  def testCanSwitchToPrintPreviewDialog(self):
+    old_handles = self._driver.GetWindowHandles()
+    self.assertEquals(1, len(old_handles))
+    self._driver.ExecuteScript('setTimeout(function(){window.print();}, 0);')
+    new_window_handle = self._WaitForNewWindow(old_handles)
+    self.assertNotEqual(None, new_window_handle)
+    self._driver.SwitchToWindow(new_window_handle)
+    self.assertEquals('chrome://print/', self._driver.GetCurrentUrl())
+
 
 class ChromeDriverAndroidTest(ChromeDriverBaseTest):
   """End to end tests for Android-specific tests."""
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index dab6122..8866cda 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -88,6 +88,8 @@
     # Flaky: https://code.google.com/p/chromedriver/issues/detail?id=653
     'PageLoadingTest.testShouldBeAbleToNavigateBackInTheBrowserHistoryInPresenceOfIframes',
     'PageLoadingTest.testShouldBeAbleToNavigateBackInTheBrowserHistory',
+    # https://code.google.com/p/chromedriver/issues/detail?id=1117
+    'PageLoadingTest.testShouldBeAbleToAccessPagesWithAnInsecureSslCertificate',
 ]
 
 
@@ -209,7 +211,13 @@
     _OS_NEGATIVE_FILTER['android:chrome']
 )
 _OS_NEGATIVE_FILTER['android:chrome_shell'] = (
-    _OS_NEGATIVE_FILTER['android:chrome'])
+    _OS_NEGATIVE_FILTER['android:chrome'] + [
+        # https://code.google.com/p/chromedriver/issues/detail?id=1119
+        'ClickTest.testShouldClickOnFirstBoundingClientRectWithNonZeroSize',
+        'CombinedInputActionsTest.testCanClickOnLinksWithAnOffset',
+        'CombinedInputActionsTest.testMouseMovementWorksWhenNavigatingToAnotherPage',
+    ]
+)
 _OS_NEGATIVE_FILTER['android:chromedriver_webview_shell'] = (
     _OS_NEGATIVE_FILTER['android:chrome'] + [
          # https://code.google.com/p/chromedriver/issues/detail?id=645
diff --git a/chrome/test/data/chromedriver/outer.html b/chrome/test/data/chromedriver/outer.html
index a78d97a..50e06586 100644
--- a/chrome/test/data/chromedriver/outer.html
+++ b/chrome/test/data/chromedriver/outer.html
@@ -5,6 +5,6 @@
   </head>
   <body>
     <p>Two</p>
-    <iframe src="inner.html">
+    <iframe src="inner.html"></iframe>
   </body>
 </html>
diff --git a/chrome/test/data/extensions/api_test/automation/tests/desktop/actions.js b/chrome/test/data/extensions/api_test/automation/tests/desktop/actions.js
index c50f3f3..92d0b48 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/desktop/actions.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/desktop/actions.js
@@ -25,6 +25,15 @@
       chrome.test.succeed();
     }, true);
     firstFocusableNode.focus();
+  },
+
+  function testContextMenu() {
+    var addressBar = rootNode.find({role: 'textField'});
+    rootNode.addEventListener(EventType.menuStart, function(e) {
+      addressBar.showContextMenu();
+      chrome.test.succeed();
+    }, true);
+    addressBar.showContextMenu();
   }
 ];
 
diff --git a/chrome/test/data/extensions/api_test/automation/tests/desktop/common.js b/chrome/test/data/extensions/api_test/automation/tests/desktop/common.js
index 7a2b9030..a793d65 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/desktop/common.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/desktop/common.js
@@ -34,7 +34,8 @@
   chrome.tabs.create(createParams, function(tab) {
     chrome.tabs.onUpdated.addListener(function(tabId, changeInfo) {
       if (tabId == tab.id && changeInfo.status == 'complete') {
-        callback();
+        if (callback)
+          callback();
       }
     });
   });
@@ -57,7 +58,7 @@
             return;
 
           if (subroot.role == 'rootWebArea' &&
-              subroot.attributes.docUrl.indexOf(opt_docString) != -1)
+              subroot.docUrl.indexOf(opt_docString) != -1)
             runTestInternal();
         },
         true);
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/find.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/find.js
index a53d6304..f171206 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/find.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/find.js
@@ -19,7 +19,7 @@
 
   h1 = group.firstChild;
   assertEq(RoleType.heading, h1.role);
-  assertEq(1, h1.attributes.hierarchicalLevel);
+  assertEq(1, h1.hierarchicalLevel);
 
   p1 = group.lastChild;
   assertEq(RoleType.paragraph, p1.role);
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/sanity_check.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/sanity_check.js
index 1a860e1..64c4e36 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/sanity_check.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/sanity_check.js
@@ -22,7 +22,7 @@
     assertEq(RoleType.rootWebArea, rootNode.role);
     assertEq(1, children.length);
     var body = children[0];
-    assertEq('body', body.attributes.htmlTag);
+    assertEq('body', body.htmlTag);
 
     RemoveUntestedStates(body.state);
     assertEq({enabled: true, readOnly: true},
diff --git a/chrome/test/data/extensions/api_test/settings_private/test.js b/chrome/test/data/extensions/api_test/settings_private/test.js
index 28ac7f64..e611668 100644
--- a/chrome/test/data/extensions/api_test/settings_private/test.js
+++ b/chrome/test/data/extensions/api_test/settings_private/test.js
@@ -28,6 +28,16 @@
           chrome.test.succeed();
         });
   },
+  function setPref_CrOSSetting() {
+    chrome.settingsPrivate.setPref(
+        'cros.accounts.allowBWSI',
+        false,
+        kTestPageId,
+        function(success) {
+          callbackResult(success);
+          chrome.test.succeed();
+        });
+  },
   function getPref() {
     chrome.settingsPrivate.getPref(
         kTestPrefName,
@@ -37,6 +47,15 @@
           chrome.test.succeed();
         });
   },
+  function getPref_CrOSSetting() {
+    chrome.settingsPrivate.getPref(
+        'cros.accounts.allowBWSI',
+        function(value) {
+          chrome.test.assertTrue(value !== null);
+          callbackResult(true);
+          chrome.test.succeed();
+        });
+  },
   function getAllPrefs() {
     chrome.settingsPrivate.getAllPrefs(
         function(prefs) {
@@ -60,6 +79,21 @@
         kTestPageId,
         function() {});
   },
+  function onPrefsChanged_CrOSSetting() {
+    chrome.settingsPrivate.onPrefsChanged.addListener(function(prefs) {
+      chrome.test.assertTrue(prefs.length > 0);
+      chrome.test.assertEq('cros.accounts.allowBWSI', prefs[0].key);
+      chrome.test.assertEq(false, prefs[0].value);
+      callbackResult(true);
+      chrome.test.succeed();
+    });
+
+    chrome.settingsPrivate.setPref(
+        'cros.accounts.allowBWSI',
+        false,
+        kTestPageId,
+        function() {});
+  },
 ];
 
 var testToRun = window.location.search.substring(1);
diff --git a/chrome/test/data/extensions/app_no_www/manifest.json b/chrome/test/data/extensions/app_no_www/manifest.json
new file mode 100644
index 0000000..9a413dc
--- /dev/null
+++ b/chrome/test/data/extensions/app_no_www/manifest.json
@@ -0,0 +1,13 @@
+{
+  "name": "App Test",
+  "version": "1",
+  "manifest_version": 2,
+  "permissions": [
+    "notifications"
+  ],
+  "app": {
+    "launch": {
+      "web_url": "http://example.com/"
+    }
+  }
+}
diff --git a/chrome/test/data/policy/blacklist-subresources.html b/chrome/test/data/policy/blacklist-subresources.html
new file mode 100644
index 0000000..c02f39d2
--- /dev/null
+++ b/chrome/test/data/policy/blacklist-subresources.html
@@ -0,0 +1,43 @@
+<html>
+<script>
+
+var imageLoadResult = 'N/A';
+var iframeLoadResult = 'N/A';
+
+function imageLoaded() {
+  var image = document.getElementById('blacklisted_image');
+  // Additional sanity check to make sure the image is indeed loaded.
+  // Not strictly needed.
+  if (image.height == 1 && image.width == 1) {
+    imageLoadResult = "success";
+  } else {
+    imageLoadResult = "error";
+  }
+}
+
+function imageError() {
+  imageLoadResult = "error";
+}
+
+function iframeLoaded() {
+  // Unfortunately, iframe load errors generally don't result in onerror
+  // actually being called, so also check that the title is accessible.
+  // Since this is a same-site iframe, it generally should be, unless there's
+  // an error page showing in the iframe, in which case it's treated as a
+  // cross-domain iframe.
+  try {
+    document.getElementById('blacklisted_iframe').contentDocument.title;
+    iframeLoadResult = "success";
+  } catch (err) {
+    iframeLoadResult = "error";
+  }
+}
+
+function iframeError() {
+  iframeLoadResult = "error";
+}
+
+</script>
+<img id="blacklisted_image" src="pixel.png" onload="imageLoaded()" onerror="imageError()"></img>
+<iframe id="blacklisted_iframe" src="blank.html" onload="iframeLoaded()" onerror="iframeError()"></iframe>
+</html>
diff --git a/chrome/test/data/policy/pixel.png b/chrome/test/data/policy/pixel.png
new file mode 100644
index 0000000..818c71d
--- /dev/null
+++ b/chrome/test/data/policy/pixel.png
Binary files differ
diff --git a/chrome/test/data/safe_browsing/iframe_redirect_malware.html b/chrome/test/data/safe_browsing/iframe_redirect_malware.html
index b8b94bff..45d2087 100644
--- a/chrome/test/data/safe_browsing/iframe_redirect_malware.html
+++ b/chrome/test/data/safe_browsing/iframe_redirect_malware.html
@@ -1,9 +1,9 @@
 <html>
 <body>
-<iframe src ="/server-redirect?http://localhost/files/safe_browsing/malware.html" width="100%" height="300">
+<iframe src="redirect_to_malware.html" width="100%" height="300">
   <p>Your browser does not support iframes.</p>
 </iframe>
-<iframe src ="/empty.hml" width="100%" height="300">
+<iframe src="/empty.hml" width="100%" height="300">
   <p>Your browser does not support iframes.</p>
 </iframe>
 </body>
diff --git a/chrome/test/data/safe_browsing/interstitial_cancel.html b/chrome/test/data/safe_browsing/interstitial_cancel.html
index 1432387e..de48c8ee 100644
--- a/chrome/test/data/safe_browsing/interstitial_cancel.html
+++ b/chrome/test/data/safe_browsing/interstitial_cancel.html
@@ -7,21 +7,16 @@
   tab = window.open("iframe_redirect_malware.html");
 }
 
-function openMalware()
-{
-  window.open("http://localhost");
-}
-
 function openWin()
 {
-  tab = window.open("/server-redirect?http://localhost/files/safe_browsing/malware.html");
+  tab = window.open("redirect_to_malware.html");
 }
 
 function stopWin()
 {
   tab.stop();
   // This will trigger a navigation event.
-  window.location = "http://localhost";
+  window.location = "/";
 }
 
 </script>
@@ -35,10 +30,6 @@
 <form>
 <input type=button value="Stop Window" onclick="stopWin()">
 </form>
-
-<form>
-<input type=button value="Open malware in tab" onclick="openMalware()">
-</form>
 </body>
 
 </html>
diff --git a/chrome/test/data/safe_browsing/redirect_to_malware.html b/chrome/test/data/safe_browsing/redirect_to_malware.html
new file mode 100644
index 0000000..257cc564
--- /dev/null
+++ b/chrome/test/data/safe_browsing/redirect_to_malware.html
@@ -0,0 +1 @@
+foo
diff --git a/chrome/test/data/safe_browsing/redirect_to_malware.html.mock-http-headers b/chrome/test/data/safe_browsing/redirect_to_malware.html.mock-http-headers
new file mode 100644
index 0000000..899a9841
--- /dev/null
+++ b/chrome/test/data/safe_browsing/redirect_to_malware.html.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 302 Redirect
+Location: malware.html
diff --git a/chromecast/app/cast_main_delegate.cc b/chromecast/app/cast_main_delegate.cc
index 58c7507..e90c34f2 100644
--- a/chromecast/app/cast_main_delegate.cc
+++ b/chromecast/app/cast_main_delegate.cc
@@ -150,13 +150,13 @@
 }
 
 content::ContentBrowserClient* CastMainDelegate::CreateContentBrowserClient() {
-  browser_client_.reset(new CastContentBrowserClient);
+  browser_client_ = CastContentBrowserClient::Create();
   return browser_client_.get();
 }
 
 content::ContentRendererClient*
 CastMainDelegate::CreateContentRendererClient() {
-  renderer_client_.reset(new CastContentRendererClient);
+  renderer_client_ = CastContentRendererClient::Create();
   return renderer_client_.get();
 }
 
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastCrashUploader.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastCrashUploader.java
index 4f0b144b..5f40480 100644
--- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastCrashUploader.java
+++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastCrashUploader.java
@@ -4,23 +4,20 @@
 
 package org.chromium.chromecast.shell;
 
-import android.net.http.AndroidHttpClient;
-import android.util.Log;
-
-import org.apache.http.HttpHost;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.InputStreamEntity;
+import org.chromium.base.Log;
 
 import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.io.SequenceInputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
 import java.util.LinkedList;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executors;
@@ -37,7 +34,7 @@
  * explicitly blocks any post-dump hooks or uploading for Android builds.
  */
 public final class CastCrashUploader {
-    private static final String TAG = "CastCrashUploader";
+    private static final String TAG = Log.makeTag("CastCrashUploader");
     private static final String CRASH_REPORT_HOST = "clients2.google.com";
     private static final String CAST_SHELL_USER_AGENT = android.os.Build.MODEL + "/CastShell";
     // Multipart dump filename has format "[random string].dmp[pid]", e.g.
@@ -93,10 +90,9 @@
      */
     private void queueAllCrashDumpUploads(boolean synchronous, String logFile) {
         if (mCrashDumpPath == null) return;
-        Log.d(TAG, "Checking for crash dumps");
+        Log.i(TAG, "Checking for crash dumps");
 
         LinkedList<Future> tasks = new LinkedList<Future>();
-        final AndroidHttpClient httpClient = AndroidHttpClient.newInstance(CAST_SHELL_USER_AGENT);
         File crashDumpDirectory = new File(mCrashDumpPath);
         for (File potentialDump : crashDumpDirectory.listFiles()) {
             String dumpName = potentialDump.getName();
@@ -111,23 +107,15 @@
                 }
                 // Check if the dump we found has pid matching this process, and if so include
                 // this process's log.
-                // TODO(kjoswiak): Currently, logs are lost if dump cannot be uploaded right away.
+                // TODO(gunsch): Currently, logs are lost if dump cannot be uploaded right away.
                 if (dumpPid == android.os.Process.myPid()) {
-                    tasks.add(queueCrashDumpUpload(httpClient, potentialDump, new File(logFile)));
+                    tasks.add(queueCrashDumpUpload(potentialDump, new File(logFile)));
                 } else {
-                    tasks.add(queueCrashDumpUpload(httpClient, potentialDump, null));
+                    tasks.add(queueCrashDumpUpload(potentialDump, null));
                 }
             }
         }
 
-        // When finished uploading all of the queued dumps, release httpClient
-        tasks.add(mExecutorService.submit(new Runnable() {
-            @Override
-            public void run() {
-                httpClient.close();
-            }
-        }));
-
         // Wait on tasks, if necessary.
         if (synchronous) {
             for (Future task : tasks) {
@@ -142,12 +130,11 @@
     /**
      * Enqueues a background task to upload a single crash dump file.
      */
-    private Future queueCrashDumpUpload(final AndroidHttpClient httpClient, final File dumpFile,
-            final File logFile) {
+    private Future queueCrashDumpUpload(final File dumpFile, final File logFile) {
         return mExecutorService.submit(new Runnable() {
             @Override
             public void run() {
-                Log.d(TAG, "Uploading dump crash log: " + dumpFile.getName());
+                Log.i(TAG, "Uploading dump crash log: %s", dumpFile.getName());
 
                 try {
                     InputStream uploadCrashDumpStream = new FileInputStream(dumpFile);
@@ -161,7 +148,7 @@
                     String mimeBoundary = dumpFirstLine.substring(2);
 
                     if (logFile != null) {
-                        Log.d(TAG, "Including log file: " + logFile.getName());
+                        Log.i(TAG, "Including log file: %s", logFile.getName());
                         StringBuffer logHeader = new StringBuffer();
                         logHeader.append(dumpFirstLine);
                         logHeader.append("\n");
@@ -178,49 +165,80 @@
                                 uploadCrashDumpStream);
                     }
 
-                    InputStreamEntity entity = new InputStreamEntity(uploadCrashDumpStream, -1);
-                    entity.setContentType("multipart/form-data; boundary=" + mimeBoundary);
-
-                    HttpPost uploadRequest = new HttpPost(mCrashReportUploadUrl);
-                    uploadRequest.setEntity(entity);
-                    HttpResponse response =
-                            httpClient.execute(new HttpHost(CRASH_REPORT_HOST), uploadRequest);
+                    HttpURLConnection connection =
+                            (HttpURLConnection) new URL(mCrashReportUploadUrl).openConnection();
 
                     // Expect a report ID as the entire response
-                    String responseLine = getFirstLine(response.getEntity().getContent());
+                    try {
+                        connection.setDoOutput(true);
+                        connection.setRequestProperty("Content-Type",
+                                "multipart/form-data; boundary=" + mimeBoundary);
+                        streamCopy(uploadCrashDumpStream, connection.getOutputStream());
 
-                    int statusCode = response.getStatusLine().getStatusCode();
-                    if (statusCode == HttpStatus.SC_OK) {
-                        Log.d(TAG, "Successfully uploaded to " + mCrashReportUploadUrl
-                                + ", report ID: " + responseLine);
-                    } else {
-                        Log.e(TAG, "Failed response (" + statusCode + "): " + responseLine);
+                        String responseLine = getFirstLine(connection.getInputStream());
 
-                        // 400 Bad Request is returned if the dump file is malformed. If requeset
-                        // is not malformed, shortcircuit before clean up to avoid deletion and
-                        // retry later, otherwise pass through and delete malformed file
-                        if (statusCode != HttpStatus.SC_BAD_REQUEST) {
-                            return;
+                        int responseCode = connection.getResponseCode();
+                        if (responseCode == HttpURLConnection.HTTP_OK
+                                || responseCode == HttpURLConnection.HTTP_CREATED
+                                || responseCode == HttpURLConnection.HTTP_ACCEPTED) {
+                            Log.i(TAG, "Successfully uploaded to %s, report ID: %s",
+                                    mCrashReportUploadUrl, responseLine);
+                        } else {
+                            Log.e(TAG, "Failed response (%d): %s", responseCode,
+                                    connection.getResponseMessage());
+
+                            // 400 Bad Request is returned if the dump file is malformed. If request
+                            // is not malformed, short-circuit before cleanup to avoid deletion and
+                            // retry later, otherwise pass through and delete malformed file.
+                            if (responseCode != HttpURLConnection.HTTP_BAD_REQUEST) {
+                                return;
+                            }
+                        }
+                    } catch (FileNotFoundException fnfe) {
+                        // Android's HttpURLConnection implementation fires FNFE on some errors.
+                        Log.e(TAG, "Failed response: " + connection.getResponseCode(), fnfe);
+                    } finally {
+                        connection.disconnect();
+                        dumpFileStream.close();
+                        if (logFileStream != null) {
+                            logFileStream.close();
                         }
                     }
 
                     // Delete the file so we don't re-upload it next time.
-                    uploadCrashDumpStream.close();
-                    dumpFileStream.close();
                     dumpFile.delete();
 
                     if (logFile != null && logFile.exists()) {
-                        logFileStream.close();
                         logFile.delete();
                     }
                 } catch (IOException e) {
-                    Log.e(TAG, "File I/O error trying to upload crash dump", e);
+                    Log.e(TAG, "Error occurred trying to upload crash dump", e);
                 }
             }
         });
     }
 
     /**
+     * Copies all available data from |inStream| to |outStream|. Closes both
+     * streams when done.
+     *
+     * @param inStream the stream to read
+     * @param outStream the stream to write to
+     * @throws IOException
+     */
+    private static void streamCopy(InputStream inStream,
+            OutputStream outStream) throws IOException {
+        byte[] temp = new byte[4096];
+        int bytesRead = inStream.read(temp);
+        while (bytesRead >= 0) {
+            outStream.write(temp, 0, bytesRead);
+            bytesRead = inStream.read(temp);
+        }
+        inStream.close();
+        outStream.close();
+    }
+
+    /**
      * Gets the first line from an input stream, opening and closing readers to do so.
      * We're targeting Java 6, so this is still tedious to do.
      * @return First line of the input stream.
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index e385d963..9e265ae 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -24,6 +24,7 @@
 #include "chromecast/browser/media/cma_message_filter_host.h"
 #include "chromecast/browser/url_request_context_factory.h"
 #include "chromecast/common/global_descriptors.h"
+#include "chromecast/media/cma/backend/media_pipeline_device.h"
 #include "components/crash/app/breakpad_linux.h"
 #include "components/crash/browser/crash_handler_host_linux.h"
 #include "components/network_hints/browser/network_hints_message_filter.h"
@@ -75,7 +76,11 @@
     content::RenderProcessHost* host) {
 #if !defined(OS_ANDROID)
   scoped_refptr<media::CmaMessageFilterHost> cma_message_filter(
-      new media::CmaMessageFilterHost(host->GetID()));
+      new media::CmaMessageFilterHost(
+          host->GetID(),
+          base::Bind(
+              &CastContentBrowserClient::PlatformCreateMediaPipelineDevice,
+              base::Unretained(this))));
   host->AddFilter(cma_message_filter.get());
 #endif  // !defined(OS_ANDROID)
 
@@ -146,22 +151,29 @@
   return false;
 }
 
+void CastContentBrowserClient::AppendMappedFileCommandLineSwitches(
+    base::CommandLine* command_line) {
+  std::string process_type =
+      command_line->GetSwitchValueNative(switches::kProcessType);
+
+#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
+  if (process_type != switches::kZygoteProcess) {
+    DCHECK(natives_fd_exists());
+    command_line->AppendSwitch(::switches::kV8NativesPassedByFD);
+    if (snapshot_fd_exists())
+      command_line->AppendSwitch(::switches::kV8SnapshotPassedByFD);
+  }
+}
+
+#endif  // V8_USE_EXTERNAL_STARTUP_DATA
 void CastContentBrowserClient::AppendExtraCommandLineSwitches(
     base::CommandLine* command_line,
     int child_process_id) {
-
   std::string process_type =
       command_line->GetSwitchValueNative(switches::kProcessType);
   base::CommandLine* browser_command_line =
       base::CommandLine::ForCurrentProcess();
 
-#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
-  if (process_type != switches::kZygoteProcess) {
-    command_line->AppendSwitch(::switches::kV8NativesPassedByFD);
-    command_line->AppendSwitch(::switches::kV8SnapshotPassedByFD);
-  }
-#endif  // V8_USE_EXTERNAL_STARTUP_DATA
-
   // IsCrashReporterEnabled() is set when InitCrashReporter() is called, and
   // controlled by GetBreakpadClient()->EnableBreakpadForProcess(), therefore
   // it's ok to add switch to every process here.
@@ -316,7 +328,7 @@
     int child_process_id,
     content::FileDescriptorInfo* mappings) {
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
-  if (v8_natives_fd_.get() == -1 || v8_snapshot_fd_.get() == -1) {
+  if (!natives_fd_exists()) {
     int v8_natives_fd = -1;
     int v8_snapshot_fd = -1;
     if (gin::V8Initializer::OpenV8FilesForChildProcesses(&v8_natives_fd,
@@ -325,7 +337,9 @@
       v8_snapshot_fd_.reset(v8_snapshot_fd);
     }
   }
-  DCHECK(v8_natives_fd_.get() != -1 && v8_snapshot_fd_.get() != -1);
+  // V8 can't start up without the source of the natives, but it can
+  // start up (slower) without the snapshot.
+  DCHECK(natives_fd_exists());
   mappings->Share(kV8NativesDataDescriptor, v8_natives_fd_.get());
   mappings->Share(kV8SnapshotDataDescriptor, v8_snapshot_fd_.get());
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h
index 5e5c262..fa71076 100644
--- a/chromecast/browser/cast_content_browser_client.h
+++ b/chromecast/browser/cast_content_browser_client.h
@@ -30,6 +30,11 @@
 }
 
 namespace chromecast {
+namespace media {
+class MediaPipelineDevice;
+class MediaPipelineDeviceParams;
+}
+
 namespace shell {
 
 class CastBrowserMainParts;
@@ -37,7 +42,10 @@
 
 class CastContentBrowserClient: public content::ContentBrowserClient {
  public:
-  CastContentBrowserClient();
+  // Creates an implementation of CastContentBrowserClient. Platform should
+  // link in an implementation as needed.
+  static scoped_ptr<CastContentBrowserClient> Create();
+
   ~CastContentBrowserClient() override;
 
   // Appends extra command line arguments before launching a new process.
@@ -48,6 +56,13 @@
   std::vector<scoped_refptr<content::BrowserMessageFilter>>
   PlatformGetBrowserMessageFilters();
 
+#if !defined(OS_ANDROID)
+  // Creates a MediaPipelineDevice (CMA backend) for media playback, called
+  // once per media player instance.
+  scoped_ptr<media::MediaPipelineDevice> PlatformCreateMediaPipelineDevice(
+      const media::MediaPipelineDeviceParams& params);
+#endif
+
   // content::ContentBrowserClient implementation:
   content::BrowserMainParts* CreateBrowserMainParts(
       const content::MainFunctionParams& parameters) override;
@@ -60,6 +75,8 @@
   bool IsHandledURL(const GURL& url) override;
   void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
                                       int child_process_id) override;
+  void AppendMappedFileCommandLineSwitches(
+      base::CommandLine* command_line) override;
   content::AccessTokenStore* CreateAccessTokenStore() override;
   void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,
                            content::WebPreferences* prefs) override;
@@ -107,6 +124,9 @@
       content::WebContents* web_contents) override;
 #endif  // defined(OS_ANDROID) && defined(VIDEO_HOLE)
 
+ protected:
+  CastContentBrowserClient();
+
  private:
   void AddNetworkHintsMessageFilter(int render_process_id,
                                     net::URLRequestContext* context);
@@ -131,6 +151,8 @@
 
   base::ScopedFD v8_natives_fd_;
   base::ScopedFD v8_snapshot_fd_;
+  bool natives_fd_exists() { return v8_natives_fd_ != -1; }
+  bool snapshot_fd_exists() { return v8_snapshot_fd_ != -1; }
 
   scoped_ptr<URLRequestContextFactory> url_request_context_factory_;
 
diff --git a/chromecast/browser/cast_content_browser_client_simple.cc b/chromecast/browser/cast_content_browser_client_simple.cc
index bde5a71..63a47040 100644
--- a/chromecast/browser/cast_content_browser_client_simple.cc
+++ b/chromecast/browser/cast_content_browser_client_simple.cc
@@ -4,12 +4,19 @@
 
 #include "chromecast/browser/cast_content_browser_client.h"
 
+#include "base/memory/scoped_ptr.h"
+#include "chromecast/media/cma/backend/media_pipeline_device.h"
 #include "content/public/browser/browser_message_filter.h"
 #include "media/audio/audio_manager_factory.h"
 
 namespace chromecast {
 namespace shell {
 
+// static
+scoped_ptr<CastContentBrowserClient> CastContentBrowserClient::Create() {
+  return make_scoped_ptr(new CastContentBrowserClient());
+}
+
 void CastContentBrowserClient::PlatformAppendExtraCommandLineSwitches(
     base::CommandLine* command_line) {
 }
@@ -26,5 +33,13 @@
   return scoped_ptr<::media::AudioManagerFactory>();
 }
 
+#if !defined(OS_ANDROID)
+scoped_ptr<media::MediaPipelineDevice>
+CastContentBrowserClient::PlatformCreateMediaPipelineDevice(
+    const media::MediaPipelineDeviceParams& params) {
+  return media::CreateMediaPipelineDevice(params);
+}
+#endif
+
 }  // namespace shell
 }  // namespace chromecast
diff --git a/chromecast/browser/media/cma_message_filter_host.cc b/chromecast/browser/media/cma_message_filter_host.cc
index 2d34dea..aeb2bc82 100644
--- a/chromecast/browser/media/cma_message_filter_host.cc
+++ b/chromecast/browser/media/cma_message_filter_host.cc
@@ -297,9 +297,12 @@
 
 }  // namespace
 
-CmaMessageFilterHost::CmaMessageFilterHost(int render_process_id)
+CmaMessageFilterHost::CmaMessageFilterHost(
+    int render_process_id,
+    const media::CreatePipelineDeviceCB& create_pipeline_device_cb)
     : content::BrowserMessageFilter(CastMediaMsgStart),
       process_id_(render_process_id),
+      create_pipeline_device_cb_(create_pipeline_device_cb),
       task_runner_(CmaMessageLoop::GetTaskRunner()),
       weak_factory_(this) {
   weak_this_ = weak_factory_.GetWeakPtr();
@@ -382,10 +385,9 @@
       base::Bind(&SetMediaPipeline,
                  process_id_, media_id, media_pipeline_host.get()));
   task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&MediaPipelineHost::Initialize,
-                 base::Unretained(media_pipeline_host.get()),
-                 load_type, client));
+      FROM_HERE, base::Bind(&MediaPipelineHost::Initialize,
+                            base::Unretained(media_pipeline_host.get()),
+                            load_type, client, create_pipeline_device_cb_));
   std::pair<MediaPipelineMap::iterator, bool> ret =
     media_pipelines_.insert(
         std::make_pair(media_id, media_pipeline_host.release()));
@@ -534,7 +536,8 @@
 }
 
 void CmaMessageFilterHost::VideoInitialize(
-    int media_id, TrackId track_id, const ::media::VideoDecoderConfig& config) {
+    int media_id, TrackId track_id,
+    const std::vector<::media::VideoDecoderConfig>& configs) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   MediaPipelineHost* media_pipeline = LookupById(media_id);
   if (!media_pipeline) {
@@ -564,7 +567,7 @@
       FROM_HERE,
       base::Bind(&MediaPipelineHost::VideoInitialize,
                  base::Unretained(media_pipeline),
-                 track_id, client, config, pipeline_status_cb));
+                 track_id, client, configs, pipeline_status_cb));
 }
 
 void CmaMessageFilterHost::StartPlayingFrom(
diff --git a/chromecast/browser/media/cma_message_filter_host.h b/chromecast/browser/media/cma_message_filter_host.h
index e000574..9b16205 100644
--- a/chromecast/browser/media/cma_message_filter_host.h
+++ b/chromecast/browser/media/cma_message_filter_host.h
@@ -12,6 +12,7 @@
 #include "base/memory/shared_memory.h"
 #include "base/memory/weak_ptr.h"
 #include "chromecast/common/media/cma_ipc_common.h"
+#include "chromecast/media/cma/backend/media_pipeline_device.h"
 #include "chromecast/media/cma/pipeline/load_type.h"
 #include "content/public/browser/browser_message_filter.h"
 #include "content/public/browser/browser_thread.h"
@@ -42,7 +43,9 @@
 class CmaMessageFilterHost
     : public content::BrowserMessageFilter {
  public:
-  explicit CmaMessageFilterHost(int render_process_id);
+  CmaMessageFilterHost(
+      int render_process_id,
+      const media::CreatePipelineDeviceCB& create_pipeline_device_cb);
 
   // content::BrowserMessageFilter implementation.
   void OnChannelClosing() override;
@@ -71,9 +74,10 @@
   void AudioInitialize(int media_id,
                        TrackId track_id,
                        const ::media::AudioDecoderConfig& config);
-  void VideoInitialize(int media_id,
-                       TrackId track_id,
-                       const ::media::VideoDecoderConfig& config);
+  void VideoInitialize(
+      int media_id,
+      TrackId track_id,
+      const std::vector<::media::VideoDecoderConfig>& configs);
   void StartPlayingFrom(int media_id, base::TimeDelta time);
   void Flush(int media_id);
   void Stop(int media_id);
@@ -109,6 +113,9 @@
   // Render process ID correponding to this message filter.
   const int process_id_;
 
+  // Factory function for device-specific part of media pipeline creation
+  media::CreatePipelineDeviceCB create_pipeline_device_cb_;
+
   // List of media pipeline and message loop media pipelines are running on.
   MediaPipelineMap media_pipelines_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
@@ -123,4 +130,3 @@
 }  // namespace chromecast
 
 #endif  // CHROMECAST_BROWSER_MEDIA_CMA_MESSAGE_FILTER_HOST_H_
-
diff --git a/chromecast/browser/media/media_pipeline_host.cc b/chromecast/browser/media/media_pipeline_host.cc
index ff3eb69..087077d 100644
--- a/chromecast/browser/media/media_pipeline_host.cc
+++ b/chromecast/browser/media/media_pipeline_host.cc
@@ -52,15 +52,15 @@
 
 void MediaPipelineHost::Initialize(
     LoadType load_type,
-    const MediaPipelineClient& client) {
+    const MediaPipelineClient& client,
+    const media::CreatePipelineDeviceCB& create_pipeline_device_cb) {
   DCHECK(thread_checker_.CalledOnValidThread());
   media_pipeline_.reset(new MediaPipelineImpl());
   MediaPipelineDeviceParams default_parameters;
   if (load_type == kLoadTypeMediaStream)
     default_parameters.sync_type = MediaPipelineDeviceParams::kModeIgnorePts;
   media_pipeline_->Initialize(
-      load_type,
-      CreateMediaPipelineDevice(default_parameters).Pass());
+      load_type, create_pipeline_device_cb.Run(default_parameters).Pass());
   media_pipeline_->SetClient(client);
 }
 
@@ -118,13 +118,13 @@
 void MediaPipelineHost::VideoInitialize(
     TrackId track_id,
     const VideoPipelineClient& client,
-    const ::media::VideoDecoderConfig& config,
+    const std::vector<::media::VideoDecoderConfig>& configs,
     const ::media::PipelineStatusCB& status_cb) {
   DCHECK(thread_checker_.CalledOnValidThread());
   CHECK(track_id == kVideoTrackId);
   media_pipeline_->GetVideoPipeline()->SetClient(client);
   media_pipeline_->InitializeVideo(
-      config, scoped_ptr<CodedFrameProvider>(), status_cb);
+      configs, scoped_ptr<CodedFrameProvider>(), status_cb);
 }
 
 void MediaPipelineHost::StartPlayingFrom(base::TimeDelta time) {
@@ -171,4 +171,3 @@
 
 }  // namespace media
 }  // namespace chromecast
-
diff --git a/chromecast/browser/media/media_pipeline_host.h b/chromecast/browser/media/media_pipeline_host.h
index dc15db9..d53ba3f 100644
--- a/chromecast/browser/media/media_pipeline_host.h
+++ b/chromecast/browser/media/media_pipeline_host.h
@@ -14,6 +14,7 @@
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "chromecast/common/media/cma_ipc_common.h"
+#include "chromecast/media/cma/backend/media_pipeline_device.h"
 #include "chromecast/media/cma/pipeline/load_type.h"
 #include "media/base/pipeline_status.h"
 
@@ -40,8 +41,10 @@
   MediaPipelineHost();
   ~MediaPipelineHost();
 
-  void Initialize(LoadType load_type,
-                  const MediaPipelineClient& client);
+  void Initialize(
+      LoadType load_type,
+      const MediaPipelineClient& client,
+      const media::CreatePipelineDeviceCB& create_pipeline_device_cb);
 
   void SetAvPipe(TrackId track_id,
                  scoped_ptr<base::SharedMemory> shared_mem,
@@ -53,7 +56,7 @@
                        const ::media::PipelineStatusCB& status_cb);
   void VideoInitialize(TrackId track_id,
                        const VideoPipelineClient& client,
-                       const ::media::VideoDecoderConfig& config,
+                       const std::vector<::media::VideoDecoderConfig>& configs,
                        const ::media::PipelineStatusCB& status_cb);
   void StartPlayingFrom(base::TimeDelta time);
   void Flush(const ::media::PipelineStatusCB& status_cb);
@@ -83,4 +86,3 @@
 }  // namespace chromecast
 
 #endif  // CHROMECAST_BROWSER_MEDIA_MEDIA_PIPELINE_HOST_H_
-
diff --git a/chromecast/chromecast.gyp b/chromecast/chromecast.gyp
index f0782ee..9519c65 100644
--- a/chromecast/chromecast.gyp
+++ b/chromecast/chromecast.gyp
@@ -51,10 +51,6 @@
         'public/video_plane.h',
       ],
     },
-    # TODO(gunsch): Remove this fake target once it's either added or no
-    # longer referenced from internal code.
-    {'target_name': 'cast_media_audio', 'type': 'none'},
-
     {
       'target_name': 'cast_base',
       'type': '<(component)',
@@ -494,6 +490,7 @@
           'dependencies': [
             '<(android_support_v13_target)',
             '../base/base.gyp:base_java',
+            '../components/components.gyp:external_video_surface_java',
             '../content/content.gyp:content_java',
             '../media/media.gyp:media_java',
             '../net/net.gyp:net_java',
diff --git a/chromecast/common/media/cma_messages.h b/chromecast/common/media/cma_messages.h
index 3fbed3db..1edb982 100644
--- a/chromecast/common/media/cma_messages.h
+++ b/chromecast/common/media/cma_messages.h
@@ -50,11 +50,12 @@
 IPC_MESSAGE_CONTROL3(CmaHostMsg_AudioInitialize,
                      int /* Media pipeline ID */,
                      chromecast::media::TrackId /* Track ID */,
-                     media::AudioDecoderConfig /* Audio config */)
+                     ::media::AudioDecoderConfig /* Audio config */)
 IPC_MESSAGE_CONTROL3(CmaHostMsg_VideoInitialize,
                      int /* Media pipeline ID */,
                      chromecast::media::TrackId /* Track ID */,
-                     media::VideoDecoderConfig /* Video config */)
+                     /* Video Config */
+                     std::vector<::media::VideoDecoderConfig>)
 IPC_MESSAGE_CONTROL3(CmaHostMsg_SetVolume,
                      int /* Media pipeline ID */,
                      chromecast::media::TrackId /* Track ID */,
@@ -112,4 +113,4 @@
 IPC_MESSAGE_CONTROL3(CmaMsg_NaturalSizeChanged,
                      int /* Media pipeline ID */,
                      chromecast::media::TrackId /* Track ID */,
-                     gfx::Size /* Size */)
\ No newline at end of file
+                     gfx::Size /* Size */)
diff --git a/chromecast/media/cma/backend/media_pipeline_device.h b/chromecast/media/cma/backend/media_pipeline_device.h
index 8a961dc7f..4b73d6c 100644
--- a/chromecast/media/cma/backend/media_pipeline_device.h
+++ b/chromecast/media/cma/backend/media_pipeline_device.h
@@ -5,6 +5,7 @@
 #ifndef CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_DEVICE_H_
 #define CHROMECAST_MEDIA_CMA_BACKEND_MEDIA_PIPELINE_DEVICE_H_
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 
@@ -32,7 +33,12 @@
   DISALLOW_COPY_AND_ASSIGN(MediaPipelineDevice);
 };
 
-// Factory to create a MediaPipelineDevice.
+// Factory method to create a MediaPipelineDevice.
+typedef base::Callback<scoped_ptr<MediaPipelineDevice>(
+    const MediaPipelineDeviceParams&)> CreatePipelineDeviceCB;
+
+// Direct creation of vendor-specific media device pipeline.
+// TODO(halliwell): move into libcast_media
 scoped_ptr<MediaPipelineDevice> CreateMediaPipelineDevice(
     const MediaPipelineDeviceParams& params);
 
diff --git a/chromecast/media/cma/base/buffering_frame_provider.cc b/chromecast/media/cma/base/buffering_frame_provider.cc
index b8d5698..7371426 100644
--- a/chromecast/media/cma/base/buffering_frame_provider.cc
+++ b/chromecast/media/cma/base/buffering_frame_provider.cc
@@ -114,7 +114,7 @@
     return;
 
   is_pending_request_ = true;
-  coded_frame_provider_->Read(BindToCurrentLoop(
+  coded_frame_provider_->Read(::media::BindToCurrentLoop(
       base::Bind(&BufferingFrameProvider::OnNewBuffer, weak_this_)));
 }
 
diff --git a/chromecast/media/cma/base/decoder_buffer_adapter.cc b/chromecast/media/cma/base/decoder_buffer_adapter.cc
index 07bc543f..ed8a779 100644
--- a/chromecast/media/cma/base/decoder_buffer_adapter.cc
+++ b/chromecast/media/cma/base/decoder_buffer_adapter.cc
@@ -31,6 +31,10 @@
   return buffer_->timestamp();
 }
 
+void DecoderBufferAdapter::set_timestamp(const base::TimeDelta& timestamp) {
+  buffer_->set_timestamp(timestamp);
+}
+
 const uint8* DecoderBufferAdapter::data() const {
   return buffer_->data();
 }
diff --git a/chromecast/media/cma/base/decoder_buffer_adapter.h b/chromecast/media/cma/base/decoder_buffer_adapter.h
index 98c1539..7c48ec8a 100644
--- a/chromecast/media/cma/base/decoder_buffer_adapter.h
+++ b/chromecast/media/cma/base/decoder_buffer_adapter.h
@@ -30,6 +30,7 @@
   // DecoderBufferBase implementation.
   StreamId stream_id() const override;
   base::TimeDelta timestamp() const override;
+  void set_timestamp(const base::TimeDelta& timestamp) override;
   const uint8* data() const override;
   uint8* writable_data() const override;
   size_t data_size() const override;
diff --git a/chromecast/media/cma/base/decoder_buffer_base.h b/chromecast/media/cma/base/decoder_buffer_base.h
index 98498eb7..1fca1b2 100644
--- a/chromecast/media/cma/base/decoder_buffer_base.h
+++ b/chromecast/media/cma/base/decoder_buffer_base.h
@@ -33,6 +33,9 @@
   // Returns the PTS of the frame.
   virtual base::TimeDelta timestamp() const = 0;
 
+  // Sets the PTS of the frame.
+  virtual void set_timestamp(const base::TimeDelta& timestamp) = 0;
+
   // Gets the frame data.
   virtual const uint8* data() const = 0;
   virtual uint8* writable_data() const = 0;
diff --git a/chromecast/media/cma/base/simple_media_task_runner.cc b/chromecast/media/cma/base/simple_media_task_runner.cc
new file mode 100644
index 0000000..c4a5439
--- /dev/null
+++ b/chromecast/media/cma/base/simple_media_task_runner.cc
@@ -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.
+
+#include "chromecast/media/cma/base/simple_media_task_runner.h"
+
+#include "base/single_thread_task_runner.h"
+
+namespace chromecast {
+namespace media {
+
+SimpleMediaTaskRunner::SimpleMediaTaskRunner(
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
+    : task_runner_(task_runner) {
+}
+
+SimpleMediaTaskRunner::~SimpleMediaTaskRunner() {
+}
+
+bool SimpleMediaTaskRunner::PostMediaTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    base::TimeDelta timestamp) {
+  return task_runner_->PostTask(from_here, task);
+}
+
+}  // namespace media
+}  // namespace chromecast
diff --git a/chromecast/media/cma/base/simple_media_task_runner.h b/chromecast/media/cma/base/simple_media_task_runner.h
new file mode 100644
index 0000000..67979f70
--- /dev/null
+++ b/chromecast/media/cma/base/simple_media_task_runner.h
@@ -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.
+
+#ifndef CHROMECAST_MEDIA_CMA_BASE_SIMPLE_MEDIA_TASK_RUNNER_H_
+#define CHROMECAST_MEDIA_CMA_BASE_SIMPLE_MEDIA_TASK_RUNNER_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "chromecast/media/cma/base/media_task_runner.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}  // namespace base
+
+namespace chromecast {
+namespace media {
+
+// This is a light version of task runner which post tasks immediately
+// by ignoring the timestamps once receiving the request.
+class SimpleMediaTaskRunner : public MediaTaskRunner {
+ public:
+  SimpleMediaTaskRunner(
+      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+
+  // MediaTaskRunner implementation.
+  bool PostMediaTask(const tracked_objects::Location& from_here,
+                     const base::Closure& task,
+                     base::TimeDelta timestamp) override;
+
+ private:
+  ~SimpleMediaTaskRunner() override;
+
+  scoped_refptr<base::SingleThreadTaskRunner> const task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(SimpleMediaTaskRunner);
+};
+
+}  // namespace media
+}  // namespace chromecast
+
+#endif  // CHROMECAST_MEDIA_CMA_BASE_SIMPLE_MEDIA_TASK_RUNNER_H_
diff --git a/chromecast/media/cma/filters/cma_renderer.cc b/chromecast/media/cma/filters/cma_renderer.cc
index 1573a8cb..9d0a5ba 100644
--- a/chromecast/media/cma/filters/cma_renderer.cc
+++ b/chromecast/media/cma/filters/cma_renderer.cc
@@ -233,12 +233,12 @@
   DCHECK_EQ(state_, kUninitialized) << state_;
   DCHECK(!init_cb_.is_null());
 
-  ::media::PipelineStatusCB audio_initialization_done_cb =
-      ::media::BindToCurrentLoop(
-          base::Bind(&CmaRenderer::OnAudioPipelineInitializeDone, weak_this_));
-
   ::media::DemuxerStream* stream =
       demuxer_stream_provider_->GetStream(::media::DemuxerStream::AUDIO);
+  ::media::PipelineStatusCB audio_initialization_done_cb =
+      ::media::BindToCurrentLoop(
+          base::Bind(&CmaRenderer::OnAudioPipelineInitializeDone, weak_this_,
+                     stream != nullptr));
   if (!stream) {
     audio_initialization_done_cb.Run(::media::PIPELINE_OK);
     return;
@@ -266,6 +266,7 @@
 }
 
 void CmaRenderer::OnAudioPipelineInitializeDone(
+    bool audio_stream_present,
     ::media::PipelineStatus status) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
@@ -279,8 +280,8 @@
     base::ResetAndReturn(&init_cb_).Run(status);
     return;
   }
-  has_audio_ = true;
 
+  has_audio_ = audio_stream_present;
   InitializeVideoPipeline();
 }
 
@@ -289,12 +290,12 @@
   DCHECK_EQ(state_, kUninitialized) << state_;
   DCHECK(!init_cb_.is_null());
 
-  ::media::PipelineStatusCB video_initialization_done_cb =
-      ::media::BindToCurrentLoop(
-          base::Bind(&CmaRenderer::OnVideoPipelineInitializeDone, weak_this_));
-
   ::media::DemuxerStream* stream =
       demuxer_stream_provider_->GetStream(::media::DemuxerStream::VIDEO);
+  ::media::PipelineStatusCB video_initialization_done_cb =
+      ::media::BindToCurrentLoop(
+          base::Bind(&CmaRenderer::OnVideoPipelineInitializeDone, weak_this_,
+                     stream != nullptr));
   if (!stream) {
     video_initialization_done_cb.Run(::media::PIPELINE_OK);
     return;
@@ -321,13 +322,16 @@
 
   initial_natural_size_ = config.natural_size();
 
+  std::vector<::media::VideoDecoderConfig> configs;
+  configs.push_back(config);
   media_pipeline_->InitializeVideo(
-      config,
+      configs,
       frame_provider.Pass(),
       video_initialization_done_cb);
 }
 
 void CmaRenderer::OnVideoPipelineInitializeDone(
+    bool video_stream_present,
     ::media::PipelineStatus status) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
@@ -341,17 +345,16 @@
     base::ResetAndReturn(&init_cb_).Run(status);
     return;
   }
-  has_video_ = true;
 
+  has_video_ = video_stream_present;
   CompleteStateTransition(kFlushed);
   base::ResetAndReturn(&init_cb_).Run(::media::PIPELINE_OK);
 }
 
 void CmaRenderer::OnEosReached(bool is_audio) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  CMALOG(kLogControl) << __FUNCTION__;
   if (state_ != kPlaying) {
-    LOG(WARNING) << "Ignoring a late EOS event";
+    LOG(WARNING) << __FUNCTION__ << " Ignoring a late EOS event";
     return;
   }
 
@@ -365,6 +368,9 @@
 
   bool audio_finished = !has_audio_ || received_audio_eos_;
   bool video_finished = !has_video_ || received_video_eos_;
+  CMALOG(kLogControl) << __FUNCTION__
+                      << " audio_finished=" << audio_finished
+                      << " video_finished=" << video_finished;
   if (audio_finished && video_finished)
     ended_cb_.Run();
 }
diff --git a/chromecast/media/cma/filters/cma_renderer.h b/chromecast/media/cma/filters/cma_renderer.h
index dbe5334c..eb4c600 100644
--- a/chromecast/media/cma/filters/cma_renderer.h
+++ b/chromecast/media/cma/filters/cma_renderer.h
@@ -70,9 +70,11 @@
   // the order below, with a successful initialization making it to
   // OnVideoPipelineInitializeDone, regardless of which streams are present.
   void InitializeAudioPipeline();
-  void OnAudioPipelineInitializeDone(::media::PipelineStatus status);
+  void OnAudioPipelineInitializeDone(bool audio_stream_present,
+                                     ::media::PipelineStatus status);
   void InitializeVideoPipeline();
-  void OnVideoPipelineInitializeDone(::media::PipelineStatus status);
+  void OnVideoPipelineInitializeDone(bool video_stream_present,
+                                     ::media::PipelineStatus status);
 
   // Callbacks for AvPipelineClient.
   void OnEosReached(bool is_audio);
diff --git a/chromecast/media/cma/filters/demuxer_stream_adapter.cc b/chromecast/media/cma/filters/demuxer_stream_adapter.cc
index c2fd5a4..4072523 100644
--- a/chromecast/media/cma/filters/demuxer_stream_adapter.cc
+++ b/chromecast/media/cma/filters/demuxer_stream_adapter.cc
@@ -10,7 +10,7 @@
 #include "chromecast/media/cma/base/balanced_media_task_runner_factory.h"
 #include "chromecast/media/cma/base/cma_logging.h"
 #include "chromecast/media/cma/base/decoder_buffer_adapter.h"
-#include "chromecast/media/cma/base/media_task_runner.h"
+#include "chromecast/media/cma/base/simple_media_task_runner.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/buffers.h"
 #include "media/base/decoder_buffer.h"
@@ -19,52 +19,14 @@
 namespace chromecast {
 namespace media {
 
-namespace {
-
-class DummyMediaTaskRunner : public MediaTaskRunner {
- public:
-  DummyMediaTaskRunner(
-      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
-
-  // MediaTaskRunner implementation.
-  bool PostMediaTask(
-      const tracked_objects::Location& from_here,
-      const base::Closure& task,
-      base::TimeDelta timestamp) override;
-
- private:
-  ~DummyMediaTaskRunner() override;
-
-  scoped_refptr<base::SingleThreadTaskRunner> const task_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(DummyMediaTaskRunner);
-};
-
-DummyMediaTaskRunner::DummyMediaTaskRunner(
-    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
-  : task_runner_(task_runner) {
-}
-
-DummyMediaTaskRunner::~DummyMediaTaskRunner() {
-}
-
-bool DummyMediaTaskRunner::PostMediaTask(
-    const tracked_objects::Location& from_here,
-    const base::Closure& task,
-    base::TimeDelta timestamp) {
-  return task_runner_->PostTask(from_here, task);
-}
-
-}  // namespace
-
 DemuxerStreamAdapter::DemuxerStreamAdapter(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     const scoped_refptr<BalancedMediaTaskRunnerFactory>&
-    media_task_runner_factory,
+        media_task_runner_factory,
     ::media::DemuxerStream* demuxer_stream)
     : task_runner_(task_runner),
       media_task_runner_factory_(media_task_runner_factory),
-      media_task_runner_(new DummyMediaTaskRunner(task_runner)),
+      media_task_runner_(new SimpleMediaTaskRunner(task_runner)),
       demuxer_stream_(demuxer_stream),
       is_pending_read_(false),
       is_pending_demuxer_read_(false),
@@ -152,7 +114,7 @@
 void DemuxerStreamAdapter::OnNewBuffer(
     const ReadCB& read_cb,
     ::media::DemuxerStream::Status status,
-    const scoped_refptr< ::media::DecoderBuffer>& input) {
+    const scoped_refptr<::media::DecoderBuffer>& input) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   is_pending_demuxer_read_ = false;
diff --git a/chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc b/chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc
index dec1ee78..5242c40 100644
--- a/chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc
+++ b/chromecast/media/cma/filters/demuxer_stream_adapter_unittest.cc
@@ -93,7 +93,7 @@
     config_idx_.pop_front();
     has_pending_read_ = false;
     read_cb.Run(kConfigChanged,
-                scoped_refptr< ::media::DecoderBuffer>());
+                scoped_refptr<::media::DecoderBuffer>());
     return;
   }
 
@@ -141,7 +141,7 @@
 
 void DummyDemuxerStream::DoRead(const ReadCB& read_cb) {
   has_pending_read_ = false;
-  scoped_refptr< ::media::DecoderBuffer> buffer(
+  scoped_refptr<::media::DecoderBuffer> buffer(
       new ::media::DecoderBuffer(16));
   buffer->set_timestamp(frame_count_ * base::TimeDelta::FromMilliseconds(40));
   frame_count_++;
diff --git a/chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.cc b/chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.cc
index 93421a5..ab3a2587 100644
--- a/chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.cc
+++ b/chromecast/media/cma/ipc_streamer/decoder_buffer_base_marshaller.cc
@@ -26,6 +26,7 @@
   // DecoderBufferBase implementation.
   StreamId stream_id() const override;
   base::TimeDelta timestamp() const override;
+  void set_timestamp(const base::TimeDelta& timestamp) override;
   const uint8* data() const override;
   uint8* writable_data() const override;
   size_t data_size() const override;
@@ -114,6 +115,10 @@
   return pts_;
 }
 
+void DecoderBufferFromMsg::set_timestamp(const base::TimeDelta& timestamp) {
+  pts_ = timestamp;
+}
+
 const uint8* DecoderBufferFromMsg::data() const {
   CHECK(msg_->IsSerializedMsgAvailable());
   return data_;
diff --git a/chromecast/media/cma/pipeline/audio_pipeline_impl.cc b/chromecast/media/cma/pipeline/audio_pipeline_impl.cc
index 82b56e2..006ea820 100644
--- a/chromecast/media/cma/pipeline/audio_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/audio_pipeline_impl.cc
@@ -109,6 +109,7 @@
   if (frame_provider)
     SetCodedFrameProvider(frame_provider.Pass());
 
+  DCHECK(audio_config.IsValidConfig());
   if (!audio_device_->SetConfig(
          DecoderConfigAdapter::ToCastAudioConfig(kPrimary, audio_config)) ||
       !av_pipeline_impl_->Initialize()) {
diff --git a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
index a10d24a..ba8109f 100644
--- a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
+++ b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
@@ -91,14 +91,15 @@
       ::media::CHANNEL_LAYOUT_STEREO,
       44100,
       NULL, 0, false);
-  ::media::VideoDecoderConfig video_config(
+  std::vector<::media::VideoDecoderConfig> video_configs;
+  video_configs.push_back(::media::VideoDecoderConfig(
       ::media::kCodecH264,
       ::media::H264PROFILE_MAIN,
       ::media::VideoFrame::I420,
       gfx::Size(640, 480),
       gfx::Rect(0, 0, 640, 480),
       gfx::Size(640, 480),
-      NULL, 0, false);
+      NULL, 0, false));
 
   // Frame generation on the producer side.
   std::vector<FrameGeneratorForTest::FrameSpec> frame_specs;
@@ -135,7 +136,7 @@
                  next_task) :
       base::Bind(&MediaPipeline::InitializeVideo,
                  base::Unretained(media_pipeline_.get()),
-                 video_config,
+                 video_configs,
                  base::Passed(&frame_provider_base),
                  next_task);
 
diff --git a/chromecast/media/cma/pipeline/decrypt_util.cc b/chromecast/media/cma/pipeline/decrypt_util.cc
index 0010380..abd4661 100644
--- a/chromecast/media/cma/pipeline/decrypt_util.cc
+++ b/chromecast/media/cma/pipeline/decrypt_util.cc
@@ -24,6 +24,7 @@
   // DecoderBufferBase implementation.
   StreamId stream_id() const override;
   base::TimeDelta timestamp() const override;
+  void set_timestamp(const base::TimeDelta& timestamp) override;
   const uint8* data() const override;
   uint8* writable_data() const override;
   size_t data_size() const override;
@@ -54,6 +55,10 @@
   return buffer_->timestamp();
 }
 
+void DecoderBufferClear::set_timestamp(const base::TimeDelta& timestamp) {
+  buffer_->set_timestamp(timestamp);
+}
+
 const uint8* DecoderBufferClear::data() const {
   return buffer_->data();
 }
diff --git a/chromecast/media/cma/pipeline/media_pipeline.h b/chromecast/media/cma/pipeline/media_pipeline.h
index 6b127cb2..6026cdc 100644
--- a/chromecast/media/cma/pipeline/media_pipeline.h
+++ b/chromecast/media/cma/pipeline/media_pipeline.h
@@ -47,7 +47,7 @@
       scoped_ptr<CodedFrameProvider> frame_provider,
       const ::media::PipelineStatusCB& status_cb) = 0;
   virtual void InitializeVideo(
-      const ::media::VideoDecoderConfig& config,
+      const std::vector<::media::VideoDecoderConfig>& configs,
       scoped_ptr<CodedFrameProvider> frame_provider,
       const ::media::PipelineStatusCB& status_cb) = 0;
 
diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.cc b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
index 29140cb..fd20ea6 100644
--- a/chromecast/media/cma/pipeline/media_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
@@ -144,7 +144,7 @@
 }
 
 void MediaPipelineImpl::InitializeVideo(
-    const ::media::VideoDecoderConfig& config,
+    const std::vector<::media::VideoDecoderConfig>& configs,
     scoped_ptr<CodedFrameProvider> frame_provider,
     const ::media::PipelineStatusCB& status_cb) {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -155,7 +155,7 @@
     return;
   }
   has_video_ = true;
-  video_pipeline_->Initialize(config, frame_provider.Pass(), status_cb);
+  video_pipeline_->Initialize(configs, frame_provider.Pass(), status_cb);
 }
 
 void MediaPipelineImpl::StartPlayingFrom(base::TimeDelta time) {
diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.h b/chromecast/media/cma/pipeline/media_pipeline_impl.h
index eb14a555b..794437a 100644
--- a/chromecast/media/cma/pipeline/media_pipeline_impl.h
+++ b/chromecast/media/cma/pipeline/media_pipeline_impl.h
@@ -45,7 +45,7 @@
       scoped_ptr<CodedFrameProvider> frame_provider,
       const ::media::PipelineStatusCB& status_cb) override;
   void InitializeVideo(
-      const ::media::VideoDecoderConfig& config,
+      const std::vector<::media::VideoDecoderConfig>& configs,
       scoped_ptr<CodedFrameProvider> frame_provider,
       const ::media::PipelineStatusCB& status_cb) override;
   void StartPlayingFrom(base::TimeDelta time) override;
@@ -83,7 +83,7 @@
   bool has_video_;
   scoped_ptr<AudioPipelineImpl> audio_pipeline_;
   scoped_ptr<VideoPipelineImpl> video_pipeline_;
-  scoped_ptr< ::media::SerialRunner> pending_callbacks_;
+  scoped_ptr<::media::SerialRunner> pending_callbacks_;
 
   // Playback rate set by the upper layer.
   float target_playback_rate_;
diff --git a/chromecast/media/cma/pipeline/video_pipeline_impl.cc b/chromecast/media/cma/pipeline/video_pipeline_impl.cc
index c1328af..38335318 100644
--- a/chromecast/media/cma/pipeline/video_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/video_pipeline_impl.cc
@@ -101,11 +101,10 @@
 }
 
 void VideoPipelineImpl::Initialize(
-    const ::media::VideoDecoderConfig& video_config,
+    const std::vector<::media::VideoDecoderConfig>& configs,
     scoped_ptr<CodedFrameProvider> frame_provider,
     const ::media::PipelineStatusCB& status_cb) {
-  CMALOG(kLogControl) << "VideoPipelineImpl::Initialize "
-                      << video_config.AsHumanReadableString();
+  CMALOG(kLogControl) << __FUNCTION__ << " config (" << configs.size() << ")";
   VideoPipelineDevice::VideoClient client;
   client.natural_size_changed_cb =
       base::Bind(&VideoPipelineImpl::OnNaturalSizeChanged, weak_this_);
@@ -113,8 +112,23 @@
   if (frame_provider)
     SetCodedFrameProvider(frame_provider.Pass());
 
-  if (!video_device_->SetConfig(
-          DecoderConfigAdapter::ToCastVideoConfig(kPrimary, video_config)) ||
+  if (configs.empty()) {
+     status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
+     return;
+  }
+  DCHECK(configs.size() <= 2);
+  DCHECK(configs[0].IsValidConfig());
+  VideoConfig video_config =
+      DecoderConfigAdapter::ToCastVideoConfig(kPrimary, configs[0]);
+  VideoConfig secondary_config;
+  if (configs.size() == 2) {
+    DCHECK(configs[1].IsValidConfig());
+    secondary_config = DecoderConfigAdapter::ToCastVideoConfig(kSecondary,
+                                                               configs[1]);
+    video_config.additional_config = &secondary_config;
+  }
+
+  if (!video_device_->SetConfig(video_config) ||
       !av_pipeline_impl_->Initialize()) {
     status_cb.Run(::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
     return;
diff --git a/chromecast/media/cma/pipeline/video_pipeline_impl.h b/chromecast/media/cma/pipeline/video_pipeline_impl.h
index 3683e8d3..25f875f 100644
--- a/chromecast/media/cma/pipeline/video_pipeline_impl.h
+++ b/chromecast/media/cma/pipeline/video_pipeline_impl.h
@@ -44,7 +44,7 @@
 
   // Functions to control the state of the audio pipeline.
   void Initialize(
-      const ::media::VideoDecoderConfig& config,
+      const std::vector<::media::VideoDecoderConfig>& configs,
       scoped_ptr<CodedFrameProvider> frame_provider,
       const ::media::PipelineStatusCB& status_cb);
   bool StartPlayingFrom(base::TimeDelta time,
diff --git a/chromecast/media/empty.cc b/chromecast/media/empty.cc
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chromecast/media/empty.cc
diff --git a/chromecast/media/media.gyp b/chromecast/media/media.gyp
index f7bdcf0..348ca37 100644
--- a/chromecast/media/media.gyp
+++ b/chromecast/media/media.gyp
@@ -10,6 +10,13 @@
     'use_default_libcast_media%': 1,
   },
   'targets': [
+    # TODO(gunsch): delete this target once Chromecast M44/earlier is obsolete.
+    # See: b/21639416
+    {
+      'target_name': 'libffmpegsumo',
+      'type': 'loadable_module',
+      'sources': ['empty.cc'],
+    },
     {
       'target_name': 'media_base',
       'type': '<(component)',
@@ -101,6 +108,8 @@
         'cma/base/decoder_config_adapter.h',
         'cma/base/media_task_runner.cc',
         'cma/base/media_task_runner.h',
+        'cma/base/simple_media_task_runner.cc',
+        'cma/base/simple_media_task_runner.h',         
       ],
     },
     {
diff --git a/chromecast/net/connectivity_checker.h b/chromecast/net/connectivity_checker.h
index 6225962..fcfb878 100644
--- a/chromecast/net/connectivity_checker.h
+++ b/chromecast/net/connectivity_checker.h
@@ -57,7 +57,7 @@
  private:
   friend class base::RefCountedThreadSafe<ConnectivityChecker>;
 
-  const scoped_refptr<ObserverListThreadSafe<ConnectivityObserver>>
+  const scoped_refptr<base::ObserverListThreadSafe<ConnectivityObserver>>
       connectivity_observer_list_;
 
   DISALLOW_COPY_AND_ASSIGN(ConnectivityChecker);
diff --git a/chromecast/net/connectivity_checker_impl.cc b/chromecast/net/connectivity_checker_impl.cc
index 3ca50c1..d10d06a1 100644
--- a/chromecast/net/connectivity_checker_impl.cc
+++ b/chromecast/net/connectivity_checker_impl.cc
@@ -58,16 +58,14 @@
   builder.DisableHttpCache();
   url_request_context_.reset(builder.Build());
 
-  net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
-  net::NetworkChangeNotifier::AddIPAddressObserver(this);
+  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
   task_runner_->PostTask(FROM_HERE,
                          base::Bind(&ConnectivityCheckerImpl::Check, this));
 }
 
 ConnectivityCheckerImpl::~ConnectivityCheckerImpl() {
   DCHECK(task_runner_.get());
-  net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
-  net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
+  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
   task_runner_->DeleteSoon(FROM_HERE, url_request_.release());
   task_runner_->DeleteSoon(FROM_HERE, url_request_context_.release());
 }
@@ -110,20 +108,16 @@
   url_request_->Start();
 }
 
-void ConnectivityCheckerImpl::OnConnectionTypeChanged(
+void ConnectivityCheckerImpl::OnNetworkChanged(
     net::NetworkChangeNotifier::ConnectionType type) {
-  VLOG(2) << "OnConnectionTypeChanged " << type;
-  if (type == net::NetworkChangeNotifier::CONNECTION_NONE)
+  VLOG(2) << "OnNetworkChanged " << type;
+  Cancel();
+
+  if (type == net::NetworkChangeNotifier::CONNECTION_NONE) {
     SetConnected(false);
+    return;
+  }
 
-  Cancel();
-  Check();
-}
-
-void ConnectivityCheckerImpl::OnIPAddressChanged() {
-  VLOG(2) << "OnIPAddressChanged";
-
-  Cancel();
   Check();
 }
 
diff --git a/chromecast/net/connectivity_checker_impl.h b/chromecast/net/connectivity_checker_impl.h
index 8bf4494..f356234 100644
--- a/chromecast/net/connectivity_checker_impl.h
+++ b/chromecast/net/connectivity_checker_impl.h
@@ -28,8 +28,7 @@
 class ConnectivityCheckerImpl
     : public ConnectivityChecker,
       public net::URLRequest::Delegate,
-      public net::NetworkChangeNotifier::ConnectionTypeObserver,
-      public net::NetworkChangeNotifier::IPAddressObserver {
+      public net::NetworkChangeNotifier::NetworkChangeObserver {
  public:
   explicit ConnectivityCheckerImpl(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
@@ -52,13 +51,10 @@
   // Initializes ConnectivityChecker
   void Initialize();
 
-  // NetworkChangeNotifier::ConnectionTypeObserver implementation:
-  void OnConnectionTypeChanged(
+  // net::NetworkChangeNotifier::NetworkChangeObserver implementation:
+  void OnNetworkChanged(
       net::NetworkChangeNotifier::ConnectionType type) override;
 
-  // net::NetworkChangeNotifier::IPAddressObserver implementation:
-  void OnIPAddressChanged() override;
-
   // Cancels current connectivity checking in progress.
   void Cancel();
 
diff --git a/chromecast/renderer/cast_content_renderer_client.h b/chromecast/renderer/cast_content_renderer_client.h
index efdc3a5..f8539f61 100644
--- a/chromecast/renderer/cast_content_renderer_client.h
+++ b/chromecast/renderer/cast_content_renderer_client.h
@@ -27,7 +27,10 @@
 
 class CastContentRendererClient : public content::ContentRendererClient {
  public:
-  CastContentRendererClient();
+  // Creates an implementation of CastContentRendererClient. Platform should
+  // link in an implementation as needed.
+  static scoped_ptr<CastContentRendererClient> Create();
+
   ~CastContentRendererClient() override;
 
   // Returns any MessageFilters from the platform implementation that should
@@ -41,14 +44,17 @@
   void AddKeySystems(
       std::vector< ::media::KeySystemInfo>* key_systems) override;
 #if !defined(OS_ANDROID)
-  scoped_ptr<media::RendererFactory> CreateMediaRendererFactory(
+  scoped_ptr<::media::RendererFactory> CreateMediaRendererFactory(
       content::RenderFrame* render_frame,
-      const scoped_refptr<media::MediaLog>& media_log) override;
+      const scoped_refptr<::media::MediaLog>& media_log) override;
 #endif
   blink::WebPrescientNetworking* GetPrescientNetworking() override;
   void DeferMediaLoad(content::RenderFrame* render_frame,
                       const base::Closure& closure) override;
 
+ protected:
+  CastContentRendererClient();
+
  private:
   scoped_ptr<network_hints::PrescientNetworkingDispatcher>
       prescient_networking_dispatcher_;
diff --git a/chromecast/renderer/cast_content_renderer_client_simple.cc b/chromecast/renderer/cast_content_renderer_client_simple.cc
index 5ad4fccb..f1d4cf2c 100644
--- a/chromecast/renderer/cast_content_renderer_client_simple.cc
+++ b/chromecast/renderer/cast_content_renderer_client_simple.cc
@@ -4,11 +4,17 @@
 
 #include "chromecast/renderer/cast_content_renderer_client.h"
 
+#include "base/memory/scoped_ptr.h"
 #include "ipc/message_filter.h"
 
 namespace chromecast {
 namespace shell {
 
+// static
+scoped_ptr<CastContentRendererClient> CastContentRendererClient::Create() {
+  return make_scoped_ptr(new CastContentRendererClient());
+}
+
 void PlatformAddRendererNativeBindings(blink::WebLocalFrame* frame) {
 }
 
diff --git a/chromecast/renderer/media/media_pipeline_proxy.cc b/chromecast/renderer/media/media_pipeline_proxy.cc
index 5168f49..559f2e07 100644
--- a/chromecast/renderer/media/media_pipeline_proxy.cc
+++ b/chromecast/renderer/media/media_pipeline_proxy.cc
@@ -214,12 +214,12 @@
 }
 
 void MediaPipelineProxy::InitializeVideo(
-    const ::media::VideoDecoderConfig& config,
+    const std::vector<::media::VideoDecoderConfig>& configs,
     scoped_ptr<CodedFrameProvider> frame_provider,
     const ::media::PipelineStatusCB& status_cb) {
   DCHECK(thread_checker_.CalledOnValidThread());
   has_video_ = true;
-  video_pipeline_->Initialize(config, frame_provider.Pass(), status_cb);
+  video_pipeline_->Initialize(configs, frame_provider.Pass(), status_cb);
 }
 
 void MediaPipelineProxy::StartPlayingFrom(base::TimeDelta time) {
diff --git a/chromecast/renderer/media/media_pipeline_proxy.h b/chromecast/renderer/media/media_pipeline_proxy.h
index de3a638b..a39ef1c 100644
--- a/chromecast/renderer/media/media_pipeline_proxy.h
+++ b/chromecast/renderer/media/media_pipeline_proxy.h
@@ -43,7 +43,7 @@
       scoped_ptr<CodedFrameProvider> frame_provider,
       const ::media::PipelineStatusCB& status_cb) override;
   void InitializeVideo(
-      const ::media::VideoDecoderConfig& config,
+      const std::vector<::media::VideoDecoderConfig>& configs,
       scoped_ptr<CodedFrameProvider> frame_provider,
       const ::media::PipelineStatusCB& status_cb) override;
   void StartPlayingFrom(base::TimeDelta time) override;
@@ -70,7 +70,7 @@
   bool has_video_;
   scoped_ptr<AudioPipelineProxy> audio_pipeline_;
   scoped_ptr<VideoPipelineProxy> video_pipeline_;
-  scoped_ptr< ::media::SerialRunner> pending_callbacks_;
+  scoped_ptr<::media::SerialRunner> pending_callbacks_;
 
   base::WeakPtr<MediaPipelineProxy> weak_this_;
   base::WeakPtrFactory<MediaPipelineProxy> weak_factory_;
diff --git a/chromecast/renderer/media/video_pipeline_proxy.cc b/chromecast/renderer/media/video_pipeline_proxy.cc
index 40d4fd63..bcef083 100644
--- a/chromecast/renderer/media/video_pipeline_proxy.cc
+++ b/chromecast/renderer/media/video_pipeline_proxy.cc
@@ -56,7 +56,7 @@
   void SetClient(const base::Closure& pipe_read_cb,
                  const VideoPipelineClient& client);
   void CreateAvPipe(const SharedMemCB& shared_mem_cb);
-  void Initialize(const ::media::VideoDecoderConfig& config,
+  void Initialize(const std::vector<::media::VideoDecoderConfig>& configs,
                   const ::media::PipelineStatusCB& status_cb);
 
  private:
@@ -166,12 +166,12 @@
 }
 
 void VideoPipelineProxyInternal::Initialize(
-    const ::media::VideoDecoderConfig& arg1,
+    const std::vector<::media::VideoDecoderConfig>& configs,
     const ::media::PipelineStatusCB& status_cb) {
   DCHECK(thread_checker_.CalledOnValidThread());
   bool success = media_channel_proxy_->Send(scoped_ptr<IPC::Message>(
       new CmaHostMsg_VideoInitialize(media_channel_proxy_->GetId(),
-                                     kVideoTrackId, arg1)));
+                                     kVideoTrackId, configs)));
   if (!success) {
     status_cb.Run( ::media::PIPELINE_ERROR_INITIALIZATION_FAILED);
     return;
@@ -223,7 +223,7 @@
 }
 
 void VideoPipelineProxy::Initialize(
-    const ::media::VideoDecoderConfig& config,
+    const std::vector<::media::VideoDecoderConfig>& configs,
     scoped_ptr<CodedFrameProvider> frame_provider,
     const ::media::PipelineStatusCB& status_cb) {
   CMALOG(kLogControl) << "VideoPipelineProxy::Initialize";
@@ -233,12 +233,12 @@
   VideoPipelineProxyInternal::SharedMemCB shared_mem_cb =
       ::media::BindToCurrentLoop(base::Bind(
           &VideoPipelineProxy::OnAvPipeCreated, weak_this_,
-          config, status_cb));
+          configs, status_cb));
   FORWARD_ON_IO_THREAD(CreateAvPipe, shared_mem_cb);
 }
 
 void VideoPipelineProxy::OnAvPipeCreated(
-    const ::media::VideoDecoderConfig& config,
+    const std::vector<::media::VideoDecoderConfig>& configs,
     const ::media::PipelineStatusCB& status_cb,
     scoped_ptr<base::SharedMemory> shared_memory) {
   CMALOG(kLogControl) << "VideoPipelineProxy::OnAvPipeCreated";
@@ -260,7 +260,7 @@
   video_streamer_->SetMediaMessageFifo(video_pipe.Pass());
 
   // Now proceed to the decoder/renderer initialization.
-  FORWARD_ON_IO_THREAD(Initialize, config, status_cb);
+  FORWARD_ON_IO_THREAD(Initialize, configs, status_cb);
 }
 
 void VideoPipelineProxy::StartFeeding() {
diff --git a/chromecast/renderer/media/video_pipeline_proxy.h b/chromecast/renderer/media/video_pipeline_proxy.h
index b15e3c6..1dbf13ec 100644
--- a/chromecast/renderer/media/video_pipeline_proxy.h
+++ b/chromecast/renderer/media/video_pipeline_proxy.h
@@ -36,7 +36,7 @@
                      scoped_refptr<MediaChannelProxy> media_channel_proxy);
   ~VideoPipelineProxy() override;
 
-  void Initialize(const ::media::VideoDecoderConfig& config,
+  void Initialize(const std::vector<::media::VideoDecoderConfig>& configs,
                   scoped_ptr<CodedFrameProvider> frame_provider,
                   const ::media::PipelineStatusCB& status_cb);
   void StartFeeding();
@@ -50,7 +50,7 @@
   base::ThreadChecker thread_checker_;
 
   void OnAvPipeCreated(
-      const ::media::VideoDecoderConfig& config,
+      const std::vector<::media::VideoDecoderConfig>& configs,
       const ::media::PipelineStatusCB& status_cb,
       scoped_ptr<base::SharedMemory> shared_memory);
   void OnPipeWrite();
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index b52c5d3..0d14601 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-7134.0.0
\ No newline at end of file
+7142.0.0
\ No newline at end of file
diff --git a/cloud_print/virtual_driver/win/port_monitor/port_monitor.cc b/cloud_print/virtual_driver/win/port_monitor/port_monitor.cc
index 3e7b5ba..a04ac04c 100644
--- a/cloud_print/virtual_driver/win/port_monitor/port_monitor.cc
+++ b/cloud_print/virtual_driver/win/port_monitor/port_monitor.cc
@@ -21,6 +21,7 @@
 #include "base/process/launch.h"
 #include "base/process/process.h"
 #include "base/strings/string16.h"
+#include "base/strings/string_util.h"
 #include "base/win/registry.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/windows_version.h"
@@ -46,6 +47,12 @@
 
 const wchar_t kAppDataDir[] = L"Google\\Cloud Printer";
 
+const wchar_t kDocumentPathPlaceHolder[] = L"%%Document_Path%%";
+
+const wchar_t kDocumentTypePlaceHolder[] = L"%%Document_Type%%";
+
+const wchar_t kJobTitlePlaceHolder[] = L"%%Job_Title%%";
+
 struct MonitorData {
   scoped_ptr<base::AtExitManager> at_exit_manager;
 };
@@ -200,39 +207,82 @@
   return true;
 }
 
-// Launches the Cloud Print dialog in Chrome.
-// xps_path references a file to print.
-// job_title is the title to be used for the resulting print job.
-bool LaunchPrintDialog(const base::FilePath& xps_path,
-                       const base::string16& job_title) {
+bool LaunchCommandAsUser(const base::CommandLine& command) {
   HANDLE token = NULL;
   if (!GetUserToken(&token)) {
     LOG(ERROR) << "Unable to get user token.";
     return false;
   }
   base::win::ScopedHandle primary_token_scoped(token);
-
-  base::FilePath chrome_path = GetChromeExePath();
-  if (chrome_path.empty()) {
-    LOG(ERROR) << "Unable to get chrome exe path.";
-    return false;
-  }
-
-  base::CommandLine command_line(chrome_path);
-
-  base::FilePath chrome_profile = GetChromeProfilePath();
-  if (!chrome_profile.empty())
-    command_line.AppendSwitchPath(switches::kUserDataDir, chrome_profile);
-
-  command_line.AppendSwitchPath(switches::kCloudPrintFile, xps_path);
-  command_line.AppendSwitchNative(switches::kCloudPrintFileType, kXpsMimeType);
-  command_line.AppendSwitchNative(switches::kCloudPrintJobTitle, job_title);
   base::LaunchOptions options;
   options.as_user = primary_token_scoped.Get();
-  base::LaunchProcess(command_line, options);
+  base::LaunchProcess(command, options);
   return true;
 }
 
+// Escape the command line argument as necessary per Microsoft rules.
+// See QuoteForCommandLineToArgvW in base/command_line.cc
+base::string16 EscapeCommandLineArg(const base::string16& arg) {
+  base::string16 quotable_chars(L" \\\"");
+  if (arg.find_first_of(quotable_chars) == base::string16::npos) {
+    // No quoting necessary.
+    return arg;
+  }
+
+  base::string16 out;
+  out.push_back(L'"');
+  for (size_t i = 0; i < arg.size(); ++i) {
+    if (arg[i] == '\\') {
+      // Find the extent of this run of backslashes.
+      size_t start = i, end = start + 1;
+      for (; end < arg.size() && arg[end] == '\\'; ++end) {}
+      size_t backslash_count = end - start;
+
+      // Backslashes are escapes only if the run is followed by a double quote.
+      // Since we also will end the string with a double quote, we escape for
+      // either a double quote or the end of the string.
+      if (end == arg.size() || arg[end] == '"') {
+        // To quote, we need to output 2x as many backslashes.
+        backslash_count *= 2;
+      }
+      for (size_t j = 0; j < backslash_count; ++j)
+        out.push_back('\\');
+
+      // Advance i to one before the end to balance i++ in loop.
+      i = end - 1;
+    } else if (arg[i] == '"') {
+      out.push_back('\\');
+      out.push_back('"');
+    } else {
+      out.push_back(arg[i]);
+    }
+  }
+  out.push_back('"');
+
+  return out;
+}
+
+// Launch the print command as specified in the cloud print registry.
+bool LaunchPrintCommandFromTemplate(const base::string16& command_template,
+                                    const base::FilePath& xps_path,
+                                    const base::string16& job_title) {
+  base::string16 command_string(command_template);
+  // Substitude the place holder with the document path wrapped in quotes.
+  ReplaceFirstSubstringAfterOffset(
+      &command_string, 0, kDocumentPathPlaceHolder,
+      EscapeCommandLineArg(xps_path.value()));
+  // Substitude the place holder with the document type wrapped in quotes.
+  ReplaceFirstSubstringAfterOffset(&command_string, 0, kDocumentTypePlaceHolder,
+                                   kXpsMimeType);
+  // Substitude the place holder with the job title wrapped in quotes.
+  ReplaceFirstSubstringAfterOffset(&command_string, 0, kJobTitlePlaceHolder,
+                                   EscapeCommandLineArg(job_title));
+
+  base::CommandLine command = base::CommandLine::FromString(command_string);
+
+  return LaunchCommandAsUser(command);
+}
+
 // Launches a page to allow the user to download chrome.
 // TODO(abodenha@chromium.org) Point to a custom page explaining what's wrong
 // rather than the generic chrome download page.  See
@@ -287,37 +337,76 @@
 }
 }  // namespace
 
-base::FilePath ReadPathFromRegistry(HKEY root, const wchar_t* path_name) {
-  base::win::RegKey gcp_key(HKEY_CURRENT_USER, kCloudPrintRegKey, KEY_READ);
+base::string16 ReadStringFromRegistry(HKEY root, const wchar_t* path_name) {
+  base::win::RegKey gcp_key(root, kCloudPrintRegKey, KEY_READ);
   base::string16 data;
-  if (SUCCEEDED(gcp_key.ReadValue(path_name, &data)) &&
-      base::PathExists(base::FilePath(data))) {
-    return base::FilePath(data);
-  }
-  return base::FilePath();
+  gcp_key.ReadValue(path_name, &data);
+  return data;
 }
 
-base::FilePath ReadPathFromAnyRegistry(const wchar_t* path_name) {
-  base::FilePath result = ReadPathFromRegistry(HKEY_CURRENT_USER, path_name);
+base::string16 ReadStringFromAnyRegistry(const wchar_t* path_name) {
+  base::string16 result = ReadStringFromRegistry(HKEY_CURRENT_USER, path_name);
   if (!result.empty())
     return result;
-  return ReadPathFromRegistry(HKEY_LOCAL_MACHINE, path_name);
+  return ReadStringFromRegistry(HKEY_LOCAL_MACHINE, path_name);
 }
 
 base::FilePath GetChromeExePath() {
-  base::FilePath path = ReadPathFromAnyRegistry(kChromeExePathRegValue);
-  if (!path.empty())
-    return path;
+  base::string16 value = ReadStringFromAnyRegistry(kChromeExePathRegValue);
+  if (!value.empty() && base::PathExists(base::FilePath(value)))
+    return base::FilePath(value);
   return chrome_launcher_support::GetAnyChromePath(false /* is_sxs */);
 }
 
 base::FilePath GetChromeProfilePath() {
-  base::FilePath path = ReadPathFromAnyRegistry(kChromeProfilePathRegValue);
-  if (!path.empty() && base::DirectoryExists(path))
-    return path;
+  base::string16 value = ReadStringFromAnyRegistry(kChromeProfilePathRegValue);
+  if (!value.empty() && base::DirectoryExists(base::FilePath(value)))
+    return base::FilePath(value);
   return base::FilePath();
 }
 
+// Launches the Cloud Print dialog in Chrome.
+bool LaunchChromePrintDialog(const base::FilePath& xps_path,
+                             const base::string16& job_title) {
+  base::FilePath chrome_path = GetChromeExePath();
+  if (chrome_path.empty()) {
+    LOG(ERROR) << "Unable to get chrome exe path.";
+    LaunchChromeDownloadPage();
+    return false;
+  }
+
+  base::CommandLine command_line(chrome_path);
+
+  base::FilePath chrome_profile = GetChromeProfilePath();
+  if (!chrome_profile.empty())
+    command_line.AppendSwitchPath(switches::kUserDataDir, chrome_profile);
+
+  command_line.AppendSwitchPath(switches::kCloudPrintFile, xps_path);
+  command_line.AppendSwitchNative(switches::kCloudPrintFileType, kXpsMimeType);
+  command_line.AppendSwitchNative(switches::kCloudPrintJobTitle, job_title);
+
+  return LaunchCommandAsUser(command_line);
+}
+
+base::string16 GetPrintCommandTemplate() {
+  return ReadStringFromAnyRegistry(kPrintCommandRegValue);
+}
+
+// Launches the print command. This will either launch Chrome to display the
+// Cloud Print dialog or another exe as specified in the cloud print registry.
+// xps_path references a file to print.
+// job_title is the title to be used for the resulting print job.
+bool LaunchPrintCommand(const base::FilePath& xps_path,
+                        const base::string16& job_title) {
+  base::string16 command_template = GetPrintCommandTemplate();
+  if (!command_template.empty()) {
+    return LaunchPrintCommandFromTemplate(
+        command_template, xps_path, job_title);
+  } else {
+    return LaunchChromePrintDialog(xps_path, job_title);
+  }
+}
+
 BOOL WINAPI Monitor2EnumPorts(HANDLE,
                               wchar_t*,
                               DWORD level,
@@ -493,9 +582,7 @@
                     port_data->job_id,
                     &job_title);
       }
-      if (!LaunchPrintDialog(port_data->file_path, job_title)) {
-        LaunchChromeDownloadPage();
-      } else {
+      if (LaunchPrintCommand(port_data->file_path, job_title)) {
         delete_file = false;
       }
     }
diff --git a/cloud_print/virtual_driver/win/port_monitor/port_monitor.h b/cloud_print/virtual_driver/win/port_monitor/port_monitor.h
index 20dae1e7..29b8432 100644
--- a/cloud_print/virtual_driver/win/port_monitor/port_monitor.h
+++ b/cloud_print/virtual_driver/win/port_monitor/port_monitor.h
@@ -19,6 +19,9 @@
 // Returns path to user profile to be used for launching Chrome.
 base::FilePath GetChromeProfilePath();
 
+// Returns the print command to launch, if set, instead of Chrome.
+base::string16 GetPrintCommandTemplate();
+
 // Implementations for the function pointers in the MONITOR2 structure
 // returned by InitializePrintMonitor2.  The prototypes and behaviors
 // are as described in the MONITOR2 documentation from Microsoft.
@@ -83,6 +86,7 @@
 extern const wchar_t kChromeExePath[];
 extern const wchar_t kChromeExePathRegValue[];
 extern const wchar_t kChromeProfilePathRegValue[];
+extern const wchar_t kPrintCommandRegValue[];
 extern const bool kIsUnittest;
 
 }   // namespace cloud_print
diff --git a/cloud_print/virtual_driver/win/port_monitor/port_monitor_dll.cc b/cloud_print/virtual_driver/win/port_monitor/port_monitor_dll.cc
index d2d1119..ca6b97d 100644
--- a/cloud_print/virtual_driver/win/port_monitor/port_monitor_dll.cc
+++ b/cloud_print/virtual_driver/win/port_monitor/port_monitor_dll.cc
@@ -32,6 +32,7 @@
 const wchar_t kChromeExePath[] = L"google\\chrome\\application\\chrome.exe";
 const wchar_t kChromeExePathRegValue[] = L"PathToChromeExe";
 const wchar_t kChromeProfilePathRegValue[] = L"PathToChromeProfile";
+const wchar_t kPrintCommandRegValue[] = L"PrintCommand";
 const bool kIsUnittest = false;
 
 namespace {
diff --git a/cloud_print/virtual_driver/win/port_monitor/port_monitor_unittest.cc b/cloud_print/virtual_driver/win/port_monitor/port_monitor_unittest.cc
index b9bc639..84963c0 100644
--- a/cloud_print/virtual_driver/win/port_monitor/port_monitor_unittest.cc
+++ b/cloud_print/virtual_driver/win/port_monitor/port_monitor_unittest.cc
@@ -19,12 +19,14 @@
 const wchar_t kChromeExePath[] = L"google\\chrome\\application\\chrometest.exe";
 const wchar_t kChromeExePathRegValue[] = L"PathToChromeTestExe";
 const wchar_t kChromeProfilePathRegValue[] = L"PathToChromeTestProfile";
+const wchar_t kPrintCommandRegValue[] = L"TestPrintCommand";
 const bool kIsUnittest = true;
 
 namespace {
 
 const wchar_t kAlternateChromeExePath[] =
     L"google\\chrome\\application\\chrometestalternate.exe";
+const wchar_t kTestPrintCommand[] = L"testprintcommand.exe";
 
 const wchar_t kCloudPrintRegKey[] = L"Software\\Google\\CloudPrint";
 
@@ -53,6 +55,10 @@
     ASSERT_EQ(ERROR_SUCCESS,
               key.WriteValue(cloud_print::kChromeProfilePathRegValue,
                              temp.value().c_str()));
+
+    ASSERT_EQ(ERROR_SUCCESS,
+              key.WriteValue(cloud_print::kPrintCommandRegValue,
+                             kTestPrintCommand));
   }
   // Deletes the registry entry created in SetUpChromeExeRegistry
   virtual void DeleteChromeExeRegistry() {
@@ -61,6 +67,7 @@
                           KEY_ALL_ACCESS);
     key.DeleteValue(cloud_print::kChromeExePathRegValue);
     key.DeleteValue(cloud_print::kChromeProfilePathRegValue);
+    key.DeleteValue(cloud_print::kPrintCommandRegValue);
   }
 
   virtual void CreateTempChromeExeFiles() {
@@ -105,6 +112,15 @@
               chrome_path.value().rfind(kChromeExePath) == std::string::npos);
 }
 
+TEST_F(PortMonitorTest, GetPrintCommandTemplateTest) {
+  base::string16 print_command = cloud_print::GetPrintCommandTemplate();
+  EXPECT_FALSE(print_command .empty());
+  EXPECT_EQ(print_command, kTestPrintCommand);
+  DeleteChromeExeRegistry();
+  print_command = cloud_print::GetPrintCommandTemplate();
+  EXPECT_TRUE(print_command.empty());
+}
+
 TEST_F(PortMonitorTest, GetChromeProfilePathTest) {
   base::FilePath data_path = cloud_print::GetChromeProfilePath();
   EXPECT_FALSE(data_path.empty());
diff --git a/components/autofill.gypi b/components/autofill.gypi
index 6c4e15b..cd22d67 100644
--- a/components/autofill.gypi
+++ b/components/autofill.gypi
@@ -202,6 +202,8 @@
         'autofill/core/browser/webdata/autofill_profile_syncable_service.h',
         'autofill/core/browser/webdata/autofill_table.cc',
         'autofill/core/browser/webdata/autofill_table.h',
+        'autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc',
+        'autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h',
         'autofill/core/browser/webdata/autofill_wallet_syncable_service.cc',
         'autofill/core/browser/webdata/autofill_wallet_syncable_service.h',
         'autofill/core/browser/webdata/autofill_webdata.h',
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index e09021e2..b6686c3c 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -296,8 +296,8 @@
   content::SSLStatus ssl_status =
       render_frame()->GetRenderView()->GetSSLStatusOfFrame(
           form.document().frame());
-  bool is_safe = url.SchemeIs(url::kHttpsScheme) &&
-      !net::IsCertStatusError(ssl_status.cert_status);
+  bool is_safe = url.SchemeIsCryptographic() &&
+                 !net::IsCertStatusError(ssl_status.cert_status);
   bool allow_unsafe = base::CommandLine::ForCurrentProcess()->HasSwitch(
       ::switches::kReduceSecurityForTesting);
   FormData form_data;
diff --git a/components/autofill/content/renderer/form_cache.cc b/components/autofill/content/renderer/form_cache.cc
index c1a41a8..a79957b 100644
--- a/components/autofill/content/renderer/form_cache.cc
+++ b/components/autofill/content/renderer/form_cache.cc
@@ -81,6 +81,8 @@
   if (document.isNull())
     return forms;
 
+  initial_checked_state_.clear();
+  initial_select_values_.clear();
   WebVector<WebFormElement> web_forms;
   document.forms(web_forms);
 
@@ -115,6 +117,14 @@
 
     if (form.fields.size() >= kRequiredAutofillFields &&
         !ContainsKey(parsed_forms_, form)) {
+      for (auto it = parsed_forms_.begin(); it != parsed_forms_.end(); ++it) {
+        if (it->SameFormAs(form)) {
+          parsed_forms_.erase(it);
+          break;
+        }
+      }
+
+      SaveInitialValues(control_elements);
       forms.push_back(form);
       parsed_forms_.insert(form);
     }
@@ -144,8 +154,10 @@
 
   if (synthetic_form.fields.size() >= kRequiredAutofillFields &&
       !parsed_forms_.count(synthetic_form)) {
+    SaveInitialValues(control_elements);
     forms.push_back(synthetic_form);
     parsed_forms_.insert(synthetic_form);
+    parsed_forms_.erase(synthetic_form_);
     synthetic_form_ = synthetic_form;
   }
   return forms;
@@ -299,26 +311,33 @@
 
     // Save original values of <select> elements so we can restore them
     // when |ClearFormWithNode()| is invoked.
+    if (IsSelectElement(element) || IsTextAreaElement(element)) {
+      ++num_editable_elements;
+    } else {
+      const WebInputElement input_element = element.toConst<WebInputElement>();
+      if (!IsCheckableElement(&input_element))
+        ++num_editable_elements;
+    }
+  }
+  return num_editable_elements;
+}
+
+void FormCache::SaveInitialValues(
+    const std::vector<WebFormControlElement>& control_elements) {
+  for (const WebFormControlElement& element : control_elements) {
     if (IsSelectElement(element)) {
       const WebSelectElement select_element =
           element.toConst<WebSelectElement>();
       initial_select_values_.insert(
           std::make_pair(select_element, select_element.value()));
-      ++num_editable_elements;
-    } else if (IsTextAreaElement(element)) {
-      ++num_editable_elements;
     } else {
-      const WebInputElement input_element =
-          element.toConst<WebInputElement>();
-      if (IsCheckableElement(&input_element)) {
+      const WebInputElement* input_element = toWebInputElement(&element);
+      if (IsCheckableElement(input_element)) {
         initial_checked_state_.insert(
-            std::make_pair(input_element, input_element.isChecked()));
-      } else {
-        ++num_editable_elements;
+            std::make_pair(*input_element, input_element->isChecked()));
       }
     }
   }
-  return num_editable_elements;
 }
 
 }  // namespace autofill
diff --git a/components/autofill/content/renderer/form_cache.h b/components/autofill/content/renderer/form_cache.h
index f534e20..15c5680 100644
--- a/components/autofill/content/renderer/form_cache.h
+++ b/components/autofill/content/renderer/form_cache.h
@@ -57,6 +57,10 @@
       const std::vector<blink::WebFormControlElement>& control_elements,
       bool log_deprecation_messages);
 
+  // Saves initial state of checkbox and select elements.
+  void SaveInitialValues(
+      const std::vector<blink::WebFormControlElement>& control_elements);
+
   // The frame this FormCache is associated with.
   const blink::WebFrame& frame_;
 
diff --git a/components/autofill/content/renderer/password_form_conversion_utils.cc b/components/autofill/content/renderer/password_form_conversion_utils.cc
index e27e482..f4dfcdf 100644
--- a/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -427,6 +427,10 @@
     UMA_HISTOGRAM_COUNTS_100(
         "PasswordManager.EmptyUsernames.TextAndPasswordFieldCount",
         layout_sequence.size());
+    // For comparison, also report the number of password fields.
+    UMA_HISTOGRAM_COUNTS_100(
+        "PasswordManager.EmptyUsernames.PasswordFieldCount",
+        std::count(layout_sequence.begin(), layout_sequence.end(), 'P'));
   }
 
   password_form->scheme = PasswordForm::SCHEME_HTML;
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 1c6a5fa6..5101bb8 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -123,6 +123,8 @@
     "webdata/autofill_profile_syncable_service.h",
     "webdata/autofill_table.cc",
     "webdata/autofill_table.h",
+    "webdata/autofill_wallet_metadata_syncable_service.cc",
+    "webdata/autofill_wallet_metadata_syncable_service.h",
     "webdata/autofill_wallet_syncable_service.cc",
     "webdata/autofill_wallet_syncable_service.h",
     "webdata/autofill_webdata.h",
@@ -241,6 +243,7 @@
     "validation_unittest.cc",
     "webdata/autofill_profile_syncable_service_unittest.cc",
     "webdata/autofill_table_unittest.cc",
+    "webdata/autofill_wallet_metadata_syncable_service_unittest.cc",
     "webdata/web_data_service_unittest.cc",
   ]
 
diff --git a/components/autofill/core/browser/autofill_merge_unittest.cc b/components/autofill/core/browser/autofill_merge_unittest.cc
index 91803e1..a737430 100644
--- a/components/autofill/core/browser/autofill_merge_unittest.cc
+++ b/components/autofill/core/browser/autofill_merge_unittest.cc
@@ -64,14 +64,11 @@
     result += "\n";
     for (size_t j = 0; j < arraysize(kProfileFieldTypes); ++j) {
       ServerFieldType type = kProfileFieldTypes[j];
-      std::vector<base::string16> values;
-      profiles[i]->GetRawMultiInfo(type, &values);
-      for (size_t k = 0; k < values.size(); ++k) {
-        result += AutofillType(type).ToString();
-        result += kFieldSeparator;
-        result += base::UTF16ToUTF8(values[k]);
-        result += "\n";
-      }
+      base::string16 value = profiles[i]->GetRawInfo(type);
+      result += AutofillType(type).ToString();
+      result += kFieldSeparator;
+      result += base::UTF16ToUTF8(value);
+      result += "\n";
     }
   }
 
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc
index 0496fcc..7012a9b1 100644
--- a/components/autofill/core/browser/autofill_profile.cc
+++ b/components/autofill/core/browser/autofill_profile.cc
@@ -186,67 +186,6 @@
   }
 }
 
-// A helper function for string streaming.  Concatenates multi-valued entries
-// stored for a given |type| into a single string.  This string is returned.
-const base::string16 MultiString(const AutofillProfile& p,
-                                 ServerFieldType type) {
-  std::vector<base::string16> values;
-  p.GetRawMultiInfo(type, &values);
-  base::string16 accumulate;
-  for (size_t i = 0; i < values.size(); ++i) {
-    if (i > 0)
-      accumulate += ASCIIToUTF16(" ");
-    accumulate += values[i];
-  }
-  return accumulate;
-}
-
-base::string16 GetFormGroupInfo(const FormGroup& form_group,
-                                const AutofillType& type,
-                                const std::string& app_locale) {
-  return app_locale.empty() ?
-      form_group.GetRawInfo(type.GetStorableType()) :
-      form_group.GetInfo(type, app_locale);
-}
-
-template <class T>
-void CopyRawValuesToItems(ServerFieldType type,
-                          const std::vector<base::string16>& values,
-                          const T& prototype,
-                          std::vector<T>* form_group_items) {
-  form_group_items->resize(values.size(), prototype);
-  for (size_t i = 0; i < form_group_items->size(); ++i) {
-    (*form_group_items)[i].SetRawInfo(type, values[i]);
-  }
-  // Must have at least one (possibly empty) element.
-  form_group_items->resize(std::max<size_t>(1UL, values.size()), prototype);
-}
-
-template <class T>
-void CopyValuesToItems(AutofillType type,
-                       const std::vector<base::string16>& values,
-                       const T& prototype,
-                       const std::string& app_locale,
-                       std::vector<T>* form_group_items) {
-  form_group_items->resize(values.size(), prototype);
-  for (size_t i = 0; i < form_group_items->size(); ++i) {
-    (*form_group_items)[i].SetInfo(type, values[i], app_locale);
-  }
-  // Must have at least one (possibly empty) element.
-  form_group_items->resize(std::max<size_t>(1UL, values.size()), prototype);
-}
-
-template <class T>
-void CopyItemsToValues(const AutofillType& type,
-                       const std::vector<T>& form_group_items,
-                       const std::string& app_locale,
-                       std::vector<base::string16>* values) {
-  values->resize(form_group_items.size());
-  for (size_t i = 0; i < values->size(); ++i) {
-    (*values)[i] = GetFormGroupInfo(form_group_items[i], type, app_locale);
-  }
-}
-
 // Collapse compound field types to their "full" type.  I.e. First name
 // collapses to full name, area code collapses to full phone, etc.
 void CollapseCompoundFieldTypes(ServerFieldTypeSet* type_set) {
@@ -303,17 +242,13 @@
                                  const std::string& origin)
     : AutofillDataModel(guid, origin),
       record_type_(LOCAL_PROFILE),
-      name_(1),
-      email_(1),
-      phone_number_(1, PhoneNumber(this)) {
+      phone_number_(this) {
 }
 
 AutofillProfile::AutofillProfile(RecordType type, const std::string& server_id)
     : AutofillDataModel(base::GenerateGUID(), std::string()),
       record_type_(type),
-      name_(1),
-      email_(1),
-      phone_number_(1, PhoneNumber(this)),
+      phone_number_(this),
       server_id_(server_id) {
   DCHECK(type == SERVER_PROFILE);
 }
@@ -321,13 +256,11 @@
 AutofillProfile::AutofillProfile()
     : AutofillDataModel(base::GenerateGUID(), std::string()),
       record_type_(LOCAL_PROFILE),
-      name_(1),
-      email_(1),
-      phone_number_(1, PhoneNumber(this)) {
+      phone_number_(this) {
 }
 
 AutofillProfile::AutofillProfile(const AutofillProfile& profile)
-    : AutofillDataModel(std::string(), std::string()) {
+    : AutofillDataModel(std::string(), std::string()), phone_number_(this) {
   operator=(profile);
 }
 
@@ -351,9 +284,7 @@
   email_ = profile.email_;
   company_ = profile.company_;
   phone_number_ = profile.phone_number_;
-
-  for (size_t i = 0; i < phone_number_.size(); ++i)
-    phone_number_[i].set_profile(this);
+  phone_number_.set_profile(this);
 
   address_ = profile.address_;
   set_language_code(profile.language_code());
@@ -419,49 +350,6 @@
   return form_group->SetInfo(type, trimmed_value, app_locale);
 }
 
-void AutofillProfile::SetRawMultiInfo(
-    ServerFieldType type,
-    const std::vector<base::string16>& values) {
-  switch (AutofillType(type).group()) {
-    case NAME:
-    case NAME_BILLING:
-      CopyRawValuesToItems(type, values, NameInfo(), &name_);
-      break;
-
-    case EMAIL:
-      CopyRawValuesToItems(type, values, EmailInfo(), &email_);
-      break;
-
-    case PHONE_HOME:
-    case PHONE_BILLING:
-      CopyRawValuesToItems(type, values, PhoneNumber(this), &phone_number_);
-      break;
-
-    default:
-      if (values.size() == 1U) {
-        SetRawInfo(type, values[0]);
-      } else if (values.empty()) {
-        SetRawInfo(type, base::string16());
-      } else {
-        // Shouldn't attempt to set multiple values on single-valued field.
-        NOTREACHED();
-      }
-      break;
-  }
-}
-
-void AutofillProfile::GetRawMultiInfo(
-    ServerFieldType type,
-    std::vector<base::string16>* values) const {
-  GetMultiInfoImpl(AutofillType(type), std::string(), values);
-}
-
-void AutofillProfile::GetMultiInfo(const AutofillType& type,
-                                   const std::string& app_locale,
-                                   std::vector<base::string16>* values) const {
-  GetMultiInfoImpl(type, app_locale, values);
-}
-
 bool AutofillProfile::IsEmpty(const std::string& app_locale) const {
   ServerFieldTypeSet types;
   GetNonEmptyTypes(app_locale, &types);
@@ -494,44 +382,27 @@
 }
 
 int AutofillProfile::Compare(const AutofillProfile& profile) const {
-  const ServerFieldType single_value_types[] = {
-    COMPANY_NAME,
-    ADDRESS_HOME_STREET_ADDRESS,
-    ADDRESS_HOME_DEPENDENT_LOCALITY,
-    ADDRESS_HOME_CITY,
-    ADDRESS_HOME_STATE,
-    ADDRESS_HOME_ZIP,
-    ADDRESS_HOME_SORTING_CODE,
-    ADDRESS_HOME_COUNTRY,
+  const ServerFieldType types[] = {
+      NAME_FULL,
+      NAME_FIRST,
+      NAME_MIDDLE,
+      NAME_LAST,
+      COMPANY_NAME,
+      ADDRESS_HOME_STREET_ADDRESS,
+      ADDRESS_HOME_DEPENDENT_LOCALITY,
+      ADDRESS_HOME_CITY,
+      ADDRESS_HOME_STATE,
+      ADDRESS_HOME_ZIP,
+      ADDRESS_HOME_SORTING_CODE,
+      ADDRESS_HOME_COUNTRY,
+      EMAIL_ADDRESS,
+      PHONE_HOME_WHOLE_NUMBER,
   };
 
-  for (size_t i = 0; i < arraysize(single_value_types); ++i) {
-    int comparison = GetRawInfo(single_value_types[i]).compare(
-        profile.GetRawInfo(single_value_types[i]));
-    if (comparison != 0)
+  for (size_t i = 0; i < arraysize(types); ++i) {
+    int comparison = GetRawInfo(types[i]).compare(profile.GetRawInfo(types[i]));
+    if (comparison != 0) {
       return comparison;
-  }
-
-  const ServerFieldType multi_value_types[] = { NAME_FULL,
-                                                NAME_FIRST,
-                                                NAME_MIDDLE,
-                                                NAME_LAST,
-                                                EMAIL_ADDRESS,
-                                                PHONE_HOME_WHOLE_NUMBER };
-
-  for (size_t i = 0; i < arraysize(multi_value_types); ++i) {
-    std::vector<base::string16> values_a;
-    std::vector<base::string16> values_b;
-    GetRawMultiInfo(multi_value_types[i], &values_a);
-    profile.GetRawMultiInfo(multi_value_types[i], &values_b);
-    if (values_a.size() < values_b.size())
-      return -1;
-    if (values_a.size() > values_b.size())
-      return 1;
-    for (size_t j = 0; j < values_a.size(); ++j) {
-      int comparison = values_a[j].compare(values_b[j]);
-      if (comparison != 0)
-        return comparison;
     }
   }
 
@@ -609,66 +480,37 @@
   return true;
 }
 
-void AutofillProfile::OverwriteOrAppendNames(
-    const std::vector<NameInfo>& names,
-    const std::string& app_locale) {
-  std::vector<NameInfo> results(name_);
-  l10n::CaseInsensitiveCompare compare;
-  for (std::vector<NameInfo>::const_iterator it = names.begin();
-       it != names.end();
-       ++it) {
-    NameInfo imported_name = *it;
-    bool should_append_imported_name = true;
-
-    for (size_t index = 0; index < name_.size(); ++index) {
-      NameInfo current_name = name_[index];
-      if (current_name.ParsedNamesAreEqual(imported_name)) {
-        if (current_name.GetRawInfo(NAME_FULL).empty()) {
-          current_name.SetRawInfo(NAME_FULL,
-                                  imported_name.GetRawInfo(NAME_FULL));
-        }
-
-        should_append_imported_name = false;
-        break;
-      }
-
-      AutofillType type = AutofillType(NAME_FULL);
-      base::string16 full_name = current_name.GetInfo(type, app_locale);
-      if (compare.StringsEqual(full_name,
-                               imported_name.GetInfo(type, app_locale))) {
-        // The imported name has the same full name string as one of the
-        // existing names for this profile.  Because full names are
-        // _heuristically_ parsed into {first, middle, last} name components,
-        // it's possible that either the existing name or the imported name
-        // was misparsed.  Prefer to keep the name whose {first, middle,
-        // last} components do not match those computed by the heuristic
-        // parse, as this more likely represents the correct, user-input parse
-        // of the name.
-        NameInfo heuristically_parsed_name;
-        heuristically_parsed_name.SetInfo(type, full_name, app_locale);
-        if (imported_name.ParsedNamesAreEqual(heuristically_parsed_name)) {
-          should_append_imported_name = false;
-          break;
-        }
-
-        if (current_name.ParsedNamesAreEqual(heuristically_parsed_name)) {
-          results[index] = imported_name;
-          should_append_imported_name = false;
-          break;
-        }
-      }
-    }
-
-    // Append unique names to the list.
-    if (should_append_imported_name)
-      results.push_back(imported_name);
+void AutofillProfile::OverwriteName(const NameInfo& imported_name,
+                                    const std::string& app_locale) {
+  if (name_.ParsedNamesAreEqual(imported_name)) {
+    if (name_.GetRawInfo(NAME_FULL).empty())
+      name_.SetRawInfo(NAME_FULL, imported_name.GetRawInfo(NAME_FULL));
+    return;
   }
 
-  name_.swap(results);
+  l10n::CaseInsensitiveCompare compare;
+  AutofillType type = AutofillType(NAME_FULL);
+  base::string16 full_name = name_.GetInfo(type, app_locale);
+  if (compare.StringsEqual(full_name,
+                           imported_name.GetInfo(type, app_locale))) {
+    // The imported name has the same full name string as the name for this
+    // profile.  Because full names are _heuristically_ parsed into
+    // {first, middle, last} name components, it's possible that either the
+    // existing name or the imported name was misparsed.  Prefer to keep the
+    // name whose {first, middle, last} components do not match those computed
+    // by the heuristic parse, as this more likely represents the correct,
+    // user-input parse of the name.
+    NameInfo heuristically_parsed_name;
+    heuristically_parsed_name.SetInfo(type, full_name, app_locale);
+    if (imported_name.ParsedNamesAreEqual(heuristically_parsed_name))
+      return;
+  }
+
+  name_ = imported_name;
 }
 
-void AutofillProfile::OverwriteWithOrAddTo(const AutofillProfile& profile,
-                                           const std::string& app_locale) {
+void AutofillProfile::OverwriteWith(const AutofillProfile& profile,
+                                    const std::string& app_locale) {
   // Verified profiles should never be overwritten with unverified data.
   DCHECK(!IsVerified() || profile.IsVerified());
   set_origin(profile.origin());
@@ -697,59 +539,53 @@
     FieldTypeGroup group = AutofillType(*iter).group();
     // Special case names.
     if (group == NAME) {
-      OverwriteOrAppendNames(profile.name_, app_locale);
+      OverwriteName(profile.name_, app_locale);
       continue;
     }
 
-    // Single value field --- overwrite.
-    if (!AutofillProfile::SupportsMultiValue(*iter)) {
-      base::string16 new_value = profile.GetRawInfo(*iter);
-      if (!compare.StringsEqual(GetRawInfo(*iter), new_value))
-        SetRawInfo(*iter, new_value);
-      continue;
-    }
-
-    // Multi value field --- overwrite/append.
-    std::vector<base::string16> new_values;
-    profile.GetRawMultiInfo(*iter, &new_values);
-    std::vector<base::string16> existing_values;
-    GetRawMultiInfo(*iter, &existing_values);
-
-    // GetMultiInfo always returns at least one element, even if the profile
-    // has no data stored for this field type.
-    if (existing_values.size() == 1 && existing_values.front().empty())
-      existing_values.clear();
-
-    for (std::vector<base::string16>::iterator value_iter =
-             new_values.begin();
-         value_iter != new_values.end(); ++value_iter) {
-      // Don't add duplicates. Most types get case insensitive matching.
-      std::vector<base::string16>::const_iterator existing_iter;
-
-      if (group == PHONE_HOME) {
-        // Phones allow "fuzzy" matching, so "1-800-FLOWERS", "18003569377",
-        // "(800)356-9377" and "356-9377" are considered the same.
-        std::string country_code =
-            base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY));
-        existing_iter =
-            std::find_if(existing_values.begin(), existing_values.end(),
-                         FindByPhone(*value_iter, country_code, app_locale));
-      } else {
-        existing_iter =
-            std::find_if(existing_values.begin(), existing_values.end(),
-                         [&compare, value_iter](base::string16& rhs) {
-                           return compare.StringsEqual(*value_iter, rhs);
-                         });
-      }
-
-      if (existing_iter == existing_values.end())
-        existing_values.insert(existing_values.end(), *value_iter);
-    }
-
-    SetRawMultiInfo(*iter, existing_values);
+    base::string16 new_value = profile.GetRawInfo(*iter);
+    if (!compare.StringsEqual(GetRawInfo(*iter), new_value))
+      SetRawInfo(*iter, new_value);
   }
 }
 
+bool AutofillProfile::SaveAdditionalInfo(const AutofillProfile& profile,
+                                         const std::string& app_locale) {
+  ServerFieldTypeSet field_types, other_field_types;
+  GetNonEmptyTypes(app_locale, &field_types);
+  profile.GetNonEmptyTypes(app_locale, &other_field_types);
+  // See note in OverwriteWith.
+  field_types.erase(ADDRESS_HOME_STREET_ADDRESS);
+  l10n::CaseInsensitiveCompare compare;
+  for (ServerFieldType field_type : field_types) {
+    if (other_field_types.count(field_type)) {
+      AutofillType type = AutofillType(field_type);
+      if (type.group() == NAME &&
+          compare.StringsEqual(
+              profile.GetInfo(AutofillType(NAME_FULL), app_locale),
+              GetInfo(AutofillType(NAME_FULL), app_locale))) {
+        continue;
+      }
+      if (type.group() == PHONE_HOME &&
+          i18n::PhoneNumbersMatch(
+              GetRawInfo(PHONE_HOME_WHOLE_NUMBER),
+              profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER),
+              base::UTF16ToASCII(GetRawInfo(ADDRESS_HOME_COUNTRY)),
+              app_locale)) {
+        continue;
+      }
+      if (!compare.StringsEqual(profile.GetRawInfo(field_type),
+                                GetRawInfo(field_type))) {
+        return false;
+      }
+    }
+  }
+
+  if (!IsVerified() || profile.IsVerified())
+    OverwriteWith(profile, app_locale);
+  return true;
+}
+
 // static
 bool AutofillProfile::SupportsMultiValue(ServerFieldType type) {
   FieldTypeGroup group = AutofillType(type).group();
@@ -815,10 +651,10 @@
 
 void AutofillProfile::GenerateServerProfileIdentifier() {
   DCHECK_EQ(SERVER_PROFILE, record_type());
-  base::string16 contents = MultiString(*this, NAME_FIRST);
-  contents.append(MultiString(*this, NAME_MIDDLE));
-  contents.append(MultiString(*this, NAME_LAST));
-  contents.append(MultiString(*this, EMAIL_ADDRESS));
+  base::string16 contents = GetRawInfo(NAME_FIRST);
+  contents.append(GetRawInfo(NAME_MIDDLE));
+  contents.append(GetRawInfo(NAME_LAST));
+  contents.append(GetRawInfo(EMAIL_ADDRESS));
   contents.append(GetRawInfo(COMPANY_NAME));
   contents.append(GetRawInfo(ADDRESS_HOME_STREET_ADDRESS));
   contents.append(GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY));
@@ -827,7 +663,7 @@
   contents.append(GetRawInfo(ADDRESS_HOME_ZIP));
   contents.append(GetRawInfo(ADDRESS_HOME_SORTING_CODE));
   contents.append(GetRawInfo(ADDRESS_HOME_COUNTRY));
-  contents.append(MultiString(*this, PHONE_HOME_WHOLE_NUMBER));
+  contents.append(GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
   std::string contents_utf8 = UTF16ToUTF8(contents);
   contents_utf8.append(language_code());
   server_id_ = base::SHA1HashString(contents_utf8);
@@ -906,28 +742,6 @@
     (*it)->GetSupportedTypes(supported_types);
 }
 
-void AutofillProfile::GetMultiInfoImpl(
-    const AutofillType& type,
-    const std::string& app_locale,
-    std::vector<base::string16>* values) const {
-  switch (type.group()) {
-    case NAME:
-    case NAME_BILLING:
-      CopyItemsToValues(type, name_, app_locale, values);
-      break;
-    case EMAIL:
-      CopyItemsToValues(type, email_, app_locale, values);
-      break;
-    case PHONE_HOME:
-    case PHONE_BILLING:
-      CopyItemsToValues(type, phone_number_, app_locale, values);
-      break;
-    default:
-      values->resize(1);
-      (*values)[0] = GetFormGroupInfo(*this, type, app_locale);
-  }
-}
-
 base::string16 AutofillProfile::ConstructInferredLabel(
     const std::vector<ServerFieldType>& included_fields,
     size_t num_fields_to_use,
@@ -1081,10 +895,10 @@
 
 AutofillProfile::FormGroupList AutofillProfile::FormGroups() const {
   FormGroupList v(5);
-  v[0] = &name_[0];
-  v[1] = &email_[0];
+  v[0] = &name_;
+  v[1] = &email_;
   v[2] = &company_;
-  v[3] = &phone_number_[0];
+  v[3] = &phone_number_;
   v[4] = &address_;
   return v;
 }
@@ -1098,17 +912,17 @@
   switch (type.group()) {
     case NAME:
     case NAME_BILLING:
-      return &name_[0];
+      return &name_;
 
     case EMAIL:
-      return &email_[0];
+      return &email_;
 
     case COMPANY:
       return &company_;
 
     case PHONE_HOME:
     case PHONE_BILLING:
-      return &phone_number_[0];
+      return &phone_number_;
 
     case ADDRESS_HOME:
     case ADDRESS_BILLING:
@@ -1134,40 +948,22 @@
 
 // So we can compare AutofillProfiles with EXPECT_EQ().
 std::ostream& operator<<(std::ostream& os, const AutofillProfile& profile) {
-  return os
-      << profile.guid()
-      << " "
-      << profile.origin()
-      << " "
-      << UTF16ToUTF8(MultiString(profile, NAME_FIRST))
-      << " "
-      << UTF16ToUTF8(MultiString(profile, NAME_MIDDLE))
-      << " "
-      << UTF16ToUTF8(MultiString(profile, NAME_LAST))
-      << " "
-      << UTF16ToUTF8(MultiString(profile, EMAIL_ADDRESS))
-      << " "
-      << UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME))
-      << " "
-      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1))
-      << " "
-      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2))
-      << " "
-      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY))
-      << " "
-      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY))
-      << " "
-      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE))
-      << " "
-      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP))
-      << " "
-      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE))
-      << " "
-      << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY))
-      << " "
-      << profile.language_code()
-      << " "
-      << UTF16ToUTF8(MultiString(profile, PHONE_HOME_WHOLE_NUMBER));
+  return os << profile.guid() << " " << profile.origin() << " "
+            << UTF16ToUTF8(profile.GetRawInfo(NAME_FIRST)) << " "
+            << UTF16ToUTF8(profile.GetRawInfo(NAME_MIDDLE)) << " "
+            << UTF16ToUTF8(profile.GetRawInfo(NAME_LAST)) << " "
+            << UTF16ToUTF8(profile.GetRawInfo(EMAIL_ADDRESS)) << " "
+            << UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME)) << " "
+            << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1)) << " "
+            << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE2)) << " "
+            << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY))
+            << " " << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_CITY)) << " "
+            << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_STATE)) << " "
+            << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_ZIP)) << " "
+            << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_SORTING_CODE)) << " "
+            << UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_COUNTRY)) << " "
+            << profile.language_code() << " "
+            << UTF16ToUTF8(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_profile.h b/components/autofill/core/browser/autofill_profile.h
index 9ad7e389..433099ac 100644
--- a/components/autofill/core/browser/autofill_profile.h
+++ b/components/autofill/core/browser/autofill_profile.h
@@ -69,15 +69,6 @@
   RecordType record_type() const { return record_type_; }
   void set_record_type(RecordType type) { record_type_ = type; }
 
-  // Multi-value equivalents to |GetInfo| and |SetInfo|.
-  void SetRawMultiInfo(ServerFieldType type,
-                       const std::vector<base::string16>& values);
-  void GetRawMultiInfo(ServerFieldType type,
-                       std::vector<base::string16>* values) const;
-  void GetMultiInfo(const AutofillType& type,
-                    const std::string& app_locale,
-                    std::vector<base::string16>* values) const;
-
   // Returns true if there are no values (field types) set.
   bool IsEmpty(const std::string& app_locale) const;
 
@@ -123,10 +114,16 @@
                              const std::string& app_locale,
                              const ServerFieldTypeSet& types) const;
 
-  // Overwrites the single-valued field data in |profile| with this
-  // Profile.  Or, for multi-valued fields append the new values.
-  void OverwriteWithOrAddTo(const AutofillProfile& profile,
-                            const std::string& app_locale);
+  // Overwrites the field data in |profile| with this Profile.
+  void OverwriteWith(const AutofillProfile& profile,
+                     const std::string& app_locale);
+
+  // Saves info from |profile| into |this|, provided |this| and |profile| do not
+  // have any direct conflicts (i.e. data is present but different). Will not
+  // make changes if |this| is verified and |profile| is not. Returns true if
+  // |this| and |profile| are similar.
+  bool SaveAdditionalInfo(const AutofillProfile& profile,
+                          const std::string& app_locale);
 
   // Returns |true| if |type| accepts multi-values.
   static bool SupportsMultiValue(ServerFieldType type);
@@ -191,13 +188,6 @@
   // FormGroup:
   void GetSupportedTypes(ServerFieldTypeSet* supported_types) const override;
 
-  // Shared implementation for GetRawMultiInfo() and GetMultiInfo().  Pass an
-  // empty |app_locale| to get the raw info; otherwise, the returned info is
-  // canonicalized according to the given |app_locale|, if appropriate.
-  void GetMultiInfoImpl(const AutofillType& type,
-                        const std::string& app_locale,
-                        std::vector<base::string16>* values) const;
-
   // Builds inferred label from the first |num_fields_to_include| non-empty
   // fields in |label_fields|. Uses as many fields as possible if there are not
   // enough non-empty fields.
@@ -225,12 +215,10 @@
   const FormGroup* FormGroupForType(const AutofillType& type) const;
   FormGroup* MutableFormGroupForType(const AutofillType& type);
 
-  // Appends unique names from |names| onto the |name_| list, dropping
-  // duplicates. If a name in |names| has the same full name representation
-  // as a name in |name_|, keeps the variant that has more information (i.e.
+  // If |name| has the same full name representation as |name_|,
+  // this will keep the one that has more information (i.e.
   // is not reconstructible via a heuristic parse of the full name string).
-  void OverwriteOrAppendNames(const std::vector<NameInfo>& names,
-                              const std::string& app_locale);
+  void OverwriteName(const NameInfo& name, const std::string& app_locale);
 
   // Same as operator==, but ignores differences in GUID.
   bool EqualsSansGuid(const AutofillProfile& profile) const;
@@ -238,10 +226,10 @@
   RecordType record_type_;
 
   // Personal information for this profile.
-  std::vector<NameInfo> name_;
-  std::vector<EmailInfo> email_;
+  NameInfo name_;
+  EmailInfo email_;
   CompanyInfo company_;
-  std::vector<PhoneNumber> phone_number_;
+  PhoneNumber phone_number_;
   Address address_;
 
   // The BCP 47 language code that can be used to format |address_| for display.
diff --git a/components/autofill/core/browser/autofill_profile_unittest.cc b/components/autofill/core/browser/autofill_profile_unittest.cc
index 168282d..431f3982 100644
--- a/components/autofill/core/browser/autofill_profile_unittest.cc
+++ b/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -830,27 +830,18 @@
   EXPECT_FALSE(a->IsSubsetOf(*b, "en-US"));
 }
 
-TEST(AutofillProfileTest, OverwriteWithOrAddTo) {
+TEST(AutofillProfileTest, OverwriteWith) {
   AutofillProfile a(base::GenerateGUID(), "https://www.example.com");
   test::SetProfileInfo(&a, "Marion", "Mitchell", "Morrison",
                        "marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
                        "Hollywood", "CA", "91601", "US",
                        "12345678910");
-  std::vector<base::string16> first_names;
-  a.GetRawMultiInfo(NAME_FIRST, &first_names);
-  first_names.push_back(ASCIIToUTF16("Marion"));
-  a.SetRawMultiInfo(NAME_FIRST, first_names);
-
-  std::vector<base::string16> last_names;
-  a.GetRawMultiInfo(NAME_LAST, &last_names);
-  last_names[last_names.size() - 1] = ASCIIToUTF16("Morrison");
-  a.SetRawMultiInfo(NAME_LAST, last_names);
 
   // Create an identical profile except that the new profile:
   //   (1) Has a different origin,
   //   (2) Has a different address line 2,
   //   (3) Lacks a company name,
-  //   (4) Has a different full name variant, and
+  //   (4) Has a different full name, and
   //   (5) Has a language code.
   AutofillProfile b = a;
   b.set_guid(base::GenerateGUID());
@@ -858,21 +849,15 @@
   b.SetRawInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("area 51"));
   b.SetRawInfo(COMPANY_NAME, base::string16());
 
-  std::vector<base::string16> names;
-  b.GetMultiInfo(AutofillType(NAME_FULL), "en-US", &names);
-  names.push_back(ASCIIToUTF16("Marion M. Morrison"));
-  b.SetRawMultiInfo(NAME_FULL, names);
+  b.SetRawInfo(NAME_FULL, ASCIIToUTF16("Marion M. Morrison"));
   b.set_language_code("en");
 
-  a.OverwriteWithOrAddTo(b, "en-US");
+  a.OverwriteWith(b, "en-US");
   EXPECT_EQ("Chrome settings", a.origin());
   EXPECT_EQ(ASCIIToUTF16("area 51"), a.GetRawInfo(ADDRESS_HOME_LINE2));
   EXPECT_EQ(ASCIIToUTF16("Fox"), a.GetRawInfo(COMPANY_NAME));
-  a.GetMultiInfo(AutofillType(NAME_FULL), "en-US", &names);
-  ASSERT_EQ(3U, names.size());
-  EXPECT_EQ(ASCIIToUTF16("Marion Mitchell Morrison"), names[0]);
-  EXPECT_EQ(ASCIIToUTF16("Marion Morrison"), names[1]);
-  EXPECT_EQ(ASCIIToUTF16("Marion M. Morrison"), names[2]);
+  base::string16 name = a.GetInfo(AutofillType(NAME_FULL), "en-US");
+  EXPECT_EQ(ASCIIToUTF16("Marion M. Morrison"), name);
   EXPECT_EQ("en", a.language_code());
 }
 
@@ -952,132 +937,6 @@
   EXPECT_LT(0, b.Compare(a));
 }
 
-TEST(AutofillProfileTest, MultiValueNames) {
-  AutofillProfile p(base::GenerateGUID(), "https://www.example.com/");
-  const base::string16 kJohnDoe(ASCIIToUTF16("John Doe"));
-  const base::string16 kJohnPDoe(ASCIIToUTF16("John P. Doe"));
-  std::vector<base::string16> set_values;
-  set_values.push_back(kJohnDoe);
-  set_values.push_back(kJohnPDoe);
-  p.SetRawMultiInfo(NAME_FULL, set_values);
-
-  // Expect regular |GetInfo| returns the first element.
-  EXPECT_EQ(kJohnDoe, p.GetRawInfo(NAME_FULL));
-
-  // Ensure that we get out what we put in.
-  std::vector<base::string16> get_values;
-  p.GetRawMultiInfo(NAME_FULL, &get_values);
-  ASSERT_EQ(2UL, get_values.size());
-  EXPECT_EQ(kJohnDoe, get_values[0]);
-  EXPECT_EQ(kJohnPDoe, get_values[1]);
-
-  // Update the values.
-  AutofillProfile p2 = p;
-  EXPECT_EQ(0, p.Compare(p2));
-  const base::string16 kNoOne(ASCIIToUTF16("No One"));
-  set_values[1] = kNoOne;
-  p.SetRawMultiInfo(NAME_FULL, set_values);
-  p.GetRawMultiInfo(NAME_FULL, &get_values);
-  ASSERT_EQ(2UL, get_values.size());
-  EXPECT_EQ(kJohnDoe, get_values[0]);
-  EXPECT_EQ(kNoOne, get_values[1]);
-  EXPECT_NE(0, p.Compare(p2));
-
-  // Delete values.
-  set_values.clear();
-  p.SetRawMultiInfo(NAME_FULL, set_values);
-  p.GetRawMultiInfo(NAME_FULL, &get_values);
-  ASSERT_EQ(1UL, get_values.size());
-  EXPECT_EQ(base::string16(), get_values[0]);
-
-  // Expect regular |GetInfo| returns empty value.
-  EXPECT_EQ(base::string16(), p.GetRawInfo(NAME_FULL));
-}
-
-TEST(AutofillProfileTest, MultiValueEmails) {
-  AutofillProfile p(base::GenerateGUID(), "https://www.example.com/");
-  const base::string16 kJohnDoe(ASCIIToUTF16("john@doe.com"));
-  const base::string16 kJohnPDoe(ASCIIToUTF16("john_p@doe.com"));
-  std::vector<base::string16> set_values;
-  set_values.push_back(kJohnDoe);
-  set_values.push_back(kJohnPDoe);
-  p.SetRawMultiInfo(EMAIL_ADDRESS, set_values);
-
-  // Expect regular |GetInfo| returns the first element.
-  EXPECT_EQ(kJohnDoe, p.GetRawInfo(EMAIL_ADDRESS));
-
-  // Ensure that we get out what we put in.
-  std::vector<base::string16> get_values;
-  p.GetRawMultiInfo(EMAIL_ADDRESS, &get_values);
-  ASSERT_EQ(2UL, get_values.size());
-  EXPECT_EQ(kJohnDoe, get_values[0]);
-  EXPECT_EQ(kJohnPDoe, get_values[1]);
-
-  // Update the values.
-  AutofillProfile p2 = p;
-  EXPECT_EQ(0, p.Compare(p2));
-  const base::string16 kNoOne(ASCIIToUTF16("no@one.com"));
-  set_values[1] = kNoOne;
-  p.SetRawMultiInfo(EMAIL_ADDRESS, set_values);
-  p.GetRawMultiInfo(EMAIL_ADDRESS, &get_values);
-  ASSERT_EQ(2UL, get_values.size());
-  EXPECT_EQ(kJohnDoe, get_values[0]);
-  EXPECT_EQ(kNoOne, get_values[1]);
-  EXPECT_NE(0, p.Compare(p2));
-
-  // Delete values.
-  set_values.clear();
-  p.SetRawMultiInfo(EMAIL_ADDRESS, set_values);
-  p.GetRawMultiInfo(EMAIL_ADDRESS, &get_values);
-  ASSERT_EQ(1UL, get_values.size());
-  EXPECT_EQ(base::string16(), get_values[0]);
-
-  // Expect regular |GetInfo| returns empty value.
-  EXPECT_EQ(base::string16(), p.GetRawInfo(EMAIL_ADDRESS));
-}
-
-TEST(AutofillProfileTest, MultiValuePhone) {
-  AutofillProfile p(base::GenerateGUID(), "https://www.example.com/");
-  const base::string16 kJohnDoe(ASCIIToUTF16("4151112222"));
-  const base::string16 kJohnPDoe(ASCIIToUTF16("4151113333"));
-  std::vector<base::string16> set_values;
-  set_values.push_back(kJohnDoe);
-  set_values.push_back(kJohnPDoe);
-  p.SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
-
-  // Expect regular |GetInfo| returns the first element.
-  EXPECT_EQ(kJohnDoe, p.GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
-
-  // Ensure that we get out what we put in.
-  std::vector<base::string16> get_values;
-  p.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &get_values);
-  ASSERT_EQ(2UL, get_values.size());
-  EXPECT_EQ(kJohnDoe, get_values[0]);
-  EXPECT_EQ(kJohnPDoe, get_values[1]);
-
-  // Update the values.
-  AutofillProfile p2 = p;
-  EXPECT_EQ(0, p.Compare(p2));
-  const base::string16 kNoOne(ASCIIToUTF16("4152110000"));
-  set_values[1] = kNoOne;
-  p.SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
-  p.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &get_values);
-  ASSERT_EQ(2UL, get_values.size());
-  EXPECT_EQ(kJohnDoe, get_values[0]);
-  EXPECT_EQ(kNoOne, get_values[1]);
-  EXPECT_NE(0, p.Compare(p2));
-
-  // Delete values.
-  set_values.clear();
-  p.SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
-  p.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &get_values);
-  ASSERT_EQ(1UL, get_values.size());
-  EXPECT_EQ(base::string16(), get_values[0]);
-
-  // Expect regular |GetInfo| returns empty value.
-  EXPECT_EQ(base::string16(), p.GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
-}
-
 TEST(AutofillProfileTest, IsPresentButInvalid) {
   AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
   EXPECT_FALSE(profile.IsPresentButInvalid(ADDRESS_HOME_STATE));
diff --git a/components/autofill/core/browser/contact_info.cc b/components/autofill/core/browser/contact_info.cc
index 079a041..10520f0 100644
--- a/components/autofill/core/browser/contact_info.cc
+++ b/components/autofill/core/browser/contact_info.cc
@@ -160,7 +160,7 @@
   return *this;
 }
 
-bool NameInfo::ParsedNamesAreEqual(const NameInfo& info) {
+bool NameInfo::ParsedNamesAreEqual(const NameInfo& info) const {
   l10n::CaseInsensitiveCompare compare;
   return compare.StringsEqual(given_, info.given_) &&
          compare.StringsEqual(middle_, info.middle_) &&
diff --git a/components/autofill/core/browser/contact_info.h b/components/autofill/core/browser/contact_info.h
index 1e3adc34..55ca8ab 100644
--- a/components/autofill/core/browser/contact_info.h
+++ b/components/autofill/core/browser/contact_info.h
@@ -25,7 +25,7 @@
 
   // Compares |NameInfo| objects for |given_|, |middle_| and |family_| names,
   // ignoring their case differences.
-  bool ParsedNamesAreEqual(const NameInfo& info);
+  bool ParsedNamesAreEqual(const NameInfo& info) const;
 
   // FormGroup:
   base::string16 GetRawInfo(ServerFieldType type) const override;
diff --git a/components/autofill/core/browser/data_driven_test.cc b/components/autofill/core/browser/data_driven_test.cc
index 01d37a2..e166699 100644
--- a/components/autofill/core/browser/data_driven_test.cc
+++ b/components/autofill/core/browser/data_driven_test.cc
@@ -52,6 +52,11 @@
 void DataDrivenTest::RunOneDataDrivenTest(
     const base::FilePath& test_file_name,
     const base::FilePath& output_directory) {
+  // iOS doesn't get rid of removed test files. TODO(estade): remove this after
+  // all iOS bots are clobbered.
+  if (test_file_name.BaseName().value() == FILE_PATH_LITERAL("multimerge.in"))
+    return;
+
   ASSERT_TRUE(base::DirectoryExists(output_directory));
   SCOPED_TRACE(test_file_name.BaseName().value());
 
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index b1ad2b06..82167f9 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -997,19 +997,14 @@
   // If we have already saved this address, merge in any missing values.
   // Only merge with the first match.
   for (AutofillProfile* existing_profile : existing_profiles) {
-    if (!matching_profile_found &&
-        !new_profile.PrimaryValue().empty() &&
-        AutofillProfile::AreProfileStringsSimilar(
-            existing_profile->PrimaryValue(),
-            new_profile.PrimaryValue())) {
+    if (!matching_profile_found && !new_profile.PrimaryValue().empty() &&
+        existing_profile->SaveAdditionalInfo(new_profile, app_locale)) {
       // Unverified profiles should always be updated with the newer data,
       // whereas verified profiles should only ever be overwritten by verified
       // data.  If an automatically aggregated profile would overwrite a
       // verified profile, just drop it.
       matching_profile_found = true;
       guid = existing_profile->guid();
-      if (!existing_profile->IsVerified() || new_profile.IsVerified())
-        existing_profile->OverwriteWithOrAddTo(new_profile, app_locale);
     }
     merged_profiles->push_back(*existing_profile);
   }
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index de7273a..245e0e1 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -1283,10 +1283,10 @@
   base::MessageLoop::current()->Run();
 
   AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
-  test::SetProfileInfo(
-      &expected, "George", NULL, "Washington", "theprez@gmail.com", NULL,
-      "1600 Pennsylvania Avenue", "Suite A", "San Francisco", "California",
-      "94102", NULL, "(650) 555-6666");
+  test::SetProfileInfo(&expected, "George", nullptr, "Washington",
+                       "theprez@gmail.com", nullptr, "1600 Pennsylvania Avenue",
+                       "Suite A", "San Francisco", "California", "94102",
+                       nullptr, "(650) 555-6666");
   const std::vector<AutofillProfile*>& results1 = personal_data_->GetProfiles();
   ASSERT_EQ(1U, results1.size());
   EXPECT_EQ(0, expected.Compare(*results1[0]));
@@ -1317,8 +1317,8 @@
   // Country gets added.
   test::CreateTestFormField("Country:", "country", "USA", "text", &field);
   form2.fields.push_back(field);
-  // Phone gets updated.
-  test::CreateTestFormField("Phone:", "phone", "6502231234", "text", &field);
+  // Same phone number with different formatting doesn't create a new profile.
+  test::CreateTestFormField("Phone:", "phone", "650-555-6666", "text", &field);
   form2.fields.push_back(field);
 
   FormStructure form_structure2(form2);
@@ -1334,11 +1334,8 @@
 
   const std::vector<AutofillProfile*>& results2 = personal_data_->GetProfiles();
 
-  // Add multi-valued phone number to expectation.  Also, country gets added.
-  std::vector<base::string16> values;
-  expected.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &values);
-  values.push_back(ASCIIToUTF16("(650) 223-1234"));
-  expected.SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, values);
+  // Phone formatting is updated.  Also, country gets added.
+  expected.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("650-555-6666"));
   expected.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
   ASSERT_EQ(1U, results2.size());
   EXPECT_EQ(0, expected.Compare(*results2[0]));
@@ -2136,7 +2133,9 @@
 }
 
 // Ensure that if a verified profile already exists, aggregated profiles cannot
-// modify it in any way.
+// modify it in any way. This also checks the profile merging/matching algorithm
+// works: if either the full name OR all the non-empty name pieces match, the
+// profile is a match.
 TEST_F(PersonalDataManagerTest, AggregateExistingVerifiedProfileWithConflict) {
   // Start with a verified profile.
   AutofillProfile profile(base::GenerateGUID(), "Chrome settings");
@@ -2157,14 +2156,14 @@
   // Simulate a form submission with conflicting info.
   FormData form;
   FormFieldData field;
-  test::CreateTestFormField(
-      "First name:", "first_name", "Marion", "text", &field);
+  test::CreateTestFormField("First name:", "first_name", "Marion Mitchell",
+                            "text", &field);
   form.fields.push_back(field);
   test::CreateTestFormField(
       "Last name:", "last_name", "Morrison", "text", &field);
   form.fields.push_back(field);
-  test::CreateTestFormField(
-      "Email:", "email", "other.email@example.com", "text", &field);
+  test::CreateTestFormField("Email:", "email", "johnwayne@me.xyz", "text",
+                            &field);
   form.fields.push_back(field);
   test::CreateTestFormField(
       "Address:", "address1", "123 Zoo St.", "text", &field);
@@ -2192,6 +2191,29 @@
   const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
   ASSERT_EQ(1U, results.size());
   EXPECT_EQ(0, profile.Compare(*results[0]));
+
+  // Try the same thing, but without "Mitchell". The profiles should still match
+  // because the non empty name pieces (first and last) match that stored in the
+  // profile.
+  test::CreateTestFormField("First name:", "first_name", "Marion", "text",
+                            &field);
+  form.fields[0] = field;
+
+  FormStructure form_structure2(form);
+  form_structure2.DetermineHeuristicTypes();
+  EXPECT_TRUE(
+      personal_data_->ImportFormData(form_structure2, &imported_credit_card));
+  EXPECT_FALSE(imported_credit_card);
+
+  // Wait for the refresh, which in this case is a no-op.
+  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+      .WillOnce(QuitMainMessageLoop());
+  base::MessageLoop::current()->Run();
+
+  // Expect that no new profile is saved.
+  const std::vector<AutofillProfile*>& results2 = personal_data_->GetProfiles();
+  ASSERT_EQ(1U, results2.size());
+  EXPECT_EQ(0, profile.Compare(*results2[0]));
 }
 
 // Ensure that if a verified credit card already exists, aggregated credit cards
@@ -2265,7 +2287,8 @@
   AutofillProfile new_verified_profile = profile;
   new_verified_profile.set_guid(base::GenerateGUID());
   new_verified_profile.set_origin("Chrome settings");
-  new_verified_profile.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Fizzbang, Inc."));
+  new_verified_profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
+                                  ASCIIToUTF16("1 234 567-8910"));
   EXPECT_TRUE(new_verified_profile.IsVerified());
 
   personal_data_->SaveImportedProfile(new_verified_profile);
@@ -2275,8 +2298,7 @@
       .WillOnce(QuitMainMessageLoop());
   base::MessageLoop::current()->Run();
 
-  // Expect that the existing profile is not modified, and instead the new
-  // profile is added.
+  // The new profile should be merged into the existing one.
   const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
   ASSERT_EQ(1U, results.size());
   EXPECT_EQ(0, new_verified_profile.Compare(*results[0]));
@@ -2303,7 +2325,8 @@
 
   AutofillProfile new_verified_profile = profile;
   new_verified_profile.set_guid(base::GenerateGUID());
-  new_verified_profile.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Fizzbang, Inc."));
+  new_verified_profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
+                                  ASCIIToUTF16("1 234 567-8910"));
   EXPECT_TRUE(new_verified_profile.IsVerified());
 
   personal_data_->SaveImportedProfile(new_verified_profile);
@@ -2314,11 +2337,9 @@
   base::MessageLoop::current()->Run();
 
   // The new profile should be merged into the existing one.
-  AutofillProfile expected_profile = profile;
-  expected_profile.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Fizzbang, Inc."));
   const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
   ASSERT_EQ(1U, results.size());
-  EXPECT_EQ(expected_profile, *results[0]);
+  EXPECT_EQ(0, new_verified_profile.Compare(*results[0]));
 }
 
 // Ensure that verified credit cards can be saved via SaveImportedCreditCard.
diff --git a/components/autofill/core/browser/webdata/autofill_change.cc b/components/autofill/core/browser/webdata/autofill_change.cc
index c02bdd84..2d2ff67 100644
--- a/components/autofill/core/browser/webdata/autofill_change.cc
+++ b/components/autofill/core/browser/webdata/autofill_change.cc
@@ -17,13 +17,11 @@
 AutofillChange::~AutofillChange() {
 }
 
-AutofillProfileChange::AutofillProfileChange(
-  Type type, const std::string& key, const AutofillProfile* profile)
-    : GenericAutofillChange<std::string>(type, key),
-      profile_(profile) {
-  DCHECK(type == ADD ? (profile && profile->guid() == key) : true);
-  DCHECK(type == UPDATE ? (profile && profile->guid() == key) : true);
-  DCHECK(type == REMOVE ? !profile : true);
+AutofillProfileChange::AutofillProfileChange(Type type,
+                                             const std::string& key,
+                                             const AutofillProfile* profile)
+    : GenericAutofillChange<std::string>(type, key), profile_(profile) {
+  DCHECK(type == REMOVE ? !profile : profile && profile->guid() == key);
 }
 
 AutofillProfileChange::~AutofillProfileChange() {
@@ -31,9 +29,23 @@
 
 bool AutofillProfileChange::operator==(
     const AutofillProfileChange& change) const {
-  return type() == change.type() &&
-         key() == change.key() &&
-         (type() != REMOVE) ? *profile() == *change.profile() : true;
+  return type() == change.type() && key() == change.key() &&
+         (type() == REMOVE || *profile() == *change.profile());
+}
+
+CreditCardChange::CreditCardChange(Type type,
+                                   const std::string& key,
+                                   const CreditCard* card)
+    : GenericAutofillChange<std::string>(type, key), card_(card) {
+  DCHECK(type == REMOVE ? !card : card && card->guid() == key);
+}
+
+CreditCardChange::~CreditCardChange() {
+}
+
+bool CreditCardChange::operator==(const CreditCardChange& change) const {
+  return type() == change.type() && key() == change.key() &&
+         (type() == REMOVE || *card() == *change.card());
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_change.h b/components/autofill/core/browser/webdata/autofill_change.h
index 0e85657..80281f5 100644
--- a/components/autofill/core/browser/webdata/autofill_change.h
+++ b/components/autofill/core/browser/webdata/autofill_change.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_CHANGE_H__
 #define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_CHANGE_H__
 
+#include <string>
 #include <vector>
 
 #include "components/autofill/core/browser/webdata/autofill_entry.h"
@@ -12,9 +13,10 @@
 namespace autofill {
 
 class AutofillProfile;
+class CreditCard;
 
 // For classic Autofill form fields, the KeyType is AutofillKey.
-// Autofill++ types such as AutofillProfile and CreditCard simply use an int.
+// Autofill++ types such as AutofillProfile and CreditCard simply use a string.
 template <typename KeyType>
 class GenericAutofillChange {
  public:
@@ -70,6 +72,25 @@
   const AutofillProfile* profile_;
 };
 
+// Change notification details for credit card changes.
+class CreditCardChange : public GenericAutofillChange<std::string> {
+ public:
+  // The |type| input specifies the change type.  The |key| input is the key,
+  // which is expected to be the GUID identifying the |card|.
+  // When |type| == ADD, |card| should be non-NULL.
+  // When |type| == UPDATE, |card| should be non-NULL.
+  // When |type| == REMOVE, |card| should be NULL.
+  CreditCardChange(Type type, const std::string& key, const CreditCard* card);
+  ~CreditCardChange() override;
+
+  const CreditCard* card() const { return card_; }
+  bool operator==(const CreditCardChange& change) const;
+
+ private:
+  // Weak reference, can be NULL.
+  const CreditCard* card_;
+};
+
 }  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_CHANGE_H__
diff --git a/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc b/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc
index 80512ee..ded701ce 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc
+++ b/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc
@@ -423,27 +423,15 @@
   specifics->set_use_count(profile.use_count());
   specifics->set_use_date(profile.use_date().ToTimeT());
 
-  std::vector<base::string16> values;
-  profile.GetRawMultiInfo(NAME_FIRST, &values);
-  for (size_t i = 0; i < values.size(); ++i) {
-    specifics->add_name_first(LimitData(UTF16ToUTF8(values[i])));
-  }
-
-  profile.GetRawMultiInfo(NAME_MIDDLE, &values);
-  for (size_t i = 0; i < values.size(); ++i) {
-    specifics->add_name_middle(LimitData(UTF16ToUTF8(values[i])));
-  }
-
-  profile.GetRawMultiInfo(NAME_LAST, &values);
-  for (size_t i = 0; i < values.size(); ++i) {
-    specifics->add_name_last(LimitData(UTF16ToUTF8(values[i])));
-  }
-
-  profile.GetRawMultiInfo(NAME_FULL, &values);
-  for (size_t i = 0; i < values.size(); ++i) {
-    specifics->add_name_full(LimitData(UTF16ToUTF8(values[i])));
-  }
-
+  // TODO(estade): this should be set_name_first.
+  specifics->add_name_first(
+      LimitData(UTF16ToUTF8(profile.GetRawInfo(NAME_FIRST))));
+  specifics->add_name_middle(
+      LimitData(UTF16ToUTF8(profile.GetRawInfo(NAME_MIDDLE))));
+  specifics->add_name_last(
+      LimitData(UTF16ToUTF8(profile.GetRawInfo(NAME_LAST))));
+  specifics->add_name_full(
+      LimitData(UTF16ToUTF8(profile.GetRawInfo(NAME_FULL))));
   specifics->set_address_home_line1(
       LimitData(UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_LINE1))));
   specifics->set_address_home_line2(
@@ -465,18 +453,17 @@
           UTF16ToUTF8(profile.GetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY))));
   specifics->set_address_home_language_code(LimitData(profile.language_code()));
 
-  profile.GetRawMultiInfo(EMAIL_ADDRESS, &values);
-  for (size_t i = 0; i < values.size(); ++i) {
-    specifics->add_email_address(LimitData(UTF16ToUTF8(values[i])));
-  }
+  // TODO(estade): this should be set_email_address.
+  specifics->add_email_address(
+      LimitData(UTF16ToUTF8(profile.GetRawInfo(EMAIL_ADDRESS))));
+  std::vector<base::string16> values;
 
   specifics->set_company_name(
       LimitData(UTF16ToUTF8(profile.GetRawInfo(COMPANY_NAME))));
 
-  profile.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &values);
-  for (size_t i = 0; i < values.size(); ++i) {
-    specifics->add_phone_home_whole_number(LimitData(UTF16ToUTF8(values[i])));
-  }
+  // TODO(estade): this should be set_phone_home_whole_number.
+  specifics->add_phone_home_whole_number(
+      LimitData(UTF16ToUTF8(profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER))));
 }
 
 void AutofillProfileSyncableService::CreateGUIDToProfileMap(
@@ -630,38 +617,22 @@
   return true;
 }
 
+// TODO(estade): remove this function.
 bool AutofillProfileSyncableService::UpdateMultivaluedField(
     ServerFieldType field_type,
     const ::google::protobuf::RepeatedPtrField<std::string>& new_values,
     AutofillProfile* autofill_profile) {
-  std::vector<base::string16> values;
-  autofill_profile->GetRawMultiInfo(field_type, &values);
-  bool changed = false;
-  if (static_cast<size_t>(new_values.size()) != values.size()) {
-    values.clear();
-    values.resize(static_cast<size_t>(new_values.size()));
-    changed = true;
-  }
-  for (size_t i = 0; i < values.size(); ++i) {
-    base::string16 synced_value(
-        UTF8ToUTF16(new_values.Get(static_cast<int>(i))));
-    if (values[i] != synced_value) {
-      values[i] = synced_value;
-      changed = true;
-    }
-  }
-  if (changed)
-    autofill_profile->SetRawMultiInfo(field_type, values);
-  return changed;
+  return UpdateField(field_type,
+                     new_values.size() < 1 ? std::string() : new_values.Get(0),
+                     autofill_profile);
 }
 
 bool AutofillProfileSyncableService::MergeProfile(
     const AutofillProfile& merge_from,
     AutofillProfile* merge_into,
     const std::string& app_locale) {
-  // Overwrites all single values and adds to multi-values. Does not overwrite
-  // GUID.
-  merge_into->OverwriteWithOrAddTo(merge_from, app_locale);
+  // Overwrites all values. Does not overwrite GUID.
+  merge_into->OverwriteWith(merge_from, app_locale);
   return !merge_into->EqualsForSyncPurposes(merge_from);
 }
 
diff --git a/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h b/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
index 65f0360..75757de 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
+++ b/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
@@ -167,8 +167,8 @@
       AutofillProfile* autofill_profile);
 
   // Calls merge_into->OverwriteWithOrAddTo() and then checks if the
-  // |merge_into| has extra data. Returns |true| if |merge_into| posseses some
-  // multi-valued field values that are not in |merge_from|.
+  // |merge_into| has extra data. Returns true if |merge_from| needs updating to
+  // be in sync with |merge_into|.
   // TODO(isherman): Seems like this should return |true| if |merge_into| was
   // modified at all: http://crbug.com/248440
   static bool MergeProfile(const AutofillProfile& merge_from,
diff --git a/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc b/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
index 4c3fe3da..e4bddcfc 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
@@ -136,32 +136,13 @@
   profile->set_use_count(7);
   profile->set_use_date(base::Time::FromTimeT(1423182152));
 
-  std::vector<base::string16> names;
-  names.push_back(ASCIIToUTF16("John K. Doe, Jr."));
-  names.push_back(ASCIIToUTF16("Jane Luise Smith MD"));
-  profile->SetRawMultiInfo(NAME_FULL, names);
-  names.clear();
-  names.push_back(ASCIIToUTF16("John"));
-  names.push_back(ASCIIToUTF16("Jane"));
-  profile->SetRawMultiInfo(NAME_FIRST, names);
-  names.clear();
-  names.push_back(ASCIIToUTF16("K."));
-  names.push_back(ASCIIToUTF16("Luise"));
-  profile->SetRawMultiInfo(NAME_MIDDLE, names);
-  names.clear();
-  names.push_back(ASCIIToUTF16("Doe"));
-  names.push_back(ASCIIToUTF16("Smith"));
-  profile->SetRawMultiInfo(NAME_LAST, names);
+  profile->SetRawInfo(NAME_FULL, ASCIIToUTF16("John K. Doe, Jr."));
+  profile->SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  profile->SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("K."));
+  profile->SetRawInfo(NAME_LAST, ASCIIToUTF16("Doe"));
 
-  std::vector<base::string16> emails;
-  emails.push_back(ASCIIToUTF16("user@example.com"));
-  emails.push_back(ASCIIToUTF16("superuser@example.org"));
-  profile->SetRawMultiInfo(EMAIL_ADDRESS, emails);
-
-  std::vector<base::string16> phones;
-  phones.push_back(ASCIIToUTF16("1.800.555.1234"));
-  phones.push_back(ASCIIToUTF16("1.866.650.0000"));
-  profile->SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, phones);
+  profile->SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("user@example.com"));
+  profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("1.800.555.1234"));
 
   profile->SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
                       ASCIIToUTF16("123 Fake St.\n"
@@ -199,16 +180,9 @@
   specifics->add_name_last("Doe");
   specifics->add_name_full("John K. Doe, Jr.");
 
-  specifics->add_name_first("Jane");
-  specifics->add_name_middle("Luise");
-  specifics->add_name_last("Smith");
-  specifics->add_name_full("Jane Luise Smith MD");
-
   specifics->add_email_address("user@example.com");
-  specifics->add_email_address("superuser@example.org");
 
   specifics->add_phone_home_whole_number("1.800.555.1234");
-  specifics->add_phone_home_whole_number("1.866.650.0000");
 
   specifics->set_address_home_line1("123 Fake St.");
   specifics->set_address_home_line2("Apt. 42");
@@ -614,155 +588,62 @@
   EXPECT_EQ(profile.GetRawInfo(COMPANY_NAME), ASCIIToUTF16(company2));
 }
 
-TEST_F(AutofillProfileSyncableServiceTest, UpdateMultivaluedField) {
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
-
-  std::vector<base::string16> values;
-  values.push_back(ASCIIToUTF16("1@1.com"));
-  values.push_back(ASCIIToUTF16("2@1.com"));
-  profile.SetRawMultiInfo(EMAIL_ADDRESS, values);
-
-  ::google::protobuf::RepeatedPtrField<std::string> specifics_fields;
-  specifics_fields.AddAllocated(new std::string("2@1.com"));
-  specifics_fields.AddAllocated(new std::string("3@1.com"));
-
-  EXPECT_TRUE(AutofillProfileSyncableService::UpdateMultivaluedField(
-      EMAIL_ADDRESS, specifics_fields, &profile));
-  profile.GetRawMultiInfo(EMAIL_ADDRESS, &values);
-  ASSERT_TRUE(values.size() == 2);
-  EXPECT_EQ(values[0], ASCIIToUTF16("2@1.com"));
-  EXPECT_EQ(values[1], ASCIIToUTF16("3@1.com"));
-
-  EXPECT_FALSE(AutofillProfileSyncableService::UpdateMultivaluedField(
-      EMAIL_ADDRESS, specifics_fields, &profile));
-  profile.GetRawMultiInfo(EMAIL_ADDRESS, &values);
-  ASSERT_EQ(values.size(), 2U);
-  EXPECT_EQ(values[0], ASCIIToUTF16("2@1.com"));
-  EXPECT_EQ(values[1], ASCIIToUTF16("3@1.com"));
-  EXPECT_TRUE(AutofillProfileSyncableService::UpdateMultivaluedField(
-      EMAIL_ADDRESS, ::google::protobuf::RepeatedPtrField<std::string>(),
-      &profile));
-  profile.GetRawMultiInfo(EMAIL_ADDRESS, &values);
-  ASSERT_EQ(values.size(), 1U);  // Always have at least an empty string.
-  EXPECT_EQ(values[0], ASCIIToUTF16(""));
-}
-
 TEST_F(AutofillProfileSyncableServiceTest, MergeProfile) {
   AutofillProfile profile1(kGuid1, kHttpOrigin);
   profile1.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("111 First St."));
 
-  std::vector<base::string16> values;
-  values.push_back(ASCIIToUTF16("1@1.com"));
-  values.push_back(ASCIIToUTF16("2@1.com"));
-  profile1.SetRawMultiInfo(EMAIL_ADDRESS, values);
-
   AutofillProfile profile2(kGuid2, kHttpsOrigin);
   profile2.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("111 First St."));
 
-  // |values| now is [ "1@1.com", "2@1.com", "3@1.com" ].
-  values.push_back(ASCIIToUTF16("3@1.com"));
-  profile2.SetRawMultiInfo(EMAIL_ADDRESS, values);
+  profile1.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("1@1.com"));
+  profile2.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("1@1.com"));
 
-  values.clear();
-  values.push_back(ASCIIToUTF16("John"));
-  profile1.SetRawMultiInfo(NAME_FIRST, values);
-  values.push_back(ASCIIToUTF16("Jane"));
-  profile2.SetRawMultiInfo(NAME_FIRST, values);
+  profile1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  profile2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
 
-  values.clear();
-  values.push_back(ASCIIToUTF16("Doe"));
-  profile1.SetRawMultiInfo(NAME_LAST, values);
-  values.push_back(ASCIIToUTF16("Other"));
-  profile2.SetRawMultiInfo(NAME_LAST, values);
+  profile1.SetRawInfo(NAME_LAST, ASCIIToUTF16("Doe"));
+  profile2.SetRawInfo(NAME_LAST, ASCIIToUTF16("Doe"));
 
-  values.clear();
-  values.push_back(ASCIIToUTF16("650234567"));
-  profile2.SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, values);
+  profile2.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("650234567"));
 
   profile1.set_language_code("en");
 
-  EXPECT_FALSE(AutofillProfileSyncableService::MergeProfile(profile2,
-                                                            &profile1,
+  EXPECT_FALSE(AutofillProfileSyncableService::MergeProfile(profile2, &profile1,
                                                             "en-US"));
 
   // The more recent use_date is maintained and synced back.
   profile2.set_use_date(base::Time::FromTimeT(30));
   profile1.set_use_date(base::Time::FromTimeT(25));
-  EXPECT_FALSE(AutofillProfileSyncableService::MergeProfile(profile2,
-                                                            &profile1,
+  EXPECT_FALSE(AutofillProfileSyncableService::MergeProfile(profile2, &profile1,
                                                             "en-US"));
   EXPECT_EQ(base::Time::FromTimeT(30), profile1.use_date());
   profile1.set_use_date(base::Time::FromTimeT(35));
-  EXPECT_TRUE(AutofillProfileSyncableService::MergeProfile(profile2,
-                                                           &profile1,
+  EXPECT_TRUE(AutofillProfileSyncableService::MergeProfile(profile2, &profile1,
                                                            "en-US"));
   EXPECT_EQ(base::Time::FromTimeT(35), profile1.use_date());
 
-  profile1.GetRawMultiInfo(NAME_FIRST, &values);
-  ASSERT_EQ(values.size(), 2U);
-  EXPECT_EQ(values[0], ASCIIToUTF16("John"));
-  EXPECT_EQ(values[1], ASCIIToUTF16("Jane"));
-
-  profile1.GetRawMultiInfo(NAME_LAST, &values);
-  ASSERT_EQ(values.size(), 2U);
-  EXPECT_EQ(values[0], ASCIIToUTF16("Doe"));
-  EXPECT_EQ(values[1], ASCIIToUTF16("Other"));
-
-  profile1.GetRawMultiInfo(EMAIL_ADDRESS, &values);
-  ASSERT_EQ(values.size(), 3U);
-  EXPECT_EQ(values[0], ASCIIToUTF16("1@1.com"));
-  EXPECT_EQ(values[1], ASCIIToUTF16("2@1.com"));
-  EXPECT_EQ(values[2], ASCIIToUTF16("3@1.com"));
-
-  profile1.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &values);
-  ASSERT_EQ(values.size(), 1U);
-  EXPECT_EQ(values[0], ASCIIToUTF16("650234567"));
+  EXPECT_EQ(ASCIIToUTF16("John"), profile1.GetRawInfo(NAME_FIRST));
+  EXPECT_EQ(ASCIIToUTF16("Doe"), profile1.GetRawInfo(NAME_LAST));
+  EXPECT_EQ(ASCIIToUTF16("1@1.com"), profile1.GetRawInfo(EMAIL_ADDRESS));
+  EXPECT_EQ(ASCIIToUTF16("650234567"),
+            profile1.GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
 
   EXPECT_EQ(profile2.origin(), profile1.origin());
 
   AutofillProfile profile3(kGuid3, kHttpOrigin);
   profile3.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("111 First St."));
-
-  values.clear();
-  values.push_back(ASCIIToUTF16("Jane"));
-  profile3.SetRawMultiInfo(NAME_FIRST, values);
-
-  values.clear();
-  values.push_back(ASCIIToUTF16("Doe"));
-  profile3.SetRawMultiInfo(NAME_LAST, values);
+  profile3.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
+  profile3.SetRawInfo(NAME_LAST, ASCIIToUTF16("Doe"));
 
   EXPECT_TRUE(AutofillProfileSyncableService::MergeProfile(profile3,
                                                            &profile1,
                                                            "en-US"));
 
-  profile1.GetRawMultiInfo(NAME_FIRST, &values);
-  ASSERT_EQ(values.size(), 3U);
-  EXPECT_EQ(values[0], ASCIIToUTF16("John"));
-  EXPECT_EQ(values[1], ASCIIToUTF16("Jane"));
-  EXPECT_EQ(values[2], ASCIIToUTF16("Jane"));
-
-  profile1.GetRawMultiInfo(NAME_LAST, &values);
-  ASSERT_EQ(values.size(), 3U);
-  EXPECT_EQ(values[0], ASCIIToUTF16("Doe"));
-  EXPECT_EQ(values[1], ASCIIToUTF16("Other"));
-  EXPECT_EQ(values[2], ASCIIToUTF16("Doe"));
-
-  // Middle name should have three entries as well.
-  profile1.GetRawMultiInfo(NAME_MIDDLE, &values);
-  ASSERT_EQ(values.size(), 3U);
-  EXPECT_TRUE(values[0].empty());
-  EXPECT_TRUE(values[1].empty());
-  EXPECT_TRUE(values[2].empty());
-
-  profile1.GetRawMultiInfo(EMAIL_ADDRESS, &values);
-  ASSERT_EQ(values.size(), 3U);
-  EXPECT_EQ(values[0], ASCIIToUTF16("1@1.com"));
-  EXPECT_EQ(values[1], ASCIIToUTF16("2@1.com"));
-  EXPECT_EQ(values[2], ASCIIToUTF16("3@1.com"));
-
-  profile1.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &values);
-  ASSERT_EQ(values.size(), 1U);
-  EXPECT_EQ(values[0], ASCIIToUTF16("650234567"));
+  EXPECT_EQ(ASCIIToUTF16("Jane"), profile1.GetRawInfo(NAME_FIRST));
+  EXPECT_EQ(ASCIIToUTF16("Doe"), profile1.GetRawInfo(NAME_LAST));
+  EXPECT_EQ(ASCIIToUTF16("1@1.com"), profile1.GetRawInfo(EMAIL_ADDRESS));
+  EXPECT_EQ(ASCIIToUTF16("650234567"),
+            profile1.GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
 }
 
 // Ensure that all profile fields are able to be synced up from the client to
@@ -1174,8 +1055,7 @@
 
   // Local autofill profile has a full name.
   AutofillProfile profile(kGuid1, kHttpsOrigin);
-  profile.SetInfo(AutofillType(NAME_FULL),
-                  ASCIIToUTF16("John Jacob Smith, Jr"), "en-US");
+  profile.SetRawInfo(NAME_FULL, ASCIIToUTF16("John Jacob Smith, Jr"));
   profiles_from_web_db.push_back(new AutofillProfile(profile));
 
   // Remote data does not have a full name value.
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc
index 3f5a4c2..b9468bb 100644
--- a/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -214,10 +214,16 @@
   if (!s.Succeeded())
     return false;
 
-  profile->SetRawMultiInfo(NAME_FIRST, first_names);
-  profile->SetRawMultiInfo(NAME_MIDDLE, middle_names);
-  profile->SetRawMultiInfo(NAME_LAST, last_names);
-  profile->SetRawMultiInfo(NAME_FULL, full_names);
+  // TODO(estade): update schema so these aren't vectors.
+  first_names.resize(1);
+  middle_names.resize(1);
+  last_names.resize(1);
+  full_names.resize(1);
+
+  profile->SetRawInfo(NAME_FIRST, first_names[0]);
+  profile->SetRawInfo(NAME_MIDDLE, middle_names[0]);
+  profile->SetRawInfo(NAME_LAST, last_names[0]);
+  profile->SetRawInfo(NAME_FULL, full_names[0]);
   return true;
 }
 
@@ -240,7 +246,9 @@
   if (!s.Succeeded())
     return false;
 
-  profile->SetRawMultiInfo(EMAIL_ADDRESS, emails);
+  // TODO(estade): update schema so this is not a vector.
+  emails.resize(1);
+  profile->SetRawInfo(EMAIL_ADDRESS, emails[0]);
   return true;
 }
 
@@ -263,82 +271,52 @@
   if (!s.Succeeded())
     return false;
 
-  profile->SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, numbers);
+  // TODO(estade): update schema so this isn't a vector.
+  numbers.resize(1);
+  profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, numbers[0]);
   return true;
 }
 
 bool AddAutofillProfileNames(const AutofillProfile& profile,
                              sql::Connection* db) {
-  std::vector<base::string16> first_names;
-  profile.GetRawMultiInfo(NAME_FIRST, &first_names);
-  std::vector<base::string16> middle_names;
-  profile.GetRawMultiInfo(NAME_MIDDLE, &middle_names);
-  std::vector<base::string16> last_names;
-  profile.GetRawMultiInfo(NAME_LAST, &last_names);
-  std::vector<base::string16> full_names;
-  profile.GetRawMultiInfo(NAME_FULL, &full_names);
-  DCHECK_EQ(first_names.size(), middle_names.size());
-  DCHECK_EQ(first_names.size(), last_names.size());
-  DCHECK_EQ(first_names.size(), full_names.size());
+  // Add the new name.
+  sql::Statement s(db->GetUniqueStatement(
+      "INSERT INTO autofill_profile_names"
+      " (guid, first_name, middle_name, last_name, full_name) "
+      "VALUES (?,?,?,?,?)"));
+  s.BindString(0, profile.guid());
+  s.BindString16(1, profile.GetRawInfo(NAME_FIRST));
+  s.BindString16(2, profile.GetRawInfo(NAME_MIDDLE));
+  s.BindString16(3, profile.GetRawInfo(NAME_LAST));
+  s.BindString16(4, profile.GetRawInfo(NAME_FULL));
 
-  for (size_t i = 0; i < first_names.size(); ++i) {
-    // Add the new name.
-    sql::Statement s(db->GetUniqueStatement(
-        "INSERT INTO autofill_profile_names"
-        " (guid, first_name, middle_name, last_name, full_name) "
-        "VALUES (?,?,?,?,?)"));
-    s.BindString(0, profile.guid());
-    s.BindString16(1, first_names[i]);
-    s.BindString16(2, middle_names[i]);
-    s.BindString16(3, last_names[i]);
-    s.BindString16(4, full_names[i]);
-
-    if (!s.Run())
-      return false;
-  }
-  return true;
+  return s.Run();
 }
 
 bool AddAutofillProfileEmails(const AutofillProfile& profile,
                               sql::Connection* db) {
-  std::vector<base::string16> emails;
-  profile.GetRawMultiInfo(EMAIL_ADDRESS, &emails);
-
-  for (size_t i = 0; i < emails.size(); ++i) {
-    // Add the new email.
-    sql::Statement s(db->GetUniqueStatement(
+  // Add the new email.
+  sql::Statement s(db->GetUniqueStatement(
       "INSERT INTO autofill_profile_emails"
       " (guid, email) "
       "VALUES (?,?)"));
-    s.BindString(0, profile.guid());
-    s.BindString16(1, emails[i]);
+  s.BindString(0, profile.guid());
+  s.BindString16(1, profile.GetRawInfo(EMAIL_ADDRESS));
 
-    if (!s.Run())
-      return false;
-  }
-
-  return true;
+  return s.Run();
 }
 
 bool AddAutofillProfilePhones(const AutofillProfile& profile,
                               sql::Connection* db) {
-  std::vector<base::string16> numbers;
-  profile.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &numbers);
-
-  for (size_t i = 0; i < numbers.size(); ++i) {
-    // Add the new number.
-    sql::Statement s(db->GetUniqueStatement(
+  // Add the new number.
+  sql::Statement s(db->GetUniqueStatement(
       "INSERT INTO autofill_profile_phones"
       " (guid, number) "
       "VALUES (?,?)"));
-    s.BindString(0, profile.guid());
-    s.BindString16(1, numbers[i]);
+  s.BindString(0, profile.guid());
+  s.BindString16(1, profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
 
-    if (!s.Run())
-      return false;
-  }
-
-  return true;
+  return s.Run();
 }
 
 bool AddAutofillProfilePieces(const AutofillProfile& profile,
diff --git a/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/components/autofill/core/browser/webdata/autofill_table_unittest.cc
index b1b87317..f3cf200 100644
--- a/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -759,120 +759,6 @@
   EXPECT_FALSE(table_->GetAutofillProfile(billing_profile.guid(), &db_profile));
 }
 
-TEST_F(AutofillTableTest, AutofillProfileMultiValueNames) {
-  AutofillProfile p;
-  const base::string16 kJohnDoe(ASCIIToUTF16("John Doe"));
-  const base::string16 kJohnPDoe(ASCIIToUTF16("John P. Doe"));
-  std::vector<base::string16> set_values;
-  set_values.push_back(kJohnDoe);
-  set_values.push_back(kJohnPDoe);
-  p.SetRawMultiInfo(NAME_FULL, set_values);
-
-  EXPECT_TRUE(table_->AddAutofillProfile(p));
-
-  AutofillProfile* db_profile;
-  ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
-  EXPECT_EQ(p, *db_profile);
-  EXPECT_EQ(0, p.Compare(*db_profile));
-  delete db_profile;
-
-  // Update the values.
-  const base::string16 kNoOne(ASCIIToUTF16("No One"));
-  set_values[1] = kNoOne;
-  p.SetRawMultiInfo(NAME_FULL, set_values);
-  EXPECT_TRUE(table_->UpdateAutofillProfile(p));
-  ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
-  EXPECT_EQ(p, *db_profile);
-  EXPECT_EQ(0, p.Compare(*db_profile));
-  delete db_profile;
-
-  // Delete values.
-  set_values.clear();
-  p.SetRawMultiInfo(NAME_FULL, set_values);
-  EXPECT_TRUE(table_->UpdateAutofillProfile(p));
-  ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
-  EXPECT_EQ(p, *db_profile);
-  EXPECT_EQ(0, p.Compare(*db_profile));
-  EXPECT_EQ(base::string16(), db_profile->GetRawInfo(NAME_FULL));
-  delete db_profile;
-}
-
-TEST_F(AutofillTableTest, AutofillProfileMultiValueEmails) {
-  AutofillProfile p;
-  const base::string16 kJohnDoe(ASCIIToUTF16("john@doe.com"));
-  const base::string16 kJohnPDoe(ASCIIToUTF16("john_p@doe.com"));
-  std::vector<base::string16> set_values;
-  set_values.push_back(kJohnDoe);
-  set_values.push_back(kJohnPDoe);
-  p.SetRawMultiInfo(EMAIL_ADDRESS, set_values);
-
-  EXPECT_TRUE(table_->AddAutofillProfile(p));
-
-  AutofillProfile* db_profile;
-  ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
-  EXPECT_EQ(p, *db_profile);
-  EXPECT_EQ(0, p.Compare(*db_profile));
-  delete db_profile;
-
-  // Update the values.
-  const base::string16 kNoOne(ASCIIToUTF16("no@one.com"));
-  set_values[1] = kNoOne;
-  p.SetRawMultiInfo(EMAIL_ADDRESS, set_values);
-  EXPECT_TRUE(table_->UpdateAutofillProfile(p));
-  ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
-  EXPECT_EQ(p, *db_profile);
-  EXPECT_EQ(0, p.Compare(*db_profile));
-  delete db_profile;
-
-  // Delete values.
-  set_values.clear();
-  p.SetRawMultiInfo(EMAIL_ADDRESS, set_values);
-  EXPECT_TRUE(table_->UpdateAutofillProfile(p));
-  ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
-  EXPECT_EQ(p, *db_profile);
-  EXPECT_EQ(0, p.Compare(*db_profile));
-  EXPECT_EQ(base::string16(), db_profile->GetRawInfo(EMAIL_ADDRESS));
-  delete db_profile;
-}
-
-TEST_F(AutofillTableTest, AutofillProfileMultiValuePhone) {
-  AutofillProfile p;
-  const base::string16 kJohnDoe(ASCIIToUTF16("4151112222"));
-  const base::string16 kJohnPDoe(ASCIIToUTF16("4151113333"));
-  std::vector<base::string16> set_values;
-  set_values.push_back(kJohnDoe);
-  set_values.push_back(kJohnPDoe);
-  p.SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
-
-  EXPECT_TRUE(table_->AddAutofillProfile(p));
-
-  AutofillProfile* db_profile;
-  ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
-  EXPECT_EQ(p, *db_profile);
-  EXPECT_EQ(0, p.Compare(*db_profile));
-  delete db_profile;
-
-  // Update the values.
-  const base::string16 kNoOne(ASCIIToUTF16("4151110000"));
-  set_values[1] = kNoOne;
-  p.SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
-  EXPECT_TRUE(table_->UpdateAutofillProfile(p));
-  ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
-  EXPECT_EQ(p, *db_profile);
-  EXPECT_EQ(0, p.Compare(*db_profile));
-  delete db_profile;
-
-  // Delete values.
-  set_values.clear();
-  p.SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, set_values);
-  EXPECT_TRUE(table_->UpdateAutofillProfile(p));
-  ASSERT_TRUE(table_->GetAutofillProfile(p.guid(), &db_profile));
-  EXPECT_EQ(p, *db_profile);
-  EXPECT_EQ(0, p.Compare(*db_profile));
-  EXPECT_EQ(base::string16(), db_profile->GetRawInfo(EMAIL_ADDRESS));
-  delete db_profile;
-}
-
 TEST_F(AutofillTableTest, AutofillProfileTrash) {
   std::vector<std::string> guids;
   table_->GetAutofillProfilesInTrash(&guids);
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc
new file mode 100644
index 0000000..dae6d71
--- /dev/null
+++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc
@@ -0,0 +1,460 @@
+// 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/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "components/autofill/core/browser/autofill_data_model.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/webdata/autofill_change.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "sync/api/sync_change.h"
+#include "sync/api/sync_error_factory.h"
+#include "sync/protocol/autofill_specifics.pb.h"
+#include "sync/protocol/sync.pb.h"
+
+namespace autofill {
+
+namespace {
+
+void* UserDataKey() {
+  // Use the address of a static so that COMDAT folding won't ever fold
+  // with something else.
+  static int user_data_key = 0;
+  return reinterpret_cast<void*>(&user_data_key);
+}
+
+// Returns syncable metadata for the |local| profile or credit card.
+syncer::SyncData BuildSyncData(sync_pb::WalletMetadataSpecifics::Type type,
+                               const std::string& server_id,
+                               const AutofillDataModel& local) {
+  sync_pb::EntitySpecifics entity;
+  sync_pb::WalletMetadataSpecifics* metadata = entity.mutable_wallet_metadata();
+  metadata->set_type(type);
+  metadata->set_id(server_id);
+  metadata->set_use_count(local.use_count());
+  metadata->set_use_date(local.use_date().ToInternalValue());
+
+  std::string sync_tag;
+  switch (type) {
+    case sync_pb::WalletMetadataSpecifics::ADDRESS:
+      sync_tag = "address-" + server_id;
+      break;
+    case sync_pb::WalletMetadataSpecifics::CARD:
+      sync_tag = "card-" + server_id;
+      break;
+    case sync_pb::WalletMetadataSpecifics::UNKNOWN:
+      NOTREACHED();
+      break;
+  }
+
+  return syncer::SyncData::CreateLocalData(sync_tag, sync_tag, entity);
+}
+
+}  // namespace
+
+AutofillWalletMetadataSyncableService::
+    ~AutofillWalletMetadataSyncableService() {
+}
+
+syncer::SyncMergeResult
+AutofillWalletMetadataSyncableService::MergeDataAndStartSyncing(
+    syncer::ModelType type,
+    const syncer::SyncDataList& initial_sync_data,
+    scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
+    scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(!sync_processor_);
+  DCHECK(!sync_error_factory_);
+  DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, type);
+
+  sync_processor_ = sync_processor.Pass();
+  sync_error_factory_ = sync_error_factory.Pass();
+
+  return MergeData(initial_sync_data);
+}
+
+void AutofillWalletMetadataSyncableService::StopSyncing(
+    syncer::ModelType type) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, type);
+
+  sync_processor_.reset();
+  sync_error_factory_.reset();
+  cache_.clear();
+}
+
+syncer::SyncDataList AutofillWalletMetadataSyncableService::GetAllSyncData(
+    syncer::ModelType type) const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, type);
+
+  syncer::SyncDataList data_list;
+  std::map<std::string, AutofillProfile*> profiles;
+  std::map<std::string, CreditCard*> cards;
+  if (GetLocalData(&profiles, &cards)) {
+    for (const auto& it : profiles) {
+      data_list.push_back(BuildSyncData(
+          sync_pb::WalletMetadataSpecifics::ADDRESS, it.first, *it.second));
+    }
+
+    for (const auto& it : cards) {
+      data_list.push_back(BuildSyncData(sync_pb::WalletMetadataSpecifics::CARD,
+                                        it.first, *it.second));
+    }
+  }
+
+  return data_list;
+}
+
+syncer::SyncError AutofillWalletMetadataSyncableService::ProcessSyncChanges(
+    const tracked_objects::Location& from_here,
+    const syncer::SyncChangeList& changes_from_sync) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  cache_.clear();
+
+  std::map<std::string, AutofillProfile*> profiles;
+  std::map<std::string, CreditCard*> cards;
+  GetLocalData(&profiles, &cards);
+
+  base::Callback<bool(const AutofillProfile&)> address_updater =
+      base::Bind(&AutofillWalletMetadataSyncableService::UpdateAddressStats,
+                 base::Unretained(this));
+  base::Callback<bool(const CreditCard&)> card_updater =
+      base::Bind(&AutofillWalletMetadataSyncableService::UpdateCardStats,
+                 base::Unretained(this));
+
+  syncer::SyncChangeList changes_to_sync;
+  for (const syncer::SyncChange& change : changes_from_sync) {
+    const sync_pb::WalletMetadataSpecifics& remote_metadata =
+        change.sync_data().GetSpecifics().wallet_metadata();
+    switch (change.change_type()) {
+      // Do not immediately delete data.
+      case syncer::SyncChange::ACTION_ADD:
+      // Intentional fall through.
+      case syncer::SyncChange::ACTION_UPDATE:
+        switch (remote_metadata.type()) {
+          case sync_pb::WalletMetadataSpecifics::ADDRESS:
+            MergeRemote(change.sync_data(), address_updater, &profiles,
+                        &changes_to_sync);
+            break;
+
+          case sync_pb::WalletMetadataSpecifics::CARD:
+            MergeRemote(change.sync_data(), card_updater, &cards,
+                        &changes_to_sync);
+            break;
+
+          case sync_pb::WalletMetadataSpecifics::UNKNOWN:
+            NOTREACHED();
+            break;
+        }
+        break;
+
+      // Undelete data immediately.
+      case syncer::SyncChange::ACTION_DELETE:
+        switch (remote_metadata.type()) {
+          case sync_pb::WalletMetadataSpecifics::ADDRESS: {
+            const auto& it = profiles.find(remote_metadata.id());
+            if (it != profiles.end()) {
+              cache_.push_back(
+                  BuildSyncData(sync_pb::WalletMetadataSpecifics::ADDRESS,
+                                it->first, *it->second));
+              changes_to_sync.push_back(syncer::SyncChange(
+                  FROM_HERE, syncer::SyncChange::ACTION_ADD, cache_.back()));
+              profiles.erase(it);
+            }
+            break;
+          }
+
+          case sync_pb::WalletMetadataSpecifics::CARD: {
+            const auto& it = cards.find(remote_metadata.id());
+            if (it != cards.end()) {
+              cache_.push_back(
+                  BuildSyncData(sync_pb::WalletMetadataSpecifics::CARD,
+                                it->first, *it->second));
+              changes_to_sync.push_back(syncer::SyncChange(
+                  FROM_HERE, syncer::SyncChange::ACTION_ADD, cache_.back()));
+              cards.erase(it);
+            }
+            break;
+          }
+
+          case sync_pb::WalletMetadataSpecifics::UNKNOWN:
+            NOTREACHED();
+            break;
+        }
+        break;
+
+      case syncer::SyncChange::ACTION_INVALID:
+        NOTREACHED();
+        break;
+    }
+  }
+
+  // The remainder of |profiles| were not listed in |changes_from_sync|.
+  for (const auto& it : profiles) {
+    cache_.push_back(BuildSyncData(sync_pb::WalletMetadataSpecifics::ADDRESS,
+                                   it.first, *it.second));
+  }
+
+  // The remainder of |cards| were not listed in |changes_from_sync|.
+  for (const auto& it : cards) {
+    cache_.push_back(BuildSyncData(sync_pb::WalletMetadataSpecifics::CARD,
+                                   it.first, *it.second));
+  }
+
+  syncer::SyncError status;
+  if (!changes_to_sync.empty())
+    status = SendChangesToSyncServer(changes_to_sync);
+
+  return status;
+}
+
+void AutofillWalletMetadataSyncableService::AutofillProfileChanged(
+    const AutofillProfileChange& change) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (sync_processor_ && change.profile() &&
+      change.profile()->record_type() == AutofillProfile::SERVER_PROFILE) {
+    AutofillDataModelChanged(change.profile()->server_id(), *change.profile());
+  }
+}
+
+void AutofillWalletMetadataSyncableService::CreditCardChanged(
+    const CreditCardChange& change) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (sync_processor_ && change.card() &&
+      change.card()->record_type() != CreditCard::LOCAL_CARD) {
+    AutofillDataModelChanged(change.card()->server_id(), *change.card());
+  }
+}
+
+void AutofillWalletMetadataSyncableService::AutofillMultipleChanged() {
+  // Merging data will clear the cache, so make a copy to avoid merging with
+  // empty remote data. Copying the cache is expensive, but still cheaper than
+  // GetAllSyncData().
+  if (sync_processor_)
+    MergeData(syncer::SyncDataList(cache_));
+}
+
+// static
+void AutofillWalletMetadataSyncableService::CreateForWebDataServiceAndBackend(
+    AutofillWebDataService* web_data_service,
+    AutofillWebDataBackend* webdata_backend,
+    const std::string& app_locale) {
+  web_data_service->GetDBUserData()->SetUserData(
+      UserDataKey(),
+      new AutofillWalletMetadataSyncableService(webdata_backend, app_locale));
+}
+
+// static
+AutofillWalletMetadataSyncableService*
+AutofillWalletMetadataSyncableService::FromWebDataService(
+    AutofillWebDataService* web_data_service) {
+  return static_cast<AutofillWalletMetadataSyncableService*>(
+      web_data_service->GetDBUserData()->GetUserData(UserDataKey()));
+}
+
+AutofillWalletMetadataSyncableService::AutofillWalletMetadataSyncableService(
+    AutofillWebDataBackend* webdata_backend,
+    const std::string& app_locale)
+    : webdata_backend_(webdata_backend), scoped_observer_(this) {
+  // No webdata in tests.
+  if (webdata_backend_)
+    scoped_observer_.Add(webdata_backend_);
+}
+
+bool AutofillWalletMetadataSyncableService::GetLocalData(
+    std::map<std::string, AutofillProfile*>* profiles,
+    std::map<std::string, CreditCard*>* cards) const {
+  std::vector<AutofillProfile*> profile_list;
+  bool success = AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase())
+                     ->GetServerProfiles(&profile_list);
+  for (AutofillProfile* profile : profile_list)
+    profiles->insert(std::make_pair(profile->server_id(), profile));
+
+  std::vector<CreditCard*> card_list;
+  success &= AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase())
+                 ->GetServerCreditCards(&card_list);
+  for (CreditCard* card : card_list)
+    cards->insert(std::make_pair(card->server_id(), card));
+
+  return success;
+}
+
+bool AutofillWalletMetadataSyncableService::UpdateAddressStats(
+    const AutofillProfile& profile) {
+  return AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase())
+      ->UpdateServerAddressUsageStats(profile);
+}
+
+bool AutofillWalletMetadataSyncableService::UpdateCardStats(
+    const CreditCard& credit_card) {
+  return AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase())
+      ->UpdateServerCardUsageStats(credit_card);
+}
+
+syncer::SyncError
+AutofillWalletMetadataSyncableService::SendChangesToSyncServer(
+    const syncer::SyncChangeList& changes_to_sync) {
+  DCHECK(sync_processor_);
+  return sync_processor_->ProcessSyncChanges(FROM_HERE, changes_to_sync);
+}
+
+syncer::SyncMergeResult AutofillWalletMetadataSyncableService::MergeData(
+    const syncer::SyncDataList& sync_data) {
+  cache_.clear();
+
+  std::map<std::string, AutofillProfile*> profiles;
+  std::map<std::string, CreditCard*> cards;
+  GetLocalData(&profiles, &cards);
+
+  syncer::SyncMergeResult result(syncer::AUTOFILL_WALLET_METADATA);
+  result.set_num_items_before_association(profiles.size() + cards.size());
+
+  base::Callback<bool(const AutofillProfile&)> address_updater =
+      base::Bind(&AutofillWalletMetadataSyncableService::UpdateAddressStats,
+                 base::Unretained(this));
+  base::Callback<bool(const CreditCard&)> card_updater =
+      base::Bind(&AutofillWalletMetadataSyncableService::UpdateCardStats,
+                 base::Unretained(this));
+
+  syncer::SyncChangeList changes_to_sync;
+  for (const syncer::SyncData& remote : sync_data) {
+    DCHECK(remote.IsValid());
+    DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, remote.GetDataType());
+    switch (remote.GetSpecifics().wallet_metadata().type()) {
+      case sync_pb::WalletMetadataSpecifics::ADDRESS:
+        if (!MergeRemote(remote, address_updater, &profiles,
+                         &changes_to_sync)) {
+          changes_to_sync.push_back(syncer::SyncChange(
+              FROM_HERE, syncer::SyncChange::ACTION_DELETE, remote));
+        }
+        break;
+
+      case sync_pb::WalletMetadataSpecifics::CARD:
+        if (!MergeRemote(remote, card_updater, &cards, &changes_to_sync)) {
+          changes_to_sync.push_back(syncer::SyncChange(
+              FROM_HERE, syncer::SyncChange::ACTION_DELETE, remote));
+        }
+        break;
+
+      case sync_pb::WalletMetadataSpecifics::UNKNOWN:
+        NOTREACHED();
+        break;
+    }
+  }
+
+  // The remainder of |profiles| were not listed in |sync_data|.
+  for (const auto& it : profiles) {
+    cache_.push_back(BuildSyncData(sync_pb::WalletMetadataSpecifics::ADDRESS,
+                                   it.first, *it.second));
+    changes_to_sync.push_back(syncer::SyncChange(
+        FROM_HERE, syncer::SyncChange::ACTION_ADD, cache_.back()));
+  }
+
+  // The remainder of |cards| were not listed in |sync_data|.
+  for (const auto& it : cards) {
+    cache_.push_back(BuildSyncData(sync_pb::WalletMetadataSpecifics::CARD,
+                                   it.first, *it.second));
+    changes_to_sync.push_back(syncer::SyncChange(
+        FROM_HERE, syncer::SyncChange::ACTION_ADD, cache_.back()));
+  }
+
+  // Metadata is not added or deleted locally to maintain a 1:1 relationship
+  // with Wallet data.
+  result.set_num_items_after_association(result.num_items_before_association());
+  result.set_num_items_added(0);
+  result.set_num_items_deleted(0);
+
+  if (!changes_to_sync.empty())
+    result.set_error(SendChangesToSyncServer(changes_to_sync));
+
+  return result;
+}
+
+template <class DataType>
+bool AutofillWalletMetadataSyncableService::MergeRemote(
+    const syncer::SyncData& remote,
+    const base::Callback<bool(const DataType&)>& updater,
+    std::map<std::string, DataType*>* locals,
+    syncer::SyncChangeList* changes_to_sync) {
+  DCHECK(locals);
+  DCHECK(changes_to_sync);
+
+  const sync_pb::WalletMetadataSpecifics& remote_metadata =
+      remote.GetSpecifics().wallet_metadata();
+  auto it = locals->find(remote_metadata.id());
+  if (it == locals->end())
+    return false;
+
+  DataType* local_metadata = it->second;
+  locals->erase(it);
+
+  size_t remote_use_count = static_cast<size_t>(remote_metadata.use_count());
+  bool is_local_modified = false;
+  bool is_remote_outdated = false;
+  if (local_metadata->use_count() < remote_use_count) {
+    local_metadata->set_use_count(remote_use_count);
+    is_local_modified = true;
+  } else if (local_metadata->use_count() > remote_use_count) {
+    is_remote_outdated = true;
+  }
+
+  base::Time remote_use_date =
+      base::Time::FromInternalValue(remote_metadata.use_date());
+  if (local_metadata->use_date() < remote_use_date) {
+    local_metadata->set_use_date(remote_use_date);
+    is_local_modified = true;
+  } else if (local_metadata->use_date() > remote_use_date) {
+    is_remote_outdated = true;
+  }
+
+  if (is_remote_outdated) {
+    cache_.push_back(BuildSyncData(remote_metadata.type(), remote_metadata.id(),
+                                   *local_metadata));
+    changes_to_sync->push_back(syncer::SyncChange(
+        FROM_HERE, syncer::SyncChange::ACTION_UPDATE, cache_.back()));
+  } else {
+    cache_.push_back(remote);
+  }
+
+  if (is_local_modified)
+    updater.Run(*local_metadata);
+
+  return true;
+}
+
+void AutofillWalletMetadataSyncableService::AutofillDataModelChanged(
+    const std::string& server_id,
+    const AutofillDataModel& local) {
+  for (auto it = cache_.begin(); it != cache_.end(); ++it) {
+    const sync_pb::WalletMetadataSpecifics& remote =
+        it->GetSpecifics().wallet_metadata();
+    if (remote.id() == server_id) {
+      if (static_cast<size_t>(remote.use_count()) < local.use_count() &&
+          base::Time::FromInternalValue(remote.use_date()) < local.use_date()) {
+        *it = BuildSyncData(remote.type(), server_id, local);
+        SendChangesToSyncServer(syncer::SyncChangeList(
+            1, syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
+                                  *it)));
+      }
+
+      return;
+    }
+  }
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h
new file mode 100644
index 0000000..45a60ce0
--- /dev/null
+++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h
@@ -0,0 +1,150 @@
+// 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_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNCABLE_SERVICE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNCABLE_SERVICE_H_
+
+#include <map>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/scoped_observer.h"
+#include "base/supports_user_data.h"
+#include "base/threading/thread_checker.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
+#include "sync/api/sync_change_processor.h"
+#include "sync/api/sync_data.h"
+#include "sync/api/sync_error.h"
+#include "sync/api/sync_merge_result.h"
+#include "sync/api/syncable_service.h"
+
+namespace syncer {
+class SyncErrorFactory;
+}
+
+namespace tracked_objects {
+class Location;
+}
+
+namespace autofill {
+
+class AutofillDataModel;
+class AutofillProfile;
+class AutofillProfileChange;
+class AutofillWebDataBackend;
+class AutofillWebDataService;
+class CreditCard;
+class CreditCardChange;
+
+// Syncs usage counts and last use dates (metadata) for Wallet cards and
+// addresses (data). Creation and deletion of metadata on the sync server
+// follows the creation and deletion of the local metadata. (Local metadata has
+// 1:1 relationship with Wallet data.)
+class AutofillWalletMetadataSyncableService
+    : public base::SupportsUserData::Data,
+      public syncer::SyncableService,
+      public AutofillWebDataServiceObserverOnDBThread {
+ public:
+  ~AutofillWalletMetadataSyncableService() override;
+
+  // syncer::SyncableService implementation.
+  syncer::SyncMergeResult MergeDataAndStartSyncing(
+      syncer::ModelType type,
+      const syncer::SyncDataList& initial_sync_data,
+      scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
+      scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) override;
+  void StopSyncing(syncer::ModelType type) override;
+  syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override;
+  syncer::SyncError ProcessSyncChanges(
+      const tracked_objects::Location& from_here,
+      const syncer::SyncChangeList& changes_from_sync) override;
+
+  // AutofillWebDataServiceObserverOnDBThread implementation.
+  void AutofillProfileChanged(const AutofillProfileChange& change) override;
+  void CreditCardChanged(const CreditCardChange& change) override;
+  void AutofillMultipleChanged() override;
+
+  // Creates a new AutofillWalletMetadataSyncableService and hangs it off of
+  // |web_data_service|, which takes ownership. This method should only be
+  // called on |web_data_service|'s DB thread.
+  static void CreateForWebDataServiceAndBackend(
+      AutofillWebDataService* web_data_service,
+      AutofillWebDataBackend* webdata_backend,
+      const std::string& app_locale);
+
+  // Retrieves the AutofillWalletMetadataSyncableService stored on
+  // |web_data_service|.
+  static AutofillWalletMetadataSyncableService* FromWebDataService(
+      AutofillWebDataService* web_data_service);
+
+ protected:
+  AutofillWalletMetadataSyncableService(AutofillWebDataBackend* webdata_backend,
+                                        const std::string& app_locale);
+
+  // Populates the provided |profiles| and |cards| with mappings from server ID
+  // to unowned server profiles and server cards as read from disk. This data
+  // contains the usage stats. Returns true on success.
+  virtual bool GetLocalData(std::map<std::string, AutofillProfile*>* profiles,
+                            std::map<std::string, CreditCard*>* cards) const;
+
+  // Updates the stats for |profile| stored on disk. Does not trigger
+  // notifications that this profile was updated.
+  virtual bool UpdateAddressStats(const AutofillProfile& profile);
+
+  // Updates the stats for |credit_card| stored on disk. Does not trigger
+  // notifications that this credit card was updated.
+  virtual bool UpdateCardStats(const CreditCard& credit_card);
+
+  // Sends the |changes_to_sync| to the sync server.
+  virtual syncer::SyncError SendChangesToSyncServer(
+      const syncer::SyncChangeList& changes_to_sync);
+
+ private:
+  // Merges local metadata with |sync_data|.
+  //
+  // Sends an "update" to the sync server if |sync_data| contains metadata that
+  // is present locally, but local metadata has higher use count and later use
+  // date.
+  //
+  // Sends a "create" to the sync server if |sync_data| does not have some local
+  // metadata.
+  //
+  // Sends a "delete" to the sync server if |sync_data| contains metadata that
+  // is not present locally.
+  syncer::SyncMergeResult MergeData(const syncer::SyncDataList& sync_data);
+
+  // Merges |remote| metadata into a collection of metadata |locals|. Returns
+  // true if the corresponding local metadata was found.
+  //
+  // Stores an "update" in |changes_to_sync| if |remote| corresponds to an item
+  // in |locals| that has higher use count and later use date.
+  template <class DataType>
+  bool MergeRemote(const syncer::SyncData& remote,
+                   const base::Callback<bool(const DataType&)>& updater,
+                   std::map<std::string, DataType*>* locals,
+                   syncer::SyncChangeList* changes_to_sync);
+
+  // Sends updates to the sync server.
+  void AutofillDataModelChanged(const std::string& server_id,
+                                const AutofillDataModel& local);
+
+  base::ThreadChecker thread_checker_;
+  AutofillWebDataBackend* webdata_backend_;  // Weak ref.
+  ScopedObserver<AutofillWebDataBackend, AutofillWalletMetadataSyncableService>
+      scoped_observer_;
+  scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
+  scoped_ptr<syncer::SyncErrorFactory> sync_error_factory_;
+
+  // Cache of sync server data maintained to avoid expensive calls to
+  // GetAllSyncData().
+  syncer::SyncDataList cache_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillWalletMetadataSyncableService);
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNCABLE_SERVICE_H_
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc
new file mode 100644
index 0000000..3ee21e07
--- /dev/null
+++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc
@@ -0,0 +1,771 @@
+// 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/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "sync/api/sync_change.h"
+#include "sync/api/sync_change_processor_wrapper_for_test.h"
+#include "sync/api/sync_error_factory_mock.h"
+#include "sync/protocol/autofill_specifics.pb.h"
+#include "sync/protocol/sync.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+namespace {
+
+using testing::DoAll;
+using testing::ElementsAre;
+using testing::Invoke;
+using testing::NiceMock;
+using testing::Return;
+using testing::UnorderedElementsAre;
+using testing::Value;
+using testing::_;
+
+ACTION_P2(GetPointersTo, profiles, cards) {
+  for (auto& profile : *profiles)
+    arg0->insert(std::make_pair(profile.server_id(), &profile));
+
+  for (auto& card : *cards)
+    arg1->insert(std::make_pair(card.server_id(), &card));
+}
+
+ACTION_P(SaveDataIn, list) {
+  for (auto it = list->begin(); it != list->end(); ++it) {
+    if (it->server_id() == arg0.server_id()) {
+      *it = arg0;
+      return;
+    }
+  }
+
+  list->push_back(arg0);
+}
+
+// A syncable service for Wallet metadata that mocks out disk IO.
+class MockService : public AutofillWalletMetadataSyncableService {
+ public:
+  MockService()
+      : AutofillWalletMetadataSyncableService(nullptr, std::string()) {
+    ON_CALL(*this, GetLocalData(_, _))
+        .WillByDefault(DoAll(GetPointersTo(&server_profiles_, &server_cards_),
+                             Return(true)));
+
+    ON_CALL(*this, UpdateAddressStats(_))
+        .WillByDefault(DoAll(SaveDataIn(&server_profiles_), Return(true)));
+
+    ON_CALL(*this, UpdateCardStats(_))
+        .WillByDefault(DoAll(SaveDataIn(&server_cards_), Return(true)));
+
+    ON_CALL(*this, SendChangesToSyncServer(_))
+        .WillByDefault(
+            Invoke(this, &MockService::SendChangesToSyncServerConcrete));
+  }
+
+  ~MockService() override {}
+
+  MOCK_METHOD1(UpdateAddressStats, bool(const AutofillProfile&));
+  MOCK_METHOD1(UpdateCardStats, bool(const CreditCard&));
+  MOCK_METHOD1(SendChangesToSyncServer,
+               syncer::SyncError(const syncer::SyncChangeList&));
+
+  void ClearServerData() {
+    server_profiles_.clear();
+    server_cards_.clear();
+  }
+
+ private:
+  MOCK_CONST_METHOD2(GetLocalData,
+                     bool(std::map<std::string, AutofillProfile*>*,
+                          std::map<std::string, CreditCard*>*));
+
+  syncer::SyncError SendChangesToSyncServerConcrete(
+      const syncer::SyncChangeList& changes) {
+    return AutofillWalletMetadataSyncableService::SendChangesToSyncServer(
+        changes);
+  }
+
+  syncer::SyncDataList GetAllSyncDataConcrete(syncer::ModelType type) const {
+    return AutofillWalletMetadataSyncableService::GetAllSyncData(type);
+  }
+
+  std::vector<AutofillProfile> server_profiles_;
+  std::vector<CreditCard> server_cards_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockService);
+};
+
+// Verify that nothing is sent to the sync server when there's no metadata on
+// disk.
+TEST(AutofillWalletMetadataSyncableServiceTest, NoMetadataToReturn) {
+  EXPECT_TRUE(NiceMock<MockService>()
+                  .GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA)
+                  .empty());
+}
+
+AutofillProfile BuildAddress(const std::string& server_id,
+                             int64 use_count,
+                             int64 use_date) {
+  AutofillProfile profile(AutofillProfile::SERVER_PROFILE, server_id);
+  profile.set_use_count(use_count);
+  profile.set_use_date(base::Time::FromInternalValue(use_date));
+  return profile;
+}
+
+CreditCard BuildCard(const std::string& server_id,
+                     int64 use_count,
+                     int64 use_date) {
+  CreditCard card(CreditCard::MASKED_SERVER_CARD, server_id);
+  card.set_use_count(use_count);
+  card.set_use_date(base::Time::FromInternalValue(use_date));
+  return card;
+}
+
+MATCHER_P5(SyncDataMatches,
+           sync_tag,
+           metadata_type,
+           server_id,
+           use_count,
+           use_date,
+           "") {
+  return arg.IsValid() &&
+         syncer::AUTOFILL_WALLET_METADATA == arg.GetDataType() &&
+         sync_tag == syncer::SyncDataLocal(arg).GetTag() &&
+         metadata_type == arg.GetSpecifics().wallet_metadata().type() &&
+         server_id == arg.GetSpecifics().wallet_metadata().id() &&
+         use_count == arg.GetSpecifics().wallet_metadata().use_count() &&
+         use_date == arg.GetSpecifics().wallet_metadata().use_date();
+}
+
+// Verify that all metadata from disk is sent to the sync server.
+TEST(AutofillWalletMetadataSyncableServiceTest, ReturnAllMetadata) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+
+  EXPECT_THAT(
+      local.GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA),
+      UnorderedElementsAre(
+          SyncDataMatches("address-addr",
+                          sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 1,
+                          2),
+          SyncDataMatches("card-card", sync_pb::WalletMetadataSpecifics::CARD,
+                          "card", 3, 4)));
+}
+
+void MergeMetadata(MockService* local, MockService* remote) {
+  // The wrapper for |remote| gives it a null change processor, so sending
+  // changes is not possible.
+  ON_CALL(*remote, SendChangesToSyncServer(_))
+      .WillByDefault(Return(syncer::SyncError()));
+
+  scoped_ptr<syncer::SyncErrorFactoryMock> errors(
+      new syncer::SyncErrorFactoryMock);
+  EXPECT_CALL(*errors, CreateAndUploadError(_, _)).Times(0);
+  EXPECT_FALSE(
+      local->MergeDataAndStartSyncing(
+               syncer::AUTOFILL_WALLET_METADATA,
+               remote->GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA),
+               scoped_ptr<syncer::SyncChangeProcessor>(
+                   new syncer::SyncChangeProcessorWrapperForTest(remote)),
+               errors.Pass())
+          .error()
+          .IsSet());
+}
+
+// Verify that nothing is written to disk or sent to the sync server when two
+// empty clients are syncing.
+TEST(AutofillWalletMetadataSyncableServiceTest, TwoEmptyClients) {
+  NiceMock<MockService> local;
+  NiceMock<MockService> remote;
+
+  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
+  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
+  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
+
+  MergeMetadata(&local, &remote);
+}
+
+MATCHER_P2(SyncChangeMatches, change_type, sync_tag, "") {
+  return arg.IsValid() && change_type == arg.change_type() &&
+         sync_tag == syncer::SyncDataLocal(arg.sync_data()).GetTag() &&
+         syncer::AUTOFILL_WALLET_METADATA == arg.sync_data().GetDataType();
+}
+
+// Verify that remote data without local counterpart is deleted during the
+// initial merge.
+TEST(AutofillWalletMetadataSyncableServiceTest, DeleteFromServerOnMerge) {
+  NiceMock<MockService> local;
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+
+  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
+  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
+  EXPECT_CALL(
+      local,
+      SendChangesToSyncServer(UnorderedElementsAre(
+          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "address-addr"),
+          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "card-card"))));
+
+  MergeMetadata(&local, &remote);
+}
+
+MATCHER_P6(SyncChangeAndDataMatch,
+           change_type,
+           sync_tag,
+           metadata_type,
+           server_id,
+           use_count,
+           use_date,
+           "") {
+  return Value(arg, SyncChangeMatches(change_type, sync_tag)) &&
+         Value(arg.sync_data(),
+               SyncDataMatches(sync_tag, metadata_type, server_id, use_count,
+                               use_date));
+}
+
+// Verify that local data is sent to the sync server during the initial merge,
+// if the server does not have the data already.
+TEST(AutofillWalletMetadataSyncableServiceTest, AddToServerOnMerge) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+
+  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
+  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
+  EXPECT_CALL(local,
+              SendChangesToSyncServer(UnorderedElementsAre(
+                  SyncChangeAndDataMatch(
+                      syncer::SyncChange::ACTION_ADD, "address-addr",
+                      sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 1, 2),
+                  SyncChangeAndDataMatch(
+                      syncer::SyncChange::ACTION_ADD, "card-card",
+                      sync_pb::WalletMetadataSpecifics::CARD, "card", 3, 4))));
+
+  MergeMetadata(&local, &remote);
+}
+
+// Verify that no data is written to disk or sent to the sync server if the
+// local and remote data are identical during the initial merge.
+TEST(AutofillWalletMetadataSyncableServiceTest, IgnoreIdenticalValuesOnMerge) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+
+  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
+  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
+  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
+
+  MergeMetadata(&local, &remote);
+}
+
+MATCHER_P3(AutofillMetadataMatches, server_id, use_count, use_date, "") {
+  return arg.server_id() == server_id &&
+         arg.use_count() == static_cast<size_t>(use_count) &&
+         arg.use_date() == base::Time::FromInternalValue(use_date);
+}
+
+// Verify that remote data with higher values of use count and last use date is
+// saved to disk during the initial merge.
+TEST(AutofillWalletMetadataSyncableServiceTest,
+     SaveHigherValuesLocallyOnMerge) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 10, 20));
+  remote.UpdateCardStats(BuildCard("card", 30, 40));
+
+  EXPECT_CALL(local,
+              UpdateAddressStats(AutofillMetadataMatches("addr", 10, 20)));
+  EXPECT_CALL(local, UpdateCardStats(AutofillMetadataMatches("card", 30, 40)));
+  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
+
+  MergeMetadata(&local, &remote);
+}
+
+// Verify that local data with higher values of use count and last use date is
+// sent to the sync server during the initial merge.
+TEST(AutofillWalletMetadataSyncableServiceTest,
+     SendHigherValuesToServerOnMerge) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 10, 20));
+  local.UpdateCardStats(BuildCard("card", 30, 40));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+
+  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
+  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
+  EXPECT_CALL(
+      local, SendChangesToSyncServer(UnorderedElementsAre(
+                 SyncChangeAndDataMatch(
+                     syncer::SyncChange::ACTION_UPDATE, "address-addr",
+                     sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 10, 20),
+                 SyncChangeAndDataMatch(
+                     syncer::SyncChange::ACTION_UPDATE, "card-card",
+                     sync_pb::WalletMetadataSpecifics::CARD, "card", 30, 40))));
+
+  MergeMetadata(&local, &remote);
+}
+
+// Verify that lower values of metadata are not sent to the sync server when
+// local metadata is updated.
+TEST(AutofillWalletMetadataSyncableServiceTest,
+     DontSendLowerValueToServerOnSingleChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+  MergeMetadata(&local, &remote);
+  AutofillProfile address = BuildAddress("addr", 0, 0);
+  CreditCard card = BuildCard("card", 0, 0);
+
+  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
+
+  local.AutofillProfileChanged(AutofillProfileChange(
+      AutofillProfileChange::UPDATE, address.guid(), &address));
+  local.CreditCardChanged(
+      CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card));
+}
+
+// Verify that higher values of metadata are sent to the sync server when local
+// metadata is updated.
+TEST(AutofillWalletMetadataSyncableServiceTest,
+     SendHigherValuesToServerOnLocalSingleChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+  MergeMetadata(&local, &remote);
+  AutofillProfile address = BuildAddress("addr", 10, 20);
+  CreditCard card = BuildCard("card", 30, 40);
+
+  EXPECT_CALL(local,
+              SendChangesToSyncServer(ElementsAre(SyncChangeAndDataMatch(
+                  syncer::SyncChange::ACTION_UPDATE, "address-addr",
+                  sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 10, 20))));
+  EXPECT_CALL(local,
+              SendChangesToSyncServer(ElementsAre(SyncChangeAndDataMatch(
+                  syncer::SyncChange::ACTION_UPDATE, "card-card",
+                  sync_pb::WalletMetadataSpecifics::CARD, "card", 30, 40))));
+
+  local.AutofillProfileChanged(AutofillProfileChange(
+      AutofillProfileChange::UPDATE, address.guid(), &address));
+  local.CreditCardChanged(
+      CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card));
+}
+
+// Verify that one-off addition of metadata is not sent to the sync
+// server. Metadata add and delete trigger multiple changes notification
+// instead.
+TEST(AutofillWalletMetadataSyncableServiceTest, DontAddToServerOnSingleChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+  MergeMetadata(&local, &remote);
+  AutofillProfile address = BuildAddress("new-addr", 5, 6);
+  CreditCard card = BuildCard("new-card", 7, 8);
+
+  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
+
+  local.AutofillProfileChanged(AutofillProfileChange(
+      AutofillProfileChange::UPDATE, address.guid(), &address));
+  local.CreditCardChanged(
+      CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card));
+}
+
+// Verify that new metadata is sent to the sync server when multiple metadata
+// values change at once.
+TEST(AutofillWalletMetadataSyncableServiceTest, AddToServerOnMultiChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+  MergeMetadata(&local, &remote);
+  // These methods do not trigger notifications or sync:
+  local.UpdateAddressStats(BuildAddress("new-addr", 5, 6));
+  local.UpdateCardStats(BuildCard("new-card", 7, 8));
+
+  EXPECT_CALL(
+      local,
+      SendChangesToSyncServer(UnorderedElementsAre(
+          SyncChangeAndDataMatch(
+              syncer::SyncChange::ACTION_ADD, "address-new-addr",
+              sync_pb::WalletMetadataSpecifics::ADDRESS, "new-addr", 5, 6),
+          SyncChangeAndDataMatch(
+              syncer::SyncChange::ACTION_ADD, "card-new-card",
+              sync_pb::WalletMetadataSpecifics::CARD, "new-card", 7, 8))));
+
+  local.AutofillMultipleChanged();
+}
+
+// Verify that higher values of existing metadata are sent to the sync server
+// when multiple metadata values change at once.
+TEST(AutofillWalletMetadataSyncableServiceTest,
+     UpdateToHigherValueOnServerOnMultiChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+  MergeMetadata(&local, &remote);
+  // These methods do not trigger notifications or sync:
+  local.UpdateAddressStats(BuildAddress("addr", 5, 6));
+  local.UpdateCardStats(BuildCard("card", 7, 8));
+
+  EXPECT_CALL(local,
+              SendChangesToSyncServer(UnorderedElementsAre(
+                  SyncChangeAndDataMatch(
+                      syncer::SyncChange::ACTION_UPDATE, "address-addr",
+                      sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 5, 6),
+                  SyncChangeAndDataMatch(
+                      syncer::SyncChange::ACTION_UPDATE, "card-card",
+                      sync_pb::WalletMetadataSpecifics::CARD, "card", 7, 8))));
+
+  local.AutofillMultipleChanged();
+}
+
+// Verify that lower values of existing metadata are not sent to the sync server
+// when multiple metadata values change at once.
+TEST(AutofillWalletMetadataSyncableServiceTest,
+     DontUpdateToLowerValueOnServerOnMultiChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+  MergeMetadata(&local, &remote);
+  // These methods do not trigger notifications or sync:
+  local.UpdateAddressStats(BuildAddress("addr", 0, 0));
+  local.UpdateCardStats(BuildCard("card", 0, 0));
+
+  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
+
+  local.AutofillMultipleChanged();
+}
+
+// Verify that erased local metadata is also erased from the sync server when
+// multiple metadata values change at once.
+TEST(AutofillWalletMetadataSyncableServiceTest, DeleteFromServerOnMultiChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+  MergeMetadata(&local, &remote);
+  // This method dooes not trigger notifications or sync:
+  local.ClearServerData();
+
+  EXPECT_CALL(
+      local,
+      SendChangesToSyncServer(UnorderedElementsAre(
+          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "address-addr"),
+          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "card-card"))));
+
+  local.AutofillMultipleChanged();
+}
+
+// Verify that empty sync change from the sync server does not trigger writing
+// to disk or sending any data to the sync server.
+TEST(AutofillWalletMetadataSyncableServiceTest, EmptySyncChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+  MergeMetadata(&local, &remote);
+
+  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
+  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
+  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
+
+  local.ProcessSyncChanges(FROM_HERE, syncer::SyncChangeList());
+}
+
+syncer::SyncChange BuildChange(
+    syncer::SyncChange::SyncChangeType change_type,
+    const std::string& sync_tag,
+    sync_pb::WalletMetadataSpecifics::Type metadata_type,
+    const std::string& server_id,
+    int64 use_count,
+    int64 use_date) {
+  sync_pb::EntitySpecifics entity;
+  entity.mutable_wallet_metadata()->set_type(metadata_type);
+  entity.mutable_wallet_metadata()->set_id(server_id);
+  entity.mutable_wallet_metadata()->set_use_count(use_count);
+  entity.mutable_wallet_metadata()->set_use_date(use_date);
+  return syncer::SyncChange(
+      FROM_HERE, change_type,
+      syncer::SyncData::CreateLocalData(sync_tag, sync_tag, entity));
+}
+
+// Verify that new metadata from the sync server is ignored when processing
+// on-going sync changes. There should be no disk writes or messages to the sync
+// server.
+TEST(AutofillWalletMetadataSyncableServiceTest,
+     IgnoreNewMetadataFromServerOnSyncChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+  MergeMetadata(&local, &remote);
+  syncer::SyncChangeList changes;
+  changes.push_back(
+      BuildChange(syncer::SyncChange::ACTION_ADD, "address-new-addr",
+                  sync_pb::WalletMetadataSpecifics::ADDRESS, "new-addr", 5, 6));
+  changes.push_back(BuildChange(syncer::SyncChange::ACTION_ADD, "card-new-card",
+                                sync_pb::WalletMetadataSpecifics::CARD,
+                                "new-card", 7, 8));
+
+  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
+  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
+  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
+
+  local.ProcessSyncChanges(FROM_HERE, changes);
+}
+
+// Verify that higher values of metadata from the sync server are saved to
+// disk when processing on-going sync changes.
+TEST(AutofillWalletMetadataSyncableServiceTest,
+     SaveHigherValuesFromServerOnSyncChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+  MergeMetadata(&local, &remote);
+  syncer::SyncChangeList changes;
+  changes.push_back(
+      BuildChange(syncer::SyncChange::ACTION_UPDATE, "address-addr",
+                  sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 10, 20));
+  changes.push_back(BuildChange(syncer::SyncChange::ACTION_UPDATE, "card-card",
+                                sync_pb::WalletMetadataSpecifics::CARD, "card",
+                                30, 40));
+
+  EXPECT_CALL(local,
+              UpdateAddressStats(AutofillMetadataMatches("addr", 10, 20)));
+  EXPECT_CALL(local, UpdateCardStats(AutofillMetadataMatches("card", 30, 40)));
+  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
+
+  local.ProcessSyncChanges(FROM_HERE, changes);
+}
+
+// Verify that higher local values of metadata are sent to the sync server when
+// processing on-going sync changes.
+TEST(AutofillWalletMetadataSyncableServiceTest,
+     SendHigherValuesToServerOnSyncChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+  MergeMetadata(&local, &remote);
+  syncer::SyncChangeList changes;
+  changes.push_back(
+      BuildChange(syncer::SyncChange::ACTION_UPDATE, "address-addr",
+                  sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 0, 0));
+  changes.push_back(BuildChange(syncer::SyncChange::ACTION_UPDATE, "card-card",
+                                sync_pb::WalletMetadataSpecifics::CARD, "card",
+                                0, 0));
+
+  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
+  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
+  EXPECT_CALL(local,
+              SendChangesToSyncServer(UnorderedElementsAre(
+                  SyncChangeAndDataMatch(
+                      syncer::SyncChange::ACTION_UPDATE, "address-addr",
+                      sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 1, 2),
+                  SyncChangeAndDataMatch(
+                      syncer::SyncChange::ACTION_UPDATE, "card-card",
+                      sync_pb::WalletMetadataSpecifics::CARD, "card", 3, 4))));
+
+  local.ProcessSyncChanges(FROM_HERE, changes);
+}
+
+// Verify that addition of known metadata is treated the same as an update.
+TEST(AutofillWalletMetadataSyncableServiceTest,
+     TreatAdditionOfKnownMetadataAsUpdateOnSyncChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+  MergeMetadata(&local, &remote);
+  syncer::SyncChangeList changes;
+  changes.push_back(BuildChange(syncer::SyncChange::ACTION_ADD, "address-addr",
+                                sync_pb::WalletMetadataSpecifics::ADDRESS,
+                                "addr", 0, 0));
+  changes.push_back(BuildChange(syncer::SyncChange::ACTION_ADD, "card-card",
+                                sync_pb::WalletMetadataSpecifics::CARD, "card",
+                                0, 0));
+
+  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
+  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
+  EXPECT_CALL(local,
+              SendChangesToSyncServer(UnorderedElementsAre(
+                  SyncChangeAndDataMatch(
+                      syncer::SyncChange::ACTION_UPDATE, "address-addr",
+                      sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 1, 2),
+                  SyncChangeAndDataMatch(
+                      syncer::SyncChange::ACTION_UPDATE, "card-card",
+                      sync_pb::WalletMetadataSpecifics::CARD, "card", 3, 4))));
+
+  local.ProcessSyncChanges(FROM_HERE, changes);
+}
+
+// Verify that an update of locally unknown metadata is ignored. There should be
+// no disk writes and no messages sent to the server.
+TEST(AutofillWalletMetadataSyncableServiceTest,
+     IgnoreUpdateOfUnknownMetadataOnSyncChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+  MergeMetadata(&local, &remote);
+  syncer::SyncChangeList changes;
+  changes.push_back(BuildChange(
+      syncer::SyncChange::ACTION_UPDATE, "address-unknown-addr",
+      sync_pb::WalletMetadataSpecifics::ADDRESS, "unknown-addr", 0, 0));
+  changes.push_back(BuildChange(
+      syncer::SyncChange::ACTION_UPDATE, "card-unknown-card",
+      sync_pb::WalletMetadataSpecifics::CARD, "unknown-card", 0, 0));
+
+  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
+  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
+  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
+
+  local.ProcessSyncChanges(FROM_HERE, changes);
+}
+
+// Verify that deletion from the sync server of locally unknown metadata is
+// ignored. There should be no disk writes and no messages sent to the server.
+TEST(AutofillWalletMetadataSyncableServiceTest,
+     IgnoreDeleteOfUnknownMetadataOnSyncChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+  MergeMetadata(&local, &remote);
+  syncer::SyncChangeList changes;
+  changes.push_back(BuildChange(
+      syncer::SyncChange::ACTION_DELETE, "address-unknown-addr",
+      sync_pb::WalletMetadataSpecifics::ADDRESS, "unknown-addr", 0, 0));
+  changes.push_back(BuildChange(
+      syncer::SyncChange::ACTION_DELETE, "card-unknown-card",
+      sync_pb::WalletMetadataSpecifics::CARD, "unknown-card", 0, 0));
+
+  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
+  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
+  EXPECT_CALL(local, SendChangesToSyncServer(_)).Times(0);
+
+  local.ProcessSyncChanges(FROM_HERE, changes);
+}
+
+// Verify that deletion from the sync server of locally existing metadata will
+// trigger an undelete message sent to the server.
+TEST(AutofillWalletMetadataSyncableServiceTest,
+     UndeleteExistingMetadataOnSyncChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  local.UpdateCardStats(BuildCard("card", 3, 4));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr", 1, 2));
+  remote.UpdateCardStats(BuildCard("card", 3, 4));
+  MergeMetadata(&local, &remote);
+  syncer::SyncChangeList changes;
+  changes.push_back(
+      BuildChange(syncer::SyncChange::ACTION_DELETE, "address-addr",
+                  sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 0, 0));
+  changes.push_back(BuildChange(syncer::SyncChange::ACTION_DELETE, "card-card",
+                                sync_pb::WalletMetadataSpecifics::CARD, "card",
+                                0, 0));
+
+  EXPECT_CALL(local, UpdateAddressStats(_)).Times(0);
+  EXPECT_CALL(local, UpdateCardStats(_)).Times(0);
+  EXPECT_CALL(local,
+              SendChangesToSyncServer(UnorderedElementsAre(
+                  SyncChangeAndDataMatch(
+                      syncer::SyncChange::ACTION_ADD, "address-addr",
+                      sync_pb::WalletMetadataSpecifics::ADDRESS, "addr", 1, 2),
+                  SyncChangeAndDataMatch(
+                      syncer::SyncChange::ACTION_ADD, "card-card",
+                      sync_pb::WalletMetadataSpecifics::CARD, "card", 3, 4))));
+
+  local.ProcessSyncChanges(FROM_HERE, changes);
+}
+
+// Verify that processing sync changes maintains the local cache of sync server
+// data, which is used to avoid calling the expensive GetAllSyncData() function.
+TEST(AutofillWalletMetadataSyncableServiceTest,
+     CacheIsUpToDateAfterSyncChange) {
+  NiceMock<MockService> local;
+  local.UpdateAddressStats(BuildAddress("addr1", 1, 2));
+  local.UpdateAddressStats(BuildAddress("addr2", 3, 4));
+  local.UpdateCardStats(BuildCard("card1", 5, 6));
+  local.UpdateCardStats(BuildCard("card2", 7, 8));
+  NiceMock<MockService> remote;
+  remote.UpdateAddressStats(BuildAddress("addr1", 1, 2));
+  remote.UpdateAddressStats(BuildAddress("addr2", 3, 4));
+  remote.UpdateCardStats(BuildCard("card1", 5, 6));
+  remote.UpdateCardStats(BuildCard("card2", 7, 8));
+  MergeMetadata(&local, &remote);
+  syncer::SyncChangeList changes;
+  changes.push_back(
+      BuildChange(syncer::SyncChange::ACTION_UPDATE, "address-addr1",
+                  sync_pb::WalletMetadataSpecifics::ADDRESS, "addr1", 10, 20));
+  changes.push_back(BuildChange(syncer::SyncChange::ACTION_UPDATE, "card-card1",
+                                sync_pb::WalletMetadataSpecifics::CARD, "card1",
+                                50, 60));
+  local.ProcessSyncChanges(FROM_HERE, changes);
+  // This method dooes not trigger notifications or sync:
+  local.ClearServerData();
+
+  EXPECT_CALL(
+      local,
+      SendChangesToSyncServer(UnorderedElementsAre(
+          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "address-addr1"),
+          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "address-addr2"),
+          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "card-card1"),
+          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, "card-card2"))));
+
+  local.AutofillMultipleChanged();
+}
+
+}  // namespace
+}  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_backend.h b/components/autofill/core/browser/webdata/autofill_webdata_backend.h
index 2f46301..8b06ffb9 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_backend.h
+++ b/components/autofill/core/browser/webdata/autofill_webdata_backend.h
@@ -31,10 +31,10 @@
   // Remove expired elements from the database and commit if needed.
   virtual void RemoveExpiredFormElements() = 0;
 
-  // Notifies listeners on the UI thread that multiple changes have been made to
-  // to Autofill records of the database.
-  // NOTE: This method is intended to be called from the DB thread. It
-  // asynchronously notifies listeners on the UI thread.
+  // Notifies listeners on both DB and UI threads that multiple changes have
+  // been made to to Autofill records of the database.
+  // NOTE: This method is intended to be called from the DB thread. The UI
+  // thread notifications are asynchronous.
   virtual void NotifyOfMultipleAutofillChanges() = 0;
 };
 
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
index ec48b80..187f3e6 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
+++ b/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
@@ -67,6 +67,12 @@
 
 void AutofillWebDataBackendImpl::NotifyOfMultipleAutofillChanges() {
   DCHECK(db_thread_->BelongsToCurrentThread());
+
+  // DB thread notification.
+  FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread, db_observer_list_,
+                    AutofillMultipleChanged());
+
+  // UI thread notification.
   ui_thread_->PostTask(FROM_HERE, on_changed_callback_);
 }
 
@@ -278,6 +284,10 @@
     return WebDatabase::COMMIT_NOT_NEEDED;
   }
 
+  FOR_EACH_OBSERVER(
+      AutofillWebDataServiceObserverOnDBThread, db_observer_list_,
+      CreditCardChanged(CreditCardChange(CreditCardChange::ADD,
+                                         credit_card.guid(), &credit_card)));
   return WebDatabase::COMMIT_NEEDED;
 }
 
@@ -297,6 +307,11 @@
     NOTREACHED();
     return WebDatabase::COMMIT_NOT_NEEDED;
   }
+
+  FOR_EACH_OBSERVER(
+      AutofillWebDataServiceObserverOnDBThread, db_observer_list_,
+      CreditCardChanged(CreditCardChange(CreditCardChange::UPDATE,
+                                         credit_card.guid(), &credit_card)));
   return WebDatabase::COMMIT_NEEDED;
 }
 
@@ -307,6 +322,10 @@
     NOTREACHED();
     return WebDatabase::COMMIT_NOT_NEEDED;
   }
+
+  FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread, db_observer_list_,
+                    CreditCardChanged(CreditCardChange(CreditCardChange::REMOVE,
+                                                       guid, nullptr)));
   return WebDatabase::COMMIT_NEEDED;
 }
 
@@ -361,20 +380,31 @@
     const CreditCard& card,
     WebDatabase* db) {
   DCHECK(db_thread_->BelongsToCurrentThread());
-  if (AutofillTable::FromWebDatabase(db)->UpdateServerCardUsageStats(card))
-    return WebDatabase::COMMIT_NEEDED;
-  return WebDatabase::COMMIT_NOT_NEEDED;
+  if (!AutofillTable::FromWebDatabase(db)->UpdateServerCardUsageStats(card))
+    return WebDatabase::COMMIT_NOT_NEEDED;
+
+  FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread, db_observer_list_,
+                    CreditCardChanged(CreditCardChange(CreditCardChange::UPDATE,
+                                                       card.guid(), &card)));
+
+  return WebDatabase::COMMIT_NEEDED;
 }
 
 WebDatabase::State AutofillWebDataBackendImpl::UpdateServerAddressUsageStats(
     const AutofillProfile& profile,
     WebDatabase* db) {
   DCHECK(db_thread_->BelongsToCurrentThread());
-  if (AutofillTable::FromWebDatabase(db)->UpdateServerAddressUsageStats(
+  if (!AutofillTable::FromWebDatabase(db)->UpdateServerAddressUsageStats(
           profile)) {
-    return WebDatabase::COMMIT_NEEDED;
+    return WebDatabase::COMMIT_NOT_NEEDED;
   }
-  return WebDatabase::COMMIT_NOT_NEEDED;
+
+  FOR_EACH_OBSERVER(
+      AutofillWebDataServiceObserverOnDBThread, db_observer_list_,
+      AutofillProfileChanged(AutofillProfileChange(
+          AutofillProfileChange::UPDATE, profile.guid(), &profile)));
+
+  return WebDatabase::COMMIT_NEEDED;
 }
 
 WebDatabase::State AutofillWebDataBackendImpl::ClearAllServerData(
@@ -400,12 +430,17 @@
           delete_end,
           &profile_guids,
           &credit_card_guids)) {
-    for (std::vector<std::string>::iterator iter = profile_guids.begin();
-         iter != profile_guids.end(); ++iter) {
-      AutofillProfileChange change(AutofillProfileChange::REMOVE, *iter, NULL);
+    for (const std::string& guid : profile_guids) {
       FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
                         db_observer_list_,
-                        AutofillProfileChanged(change));
+                        AutofillProfileChanged(AutofillProfileChange(
+                            AutofillProfileChange::REMOVE, guid, nullptr)));
+    }
+    for (const std::string& guid : credit_card_guids) {
+      FOR_EACH_OBSERVER(AutofillWebDataServiceObserverOnDBThread,
+                        db_observer_list_,
+                        CreditCardChanged(CreditCardChange(
+                            CreditCardChange::REMOVE, guid, nullptr)));
     }
     // Note: It is the caller's responsibility to post notifications for any
     // changes, e.g. by calling the Refresh() method of PersonalDataManager.
diff --git a/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h b/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h
index f4333e5..e8bf79ca 100644
--- a/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h
+++ b/components/autofill/core/browser/webdata/autofill_webdata_service_observer.h
@@ -18,6 +18,14 @@
   // in the WebDatabase.
   virtual void AutofillProfileChanged(const AutofillProfileChange& change) {}
 
+  // Called on DB thread when a CreditCard has been added/removed/updated in the
+  // WebDatabase.
+  virtual void CreditCardChanged(const CreditCardChange& change) {}
+
+  // Called on DB thread when multiple Autofill entries have been modified by
+  // Sync.
+  virtual void AutofillMultipleChanged() {}
+
  protected:
   virtual ~AutofillWebDataServiceObserverOnDBThread() {}
 };
diff --git a/components/autofill/ios/OWNERS b/components/autofill/ios/OWNERS
index 5d88be5..bf70425 100644
--- a/components/autofill/ios/OWNERS
+++ b/components/autofill/ios/OWNERS
@@ -1,2 +1,2 @@
-dconnelly@chromium.org
 jdonnelly@chromium.org
+thestig@chromium.org
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index dbac9807..b97f071f 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -58,6 +58,7 @@
       'autofill/core/browser/ui/card_unmask_prompt_controller_impl_unittest.cc',
       'autofill/core/browser/validation_unittest.cc',
       'autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc',
+      'autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc',
       'autofill/core/browser/webdata/autofill_table_unittest.cc',
       'autofill/core/browser/webdata/web_data_service_unittest.cc',
       'autofill/core/common/autofill_regexes_unittest.cc',
@@ -435,6 +436,7 @@
     'proximity_auth_unittest_sources': [
       'proximity_auth/ble/bluetooth_low_energy_characteristics_finder_unittest.cc',
       'proximity_auth/ble/bluetooth_low_energy_connection_finder_unittest.cc',
+      'proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc',
       'proximity_auth/ble/proximity_auth_ble_system_unittest.cc',
       'proximity_auth/bluetooth_connection_finder_unittest.cc',
       'proximity_auth/bluetooth_connection_unittest.cc',
diff --git a/components/content_settings.gypi b/components/content_settings.gypi
index d0218fe0..984b4541 100644
--- a/components/content_settings.gypi
+++ b/components/content_settings.gypi
@@ -81,8 +81,6 @@
         'content_settings/core/common/content_settings_pattern_parser.cc',
         'content_settings/core/common/content_settings_pattern_parser.h',
         'content_settings/core/common/content_settings_types.h',
-        'content_settings/core/common/permission_request_id.cc',
-        'content_settings/core/common/permission_request_id.h',
         'content_settings/core/common/pref_names.cc',
         'content_settings/core/common/pref_names.h',
       ],
diff --git a/components/content_settings/core/common/BUILD.gn b/components/content_settings/core/common/BUILD.gn
index 3784bc6f..0570be8 100644
--- a/components/content_settings/core/common/BUILD.gn
+++ b/components/content_settings/core/common/BUILD.gn
@@ -11,8 +11,6 @@
     "content_settings_pattern_parser.cc",
     "content_settings_pattern_parser.h",
     "content_settings_types.h",
-    "permission_request_id.cc",
-    "permission_request_id.h",
     "pref_names.cc",
     "pref_names.h",
   ]
diff --git a/components/content_settings/core/common/permission_request_id.h b/components/content_settings/core/common/permission_request_id.h
deleted file mode 100644
index 6b798d4..0000000
--- a/components/content_settings/core/common/permission_request_id.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2013 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_CONTENT_SETTINGS_CORE_COMMON_PERMISSION_REQUEST_ID_H_
-#define COMPONENTS_CONTENT_SETTINGS_CORE_COMMON_PERMISSION_REQUEST_ID_H_
-
-#include <string>
-
-#include "url/gurl.h"
-
-// Uniquely identifies a particular permission request.
-class PermissionRequestID {
- public:
-  PermissionRequestID(int render_process_id,
-                      int render_frame_id,
-                      int bridge_id,
-                      const GURL& origin);
-  ~PermissionRequestID();
-
-  int render_process_id() const { return render_process_id_; }
-  int render_frame_id() const { return render_frame_id_; }
-  int bridge_id() const { return bridge_id_; }
-  GURL origin() const { return origin_; }
-
-  bool Equals(const PermissionRequestID& other) const;
-  std::string ToString() const;
-
- private:
-  int render_process_id_;
-  int render_frame_id_;
-  // Id unique to this instance.
-  int bridge_id_;
-  // Needed for permission checks that are based on origin.
-  // If you don't use origin to check permission request, pass an empty GURL.
-  GURL origin_;
-
-  // Purposefully do not disable copying, as this is stored in STL containers.
-};
-
-#endif  // COMPONENTS_CONTENT_SETTINGS_CORE_COMMON_PERMISSION_REQUEST_ID_H_
diff --git a/components/crash/app/breakpad_linux.cc b/components/crash/app/breakpad_linux.cc
index 393c604..ba57acc9 100644
--- a/components/crash/app/breakpad_linux.cc
+++ b/components/crash/app/breakpad_linux.cc
@@ -166,35 +166,6 @@
     output[index - 1] = '0' + (i % 10);
 }
 
-#if defined(OS_ANDROID)
-char* my_strncpy(char* dst, const char* src, size_t len) {
-  int i = len;
-  char* p = dst;
-  if (!dst || !src)
-    return dst;
-  while (i != 0 && *src != '\0') {
-    *p++ = *src++;
-    i--;
-  }
-  while (i != 0) {
-    *p++ = '\0';
-    i--;
-  }
-  return dst;
-}
-
-char* my_strncat(char *dest, const char* src, size_t len) {
-  char* ret = dest;
-  while (*dest)
-      dest++;
-  while (len--)
-    if (!(*dest++ = *src++))
-      return ret;
-  *dest = 0;
-  return ret;
-}
-#endif
-
 #if !defined(OS_CHROMEOS)
 bool my_isxdigit(char c) {
   return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f');
@@ -1093,30 +1064,80 @@
   static const char msg[] = "Cannot upload crash dump: cannot exec "
                             "/sbin/crash_reporter\n";
 #else
+  // Compress |dumpfile| with gzip.
+  const pid_t gzip_child = sys_fork();
+  if (gzip_child < 0) {
+    static const char msg[] = "sys_fork() for gzip process failed.\n";
+    WriteLog(msg, sizeof(msg) - 1);
+    sys__exit(1);
+  }
+  if (!gzip_child) {
+    // gzip process.
+    const char* args[] = {
+      "/bin/gzip",
+      "-f",  // Do not prompt to verify before overwriting.
+      dumpfile,
+      nullptr,
+    };
+    execve(args[0], const_cast<char**>(args), environ);
+    static const char msg[] = "Cannot exec gzip.\n";
+    WriteLog(msg, sizeof(msg) - 1);
+    sys__exit(1);
+  }
+  // Wait for gzip process.
+  int status = 0;
+  if (sys_waitpid(gzip_child, &status, 0) != gzip_child ||
+      !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+    static const char msg[] = "sys_waitpid() for gzip process failed.\n";
+    WriteLog(msg, sizeof(msg) - 1);
+    sys_kill(gzip_child, SIGKILL);
+    sys__exit(1);
+  }
+
+  static const char kGzipExtension[] = ".gz";
+  const size_t gzip_file_size = my_strlen(dumpfile) + sizeof(kGzipExtension);
+  char* const gzip_file = reinterpret_cast<char*>(allocator->Alloc(
+      gzip_file_size));
+  my_strlcpy(gzip_file, dumpfile, gzip_file_size);
+  my_strlcat(gzip_file, kGzipExtension, gzip_file_size);
+
+  // Rename |gzip_file| to |dumpfile| (the original file was deleted by gzip).
+  if (rename(gzip_file, dumpfile)) {
+    static const char msg[] = "Failed to rename gzipped file.\n";
+    WriteLog(msg, sizeof(msg) - 1);
+    sys__exit(1);
+  }
+
   // The --header argument to wget looks like:
+  //   --header=Content-Encoding: gzip
   //   --header=Content-Type: multipart/form-data; boundary=XYZ
   // where the boundary has two fewer leading '-' chars
+  static const char header_content_encoding[] =
+      "--header=Content-Encoding: gzip";
   static const char header_msg[] =
       "--header=Content-Type: multipart/form-data; boundary=";
-  char* const header = reinterpret_cast<char*>(allocator->Alloc(
-      sizeof(header_msg) - 1 + strlen(mime_boundary) - 2 + 1));
-  memcpy(header, header_msg, sizeof(header_msg) - 1);
-  memcpy(header + sizeof(header_msg) - 1, mime_boundary + 2,
-         strlen(mime_boundary) - 2);
-  // We grab the NUL byte from the end of |mime_boundary|.
+  const size_t header_content_type_size =
+      sizeof(header_msg) - 1 + my_strlen(mime_boundary) - 2 + 1;
+  char* const header_content_type = reinterpret_cast<char*>(allocator->Alloc(
+      header_content_type_size));
+  my_strlcpy(header_content_type, header_msg, header_content_type_size);
+  my_strlcat(header_content_type, mime_boundary + 2, header_content_type_size);
 
   // The --post-file argument to wget looks like:
   //   --post-file=/tmp/...
   static const char post_file_msg[] = "--post-file=";
+  const size_t post_file_size =
+      sizeof(post_file_msg) - 1 + my_strlen(dumpfile) + 1;
   char* const post_file = reinterpret_cast<char*>(allocator->Alloc(
-       sizeof(post_file_msg) - 1 + strlen(dumpfile) + 1));
-  memcpy(post_file, post_file_msg, sizeof(post_file_msg) - 1);
-  memcpy(post_file + sizeof(post_file_msg) - 1, dumpfile, strlen(dumpfile));
+      post_file_size));
+  my_strlcpy(post_file, post_file_msg, post_file_size);
+  my_strlcat(post_file, dumpfile, post_file_size);
 
   static const char kWgetBinary[] = "/usr/bin/wget";
   const char* args[] = {
     kWgetBinary,
-    header,
+    header_content_encoding,
+    header_content_type,
     post_file,
     kUploadURL,
     "--timeout=10",  // Set a timeout so we don't hang forever.
@@ -1341,7 +1362,7 @@
     }
   } else {
     if (info.upload) {
-      memcpy(temp_file, temp_file_template, sizeof(temp_file_template));
+      my_memcpy(temp_file, temp_file_template, sizeof(temp_file_template));
 
       for (unsigned i = 0; i < 10; ++i) {
         uint64_t t;
@@ -1542,36 +1563,33 @@
 
 #if defined(OS_ANDROID)
   if (info.filename) {
-    int filename_length = my_strlen(info.filename);
+    size_t filename_length = my_strlen(info.filename);
 
     // If this was a file, we need to copy it to the right place and use the
     // right file name so it gets uploaded by the browser.
     const char msg[] = "Output crash dump file:";
     WriteLog(msg, sizeof(msg) - 1);
-    WriteLog(info.filename, filename_length - 1);
+    WriteLog(info.filename, filename_length);
 
     char pid_buf[kUint64StringSize];
-    uint64_t pid_str_length = my_uint64_len(info.pid);
+    size_t pid_str_length = my_uint64_len(info.pid);
     my_uint64tos(pid_buf, info.pid, pid_str_length);
+    pid_buf[pid_str_length] = 0;  // my_uint64tos() doesn't null-terminate.
 
-    // -1 because we won't need the null terminator on the original filename.
-    unsigned done_filename_len = filename_length - 1 + pid_str_length;
+    size_t done_filename_len = filename_length + pid_str_length + 1;
     char* done_filename = reinterpret_cast<char*>(
         allocator.Alloc(done_filename_len));
     // Rename the file such that the pid is the suffix in order signal to other
     // processes that the minidump is complete. The advantage of using the pid
     // as the suffix is that it is trivial to associate the minidump with the
     // crashed process.
-    // Finally, note strncpy prevents null terminators from
-    // being copied. Pad the rest with 0's.
-    my_strncpy(done_filename, info.filename, done_filename_len);
-    // Append the suffix a null terminator should be added.
-    my_strncat(done_filename, pid_buf, pid_str_length);
+    my_strlcpy(done_filename, info.filename, done_filename_len);
+    my_strlcat(done_filename, pid_buf, done_filename_len);
     // Rename the minidump file to signal that it is complete.
     if (rename(info.filename, done_filename)) {
       const char failed_msg[] = "Failed to rename:";
       WriteLog(failed_msg, sizeof(failed_msg) - 1);
-      WriteLog(info.filename, filename_length - 1);
+      WriteLog(info.filename, filename_length);
       const char to_msg[] = "to";
       WriteLog(to_msg, sizeof(to_msg) - 1);
       WriteLog(done_filename, done_filename_len - 1);
diff --git a/components/cronet.gypi b/components/cronet.gypi
index 4fb3fb97..52f69bb 100644
--- a/components/cronet.gypi
+++ b/components/cronet.gypi
@@ -99,6 +99,41 @@
           ],
         },
         {
+          'target_name': 'cronet_version_header',
+          'type': 'none',
+          # Need to set hard_depency flag because cronet_version generates a
+          # header.
+          'hard_dependency': 1,
+          'direct_dependent_settings': {
+            'include_dirs': [
+              '<(SHARED_INTERMEDIATE_DIR)/',
+            ],
+          },
+          'actions': [
+            {
+              'action_name': 'version_header',
+              'message': 'Generating version header file: <@(_outputs)',
+              'inputs': [
+                '<(version_path)',
+                'cronet/version.h.in',
+              ],
+              'outputs': [
+                '<(SHARED_INTERMEDIATE_DIR)/components/cronet/version.h',
+              ],
+              'action': [
+                'python',
+                '<(version_py_path)',
+                '-e', 'VERSION_FULL="<(version_full)"',
+                'cronet/version.h.in',
+                '<@(_outputs)',
+              ],
+              'includes': [
+                '../build/util/version.gypi',
+              ],
+            },
+          ],
+        },
+        {
           # cronet_static_small target has reduced binary size through using
           # ICU alternatives which requires file and ftp support be disabled.
           'target_name': 'cronet_static_small',
@@ -500,6 +535,19 @@
                 '<@(_outputs)',
               ],
             },
+            {
+              'action_name': 'generate javadoc',
+              'inputs': ['cronet/tools/generate_javadoc.py'] ,
+              'outputs': ['<(package_dir)/javadoc'],
+              'action': [
+                'python',
+                '<@(_inputs)',
+                '--source-dir=src',
+                '--output-dir=<(package_dir)/javadoc',
+                '--working-dir=cronet/android/java',
+              ],
+              'message': 'Generating Javadoc',
+            },
           ],
           'copies': [
             {
diff --git a/components/cronet/android/cronet_library_loader.cc b/components/cronet/android/cronet_library_loader.cc
index b1d4542..ddc5f1ba 100644
--- a/components/cronet/android/cronet_library_loader.cc
+++ b/components/cronet/android/cronet_library_loader.cc
@@ -21,6 +21,7 @@
 #include "components/cronet/android/cronet_upload_data_stream_adapter.h"
 #include "components/cronet/android/cronet_url_request_adapter.h"
 #include "components/cronet/android/cronet_url_request_context_adapter.h"
+#include "components/cronet/version.h"
 #include "jni/CronetLibraryLoader_jni.h"
 #include "net/android/net_jni_registrar.h"
 #include "net/android/network_change_notifier_factory_android.h"
@@ -112,4 +113,8 @@
   g_network_change_notifier = net::NetworkChangeNotifier::Create();
 }
 
+jstring GetCronetVersion(JNIEnv* env, jclass jcaller) {
+  return base::android::ConvertUTF8ToJavaString(env, CRONET_VERSION).Release();
+}
+
 }  // namespace cronet
diff --git a/components/cronet/android/java/build.xml b/components/cronet/android/java/build.xml
new file mode 100644
index 0000000..b87f6156
--- /dev/null
+++ b/components/cronet/android/java/build.xml
@@ -0,0 +1,18 @@
+<project>
+  <target name="doc" description="generate documentation">
+      <javadoc destdir="${doc.dir}"
+               windowtitle="Cronet API"
+               nohelp="yes"
+               notree="yes"
+               nodeprecated="yes"
+               >
+        <fileset dir="${source.dir}" defaultexcludes="yes">
+          <include name="**/*.java"/>
+          <!-- exclude legacy API -->
+          <exclude name="**/Chromium*.java"/>
+          <exclude name="**/ChunkedWritableByteChannel*.java"/>
+          <exclude name="**/HttpUrl*.java"/>
+        </fileset>
+      </javadoc>
+  </target>
+</project>
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetLibraryLoader.java b/components/cronet/android/java/src/org/chromium/net/CronetLibraryLoader.java
index 2cf9b16a..95e9559 100644
--- a/components/cronet/android/java/src/org/chromium/net/CronetLibraryLoader.java
+++ b/components/cronet/android/java/src/org/chromium/net/CronetLibraryLoader.java
@@ -32,6 +32,13 @@
                 return;
             }
             System.loadLibrary(config.libraryName());
+            if (!Version.CRONET_VERSION.equals(nativeGetCronetVersion())) {
+                throw new RuntimeException(String.format(
+                      "Expected Cronet version number %s, "
+                              + "actual version number %s.",
+                      Version.CRONET_VERSION,
+                      nativeGetCronetVersion()));
+            }
             nativeCronetInitApplicationContext(context.getApplicationContext());
             // Init native Chromium URLRequestContext on Main UI thread.
             Runnable task = new Runnable() {
@@ -69,4 +76,5 @@
     // Native methods are implemented in cronet_loader.cc.
     private static native void nativeCronetInitOnMainThread();
     private static native void nativeCronetInitApplicationContext(Context appContext);
+    private static native String nativeGetCronetVersion();
 }
diff --git a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
index 4a3fb10c..01928823 100644
--- a/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
+++ b/components/cronet/android/java/src/org/chromium/net/CronetUrlRequestContext.java
@@ -83,6 +83,16 @@
     }
 
     @Override
+    public UrlRequest createRequest(String url, UrlRequestListener listener,
+                                    Executor executor, int priority) {
+        synchronized (mLock) {
+            checkHaveAdapter();
+            return new CronetUrlRequest(this, mUrlRequestContextAdapter, url,
+                    priority, listener, executor);
+        }
+    }
+
+    @Override
     public boolean isEnabled() {
         return Build.VERSION.SDK_INT >= 14;
     }
diff --git a/components/cronet/android/java/src/org/chromium/net/UrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/UrlRequestContext.java
index 80f2df8..3394269 100644
--- a/components/cronet/android/java/src/org/chromium/net/UrlRequestContext.java
+++ b/components/cronet/android/java/src/org/chromium/net/UrlRequestContext.java
@@ -20,12 +20,10 @@
             "org.chromium.net.CronetUrlRequestContext";
 
     /**
-     * Creates an UrlRequest object. All UrlRequest functions must
-     * be called on the Executor's thread, and all callbacks will be called
-     * on the Executor's thread as well. Executor must not run tasks on the
+     * Creates a {@link UrlRequest} object. All callbacks will
+     * be called on the Executor's thread. Executor must not run tasks on the
      * current thread to prevent network jank and exception during shutdown.
      *
-     * createRequest itself may be called on any thread.
      * @param url URL for the request.
      * @param listener Callback interface that gets called on different events.
      * @param executor Executor on which all callbacks will be called.
@@ -35,6 +33,21 @@
             UrlRequestListener listener, Executor executor);
 
     /**
+     * Creates a {@link UrlRequest} object. All callbacks will
+     * be called on the Executor's thread. Executor must not run tasks on the
+     * current thread to prevent network jank and exception during shutdown.
+     *
+     * @param url URL for the request.
+     * @param listener Callback interface that gets called on different events.
+     * @param executor Executor on which all callbacks will be called.
+     * @param priority Priority of the request which should be one of the
+                  REQUEST_PRIORITY_* values in {@link UrlRequest}.
+     * @return new request.
+     */
+    public abstract UrlRequest createRequest(String url,
+            UrlRequestListener listener, Executor executor, int priority);
+
+    /**
      * @return true if the context is enabled.
      */
     public abstract boolean isEnabled();
diff --git a/components/cronet/cronet_static.gypi b/components/cronet/cronet_static.gypi
index b04f778..9ce059e 100644
--- a/components/cronet/cronet_static.gypi
+++ b/components/cronet/cronet_static.gypi
@@ -12,6 +12,7 @@
     'cronet_url_request_context_config_list',
     'cronet_url_request_java',
     'cronet_version',
+    'cronet_version_header',
     'metrics',
   ],
   'sources': [
diff --git a/components/cronet/tools/generate_javadoc.py b/components/cronet/tools/generate_javadoc.py
new file mode 100755
index 0000000..614c51f
--- /dev/null
+++ b/components/cronet/tools/generate_javadoc.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+#
+# 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 fnmatch
+import optparse
+import os
+import sys
+
+REPOSITORY_ROOT = os.path.abspath(os.path.join(
+    os.path.dirname(__file__), '..', '..', '..'))
+
+sys.path.append(os.path.join(REPOSITORY_ROOT, 'build/android/gyp/util'))
+import build_utils
+
+
+def GenerateJavadoc(options):
+  source_dir = options.source_dir
+  output_dir = options.output_dir
+  working_dir = options.working_dir
+
+  build_utils.DeleteDirectory(output_dir)
+  build_utils.MakeDirectory(output_dir)
+  javadoc_cmd = ['ant', '-Dsource.dir=' + source_dir,
+             '-Ddoc.dir=' + os.path.abspath(output_dir), 'doc']
+  build_utils.CheckOutput(javadoc_cmd, cwd=working_dir)
+
+
+def main():
+  parser = optparse.OptionParser()
+  parser.add_option('--source-dir', help='Source directory')
+  parser.add_option('--output-dir', help='Directory to put javadoc')
+  parser.add_option('--working-dir', help='Working directory')
+
+  options, _ = parser.parse_args()
+
+  GenerateJavadoc(options)
+
+if __name__ == '__main__':
+  sys.exit(main())
+
diff --git a/components/cronet/version.h.in b/components/cronet/version.h.in
new file mode 100644
index 0000000..013b667
--- /dev/null
+++ b/components/cronet/version.h.in
@@ -0,0 +1,12 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// version.h is generated from version.h.in.  Edit the source!
+
+#ifndef COMPONENTS_CRONET_VERSION_H_
+#define COMPONENTS_CRONET_VERSION_H_
+
+#define CRONET_VERSION "@VERSION_FULL@"
+
+#endif  // COMPONENTS_CRONET_VERSION_H_
diff --git a/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.cc b/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.cc
index cc021bca..7fbb47b2 100644
--- a/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.cc
+++ b/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.cc
@@ -46,16 +46,17 @@
 void DataReductionProxyMessageFilter::OnDataReductionProxyStatus(
     const net::HostPortPair& proxy_server,
     bool* is_data_reduction_proxy,
-    AutoLoFiStatus* lofi_status) {
+    LoFiStatus* lofi_status) {
+  DCHECK(is_data_reduction_proxy);
+  DCHECK(lofi_status);
   *is_data_reduction_proxy = false;
-  *lofi_status = AUTO_LOFI_STATUS_DISABLED;
-  if (!config_) {
+  *lofi_status = LOFI_STATUS_TEMPORARILY_OFF;
+  if (!config_)
     return;
-  }
   *is_data_reduction_proxy =
       config_->IsDataReductionProxy(proxy_server, nullptr);
   if (*is_data_reduction_proxy)
-    *lofi_status = config_->GetAutoLoFiStatus();
+    *lofi_status = config_->GetLoFiStatus();
 }
 
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h b/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h
index e4595b7a..884cc1f2 100644
--- a/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h
+++ b/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h
@@ -29,7 +29,7 @@
   // Sets |lofi_response| to the current status of the LoFi.
   void OnDataReductionProxyStatus(const net::HostPortPair& proxy_server,
                                   bool* is_data_reduction_proxy,
-                                  AutoLoFiStatus* lofi_status);
+                                  LoFiStatus* lofi_status);
 
  private:
   ~DataReductionProxyMessageFilter() override;
diff --git a/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc b/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc
index 37aa0ce..77f07dad 100644
--- a/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc
+++ b/components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
@@ -49,93 +50,109 @@
   net::HostPortPair proxy_server =
       net::HostPortPair::FromString("www.google.com:443");
 
-  const bool enable_lofi_on_switch[] = {false, true};
-
   const struct {
-    bool is_data_reduction_proxy;
+    bool lofi_on_through_switch;
+    bool data_reduction_proxy_used;
     bool auto_lofi_enabled_field_trial_group;
     bool auto_lofi_control_field_trial_group;
-    bool is_network_bad;
-    bool expected_is_data_reduction_proxy;
-    AutoLoFiStatus expected_auto_lofi_status;
+    bool network_quality_prohibitively_slow;
+    bool expected_data_reduction_proxy;
+    LoFiStatus expected_lofi_status;
 
   } tests[] = {
       {
-       // In Enabled field trial group and the network is bad.
+       // In Enabled field trial group and the network is prohibitively slow.
+       false,
        true,
        true,
        false,
        true,
        true,
-       AUTO_LOFI_STATUS_ON,
+       LOFI_STATUS_ACTIVE,
       },
       {
-       // In Enabled field trial group but the network is not bad.
+       // In Enabled field trial group but the network is not prohibitively
+       // slow.
+       false,
        true,
        true,
        false,
        false,
        true,
-       AUTO_LOFI_STATUS_DISABLED,
+       LOFI_STATUS_INACTIVE,
       },
       {
-       // In Control field trial group and the network is bad.
+       // In Control field trial group and the network is prohibitively slow.
+       false,
        true,
        false,
        true,
        true,
        true,
-       AUTO_LOFI_STATUS_OFF,
+       LOFI_STATUS_ACTIVE_CONTROL,
       },
       {
-       // In Control field trial group but the network is not bad.
+       // In Control field trial group but the network is not prohibitively
+       // slow.
+       false,
        true,
        false,
        true,
        false,
        true,
-       AUTO_LOFI_STATUS_DISABLED,
+       LOFI_STATUS_INACTIVE_CONTROL,
       },
       {
        // Not a data reduction proxy server.
        false,
+       false,
        true,
        false,
        true,
        false,
-       AUTO_LOFI_STATUS_DISABLED,
+       LOFI_STATUS_TEMPORARILY_OFF,
+      },
+      {
+       // Enabled through command line switch.
+       true,
+       true,
+       true,
+       false,
+       true,
+       true,
+       LOFI_STATUS_ACTIVE_FROM_FLAGS,
       },
   };
 
-  for (size_t i = 0; i < arraysize(enable_lofi_on_switch); ++i) {
-    if (enable_lofi_on_switch[i]) {
-      // Enabling LoFi on switch should have no effect on Auto LoFi.
+  for (size_t i = 0; i < arraysize(tests); ++i) {
+    bool is_data_reduction_proxy = false;
+
+    if (tests[i].lofi_on_through_switch) {
       base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
       command_line->AppendSwitch(
           data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
     }
 
-    for (size_t j = 0; j < arraysize(tests); ++j) {
-      bool is_data_reduction_proxy = false;
+    EXPECT_CALL(*config(), IsDataReductionProxy(testing::_, nullptr))
+        .WillOnce(testing::Return(tests[i].data_reduction_proxy_used));
 
-      EXPECT_CALL(*config(), IsDataReductionProxy(testing::_, nullptr))
-          .WillOnce(testing::Return(tests[j].is_data_reduction_proxy));
-      EXPECT_CALL(*config(), IsNetworkBad())
-          .WillRepeatedly(testing::Return(tests[j].is_network_bad));
-      EXPECT_CALL(*config(), IsIncludedInLoFiEnabledFieldTrial())
-          .WillRepeatedly(
-              testing::Return(tests[j].auto_lofi_enabled_field_trial_group));
-      EXPECT_CALL(*config(), IsIncludedInLoFiControlFieldTrial())
-          .WillRepeatedly(
-              testing::Return(tests[j].auto_lofi_control_field_trial_group));
-      enum AutoLoFiStatus auto_lofi_status;
-      message_filter()->OnDataReductionProxyStatus(
-          proxy_server, &is_data_reduction_proxy, &auto_lofi_status);
-      EXPECT_EQ(is_data_reduction_proxy,
-                tests[j].expected_is_data_reduction_proxy)
-          << i << j;
-      EXPECT_EQ(auto_lofi_status, tests[j].expected_auto_lofi_status) << i << j;
-    }
+    EXPECT_CALL(*config(), IsNetworkQualityProhibitivelySlow(testing::_))
+        .WillRepeatedly(
+            testing::Return(tests[i].network_quality_prohibitively_slow));
+
+    EXPECT_CALL(*config(), IsIncludedInLoFiEnabledFieldTrial())
+        .WillRepeatedly(
+            testing::Return(tests[i].auto_lofi_enabled_field_trial_group));
+    EXPECT_CALL(*config(), IsIncludedInLoFiControlFieldTrial())
+        .WillRepeatedly(
+            testing::Return(tests[i].auto_lofi_control_field_trial_group));
+    config()->UpdateLoFiStatusOnMainFrameRequest(false, nullptr);
+    LoFiStatus lofi_status;
+    message_filter()->OnDataReductionProxyStatus(
+        proxy_server, &is_data_reduction_proxy, &lofi_status);
+    EXPECT_EQ(tests[i].expected_data_reduction_proxy, is_data_reduction_proxy)
+        << i;
+    EXPECT_EQ(tests[i].expected_lofi_status, lofi_status) << i;
   }
 }
 
diff --git a/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h b/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h
index ecbf3048..e4a4752c 100644
--- a/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h
+++ b/components/data_reduction_proxy/content/common/data_reduction_proxy_messages.h
@@ -10,12 +10,11 @@
 
 #define IPC_MESSAGE_START DataReductionProxyStart
 
-IPC_ENUM_TRAITS_MAX_VALUE(data_reduction_proxy::AutoLoFiStatus,
-                          data_reduction_proxy::AUTO_LOFI_STATUS_LAST);
+IPC_ENUM_TRAITS_MAX_VALUE(data_reduction_proxy::LoFiStatus,
+                          data_reduction_proxy::LOFI_STATUS_LAST);
 
 IPC_SYNC_MESSAGE_CONTROL1_2(
     DataReductionProxyViewHostMsg_DataReductionProxyStatus,
     net::HostPortPair /* proxy server */,
     bool /* true iff the proxy server is a Data Reduction Proxy */,
-    data_reduction_proxy::AutoLoFiStatus
-    /* set to the current Auto LoFi status */)
+    data_reduction_proxy::LoFiStatus /* current LoFi status */)
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
index 5655e12..6db84f1 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
@@ -704,6 +704,7 @@
     // Here, we prefer collecting less data but the collected data is
     // associated with an accurate date.
     if (days_since_last_update == 1) {
+      RecordUserVisibleDataSavings();
       // The previous day's data point is the second one from the tail.
       // Therefore (kNumDaysInHistory - 2) below.
       RecordDailyContentLengthHistograms(
@@ -721,4 +722,26 @@
   }
 }
 
+void DataReductionProxyCompressionStats::RecordUserVisibleDataSavings() {
+  int64 original_content_length;
+  int64 received_content_length;
+  int64 last_update_internal;
+  GetContentLengths(kNumDaysInHistorySummary, &original_content_length,
+                    &received_content_length, &last_update_internal);
+
+  if (original_content_length == 0)
+    return;
+
+  int64 user_visible_savings_bytes =
+      original_content_length - received_content_length;
+  int user_visible_savings_percent =
+      user_visible_savings_bytes * 100 / original_content_length;
+  UMA_HISTOGRAM_PERCENTAGE(
+      "Net.DailyUserVisibleSavingsPercent_DataRedictionProxyEnabled",
+      user_visible_savings_percent);
+  UMA_HISTOGRAM_COUNTS(
+      "Net.DailyUserVisibleSavingsSize_DataRedictionProxyEnabled",
+      user_visible_savings_bytes >> 10);
+}
+
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
index 6206adda..0ed7d1b 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
@@ -132,6 +132,11 @@
                                 DataReductionProxyRequestType request_type,
                                 base::Time now);
 
+  // Record UMA with data savings bytes and percent over the past
+  // |DataReductionProxy::kNumDaysInHistorySummary| days. These numbers
+  // are displayed to users as their data savings.
+  void RecordUserVisibleDataSavings();
+
   PrefService* pref_service_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
   const base::TimeDelta delay_;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
index 91e8e33..6beee3cf 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
@@ -4,20 +4,25 @@
 
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
 
-#include <string>
 #include <vector>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/sparse_histogram.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/time/time.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
+#include "components/variations/variations_associated_data.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/load_flags.h"
+#include "net/base/network_quality.h"
+#include "net/base/network_quality_estimator.h"
 #include "net/proxy/proxy_server.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_fetcher_delegate.h"
@@ -25,8 +30,13 @@
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_status.h"
 
+using base::FieldTrialList;
+
 namespace {
 
+const char kEnabled[] = "Enabled";
+const char kControl[] = "Control";
+
 // Values of the UMA DataReductionProxy.NetworkChangeEvents histograms.
 // This enum must remain synchronized with the enum of the same
 // name in metrics/histograms/histograms.xml.
@@ -68,6 +78,43 @@
   return false;
 }
 
+// Values of change in the state of Auto Lo-Fi request headers.
+// Possible Lo-Fi headers are: empty (""), low ("low").
+// This enum must remain synchronized with the enum of the same name in
+// metrics/histograms/histograms.xml.
+enum AutoLoFiRequestHeaderState {
+  AUTO_LOFI_REQUEST_HEADER_STATE_EMPTY_TO_EMPTY = 0,
+  AUTO_LOFI_REQUEST_HEADER_STATE_EMPTY_TO_LOW = 1,
+  AUTO_LOFI_REQUEST_HEADER_STATE_LOW_TO_EMPTY = 2,
+  AUTO_LOFI_REQUEST_HEADER_STATE_LOW_TO_LOW = 3,
+  AUTO_LOFI_REQUEST_HEADER_STATE_INDEX_BOUNDARY
+};
+
+// Following UMA is plotted to measure how frequently Lo-Fi state changes.
+// Too frequent changes are undesirable.
+void RecordAutoLoFiRequestHeaderStateChange(bool previous_header_low,
+                                            bool current_header_low) {
+  AutoLoFiRequestHeaderState state;
+  if (!previous_header_low) {
+    if (current_header_low)
+      state = AUTO_LOFI_REQUEST_HEADER_STATE_EMPTY_TO_LOW;
+    else
+      state = AUTO_LOFI_REQUEST_HEADER_STATE_EMPTY_TO_EMPTY;
+  } else {
+    if (current_header_low) {
+      // Low to low in useful in checking how many consecutive page loads
+      // are done with Lo-Fi enabled.
+      state = AUTO_LOFI_REQUEST_HEADER_STATE_LOW_TO_LOW;
+    } else {
+      state = AUTO_LOFI_REQUEST_HEADER_STATE_LOW_TO_EMPTY;
+    }
+  }
+
+  UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.AutoLoFiRequestHeaderState",
+                            state,
+                            AUTO_LOFI_REQUEST_HEADER_STATE_INDEX_BOUNDARY);
+}
+
 }  // namespace
 
 namespace data_reduction_proxy {
@@ -148,7 +195,11 @@
       config_values_(config_values.Pass()),
       net_log_(net_log),
       configurator_(configurator),
-      event_creator_(event_creator) {
+      event_creator_(event_creator),
+      auto_lofi_minimum_rtt_(base::TimeDelta()),
+      auto_lofi_maximum_kbps_(0),
+      auto_lofi_hysteresis_(base::TimeDelta()),
+      lofi_status_(LOFI_STATUS_TEMPORARILY_OFF) {
   DCHECK(configurator);
   DCHECK(event_creator);
   // Constructed on the UI thread, but should be checked on the IO thread.
@@ -167,6 +218,7 @@
   if (!config_values_->allowed())
     return;
 
+  PopulateAutoLoFiParams();
   AddDefaultProxyBypassRules();
   net::NetworkChangeNotifier::AddIPAddressObserver(this);
 }
@@ -272,8 +324,7 @@
     return AreProxiesBypassed(
         request.context()->proxy_service()->proxy_retry_info(),
         data_reduction_proxy_config.proxy_rules(),
-        request.url().SchemeIs(url::kHttpsScheme),
-        min_retry_delay);
+        request.url().SchemeIsCryptographic(), min_retry_delay);
   }
 
   return false;
@@ -318,34 +369,98 @@
   return bypassed;
 }
 
-bool DataReductionProxyConfig::IsNetworkBad() const {
-  // TODO(tbansal): This must return the network quality based on
-  // network quality estimated by NQE.
+bool DataReductionProxyConfig::IsNetworkQualityProhibitivelySlow(
+    const net::NetworkQualityEstimator* network_quality_estimator) const {
   DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (!network_quality_estimator)
+    return false;
+
+  net::NetworkQuality network_quality =
+      network_quality_estimator->GetEstimate();
+  // TODO(tbansal): Set |network_prohibitively_slow| based on medians
+  // provided by NetworkQualityEstimator API and field trial parameters.
+  // Also, ensure that state of network is not changed more than once within
+  // the hysteresis period.
   return false;
 }
 
 bool DataReductionProxyConfig::IsIncludedInLoFiEnabledFieldTrial() const {
-  // TODO(tbansal): This must return if the current session is in the LoFi
-  // enabled field trial group.
   DCHECK(thread_checker_.CalledOnValidThread());
-  return false;
+  return FieldTrialList::FindFullName(
+             DataReductionProxyParams::GetLoFiFieldTrialName()) == kEnabled;
 }
 
 bool DataReductionProxyConfig::IsIncludedInLoFiControlFieldTrial() const {
-  // TODO(tbansal): This must return if the current session is in the LoFi
-  // control field trial group.
   DCHECK(thread_checker_.CalledOnValidThread());
+  return FieldTrialList::FindFullName(
+             DataReductionProxyParams::GetLoFiFieldTrialName()) == kControl;
+}
+
+LoFiStatus DataReductionProxyConfig::GetLoFiStatus() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return lofi_status_;
+}
+
+// static
+bool DataReductionProxyConfig::ShouldUseLoFiHeaderForRequests(
+    LoFiStatus lofi_status) {
+  switch (lofi_status) {
+    case LOFI_STATUS_OFF:
+    case LOFI_STATUS_TEMPORARILY_OFF:
+    case LOFI_STATUS_ACTIVE_CONTROL:
+    case LOFI_STATUS_INACTIVE_CONTROL:
+    case LOFI_STATUS_INACTIVE:
+      return false;
+    // Lo-Fi header can be used only if Lo-Fi is not temporarily off and either
+    // the user has enabled Lo-Fi through flags, or session is in Lo-Fi enabled
+    // group with network quality prohibitively slow.
+    case LOFI_STATUS_ACTIVE_FROM_FLAGS:
+    case LOFI_STATUS_ACTIVE:
+      return true;
+    default:
+      NOTREACHED() << lofi_status;
+  }
   return false;
 }
 
-AutoLoFiStatus DataReductionProxyConfig::GetAutoLoFiStatus() const {
+bool DataReductionProxyConfig::ShouldUseLoFiHeaderForRequests() const {
   DCHECK(thread_checker_.CalledOnValidThread());
-  if (IsIncludedInLoFiControlFieldTrial() && IsNetworkBad())
-    return AUTO_LOFI_STATUS_OFF;
-  if (IsIncludedInLoFiEnabledFieldTrial() && IsNetworkBad())
-    return AUTO_LOFI_STATUS_ON;
-  return AUTO_LOFI_STATUS_DISABLED;
+  return ShouldUseLoFiHeaderForRequests(lofi_status_);
+}
+
+void DataReductionProxyConfig::PopulateAutoLoFiParams() {
+  if (!IsIncludedInLoFiControlFieldTrial() &&
+      !IsIncludedInLoFiEnabledFieldTrial())
+    return;
+
+  uint64_t auto_lofi_minimum_rtt_msec;
+  std::string variation_value = variations::GetVariationParamValue(
+      DataReductionProxyParams::GetLoFiFieldTrialName(), "rtt_msec");
+  if (!variation_value.empty() &&
+      base::StringToUint64(variation_value, &auto_lofi_minimum_rtt_msec)) {
+    auto_lofi_minimum_rtt_ =
+        base::TimeDelta::FromMilliseconds(auto_lofi_minimum_rtt_msec);
+  }
+
+  uint64_t auto_lofi_maximum_kbps;
+  variation_value = variations::GetVariationParamValue(
+      DataReductionProxyParams::GetLoFiFieldTrialName(), "kbps");
+  if (!variation_value.empty() &&
+      base::StringToUint64(variation_value, &auto_lofi_maximum_kbps)) {
+    auto_lofi_maximum_kbps_ = auto_lofi_maximum_kbps;
+  }
+
+  uint32_t auto_lofi_hysteresis_period_seconds;
+  variation_value = variations::GetVariationParamValue(
+      DataReductionProxyParams::GetLoFiFieldTrialName(),
+      "hysteresis_period_seconds");
+  if (!variation_value.empty() &&
+      base::StringToUint(variation_value,
+                         &auto_lofi_hysteresis_period_seconds)) {
+    auto_lofi_hysteresis_ =
+        base::TimeDelta::FromSeconds(auto_lofi_hysteresis_period_seconds);
+  }
 }
 
 bool DataReductionProxyConfig::IsProxyBypassed(
@@ -607,6 +722,72 @@
                                                      fetcher_callback);
 }
 
+void DataReductionProxyConfig::UpdateLoFiStatusOnMainFrameRequest(
+    bool user_temporarily_disabled_lofi,
+    const net::NetworkQualityEstimator* network_quality_estimator) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // If Lo-Fi has been permanently turned off, its status can't change.
+  if (lofi_status_ == LOFI_STATUS_OFF)
+    return;
+
+  // If the user has temporarily disabled Lo-Fi on a main frame request, it will
+  // remain disabled until next main frame request.
+  if (user_temporarily_disabled_lofi) {
+    switch (lofi_status_) {
+      // Turn off Lo-Fi temporarily (until next main frame request) if it was
+      // enabled from flags or because the session is in Lo-Fi enabled group.
+      case LOFI_STATUS_ACTIVE_FROM_FLAGS:
+      case LOFI_STATUS_ACTIVE:
+      case LOFI_STATUS_INACTIVE:
+        lofi_status_ = LOFI_STATUS_TEMPORARILY_OFF;
+        return;
+      // Lo-Fi is already temporarily off, so no need to change state.
+      case LOFI_STATUS_TEMPORARILY_OFF:
+      // If the current session does not have Lo-Fi switch, is not in Auto Lo-Fi
+      // enabled group and is in Auto Lo-Fi control group, then we do not need
+      // to temporarily disable Lo-Fi because it would never be used.
+      case LOFI_STATUS_ACTIVE_CONTROL:
+      case LOFI_STATUS_INACTIVE_CONTROL:
+        return;
+
+      default:
+        NOTREACHED() << "Unexpected Lo-Fi status = " << lofi_status_;
+    }
+  }
+
+  if (DataReductionProxyParams::IsLoFiEnabledThroughSwitch()) {
+    lofi_status_ = LOFI_STATUS_ACTIVE_FROM_FLAGS;
+    return;
+  }
+
+  if (IsIncludedInLoFiControlFieldTrial()) {
+    lofi_status_ = IsNetworkQualityProhibitivelySlow(network_quality_estimator)
+                       ? LOFI_STATUS_ACTIVE_CONTROL
+                       : LOFI_STATUS_INACTIVE_CONTROL;
+    return;
+  }
+
+  // Store the previous state of Lo-Fi, so that change in Lo-Fi status can be
+  // recorded properly. This is not needed for the control group, because it
+  // is only used to report changes in request headers, and the request headers
+  // are never modified in the control group.
+  LoFiStatus previous_lofi_status = lofi_status_;
+
+  if (IsIncludedInLoFiEnabledFieldTrial()) {
+    lofi_status_ = IsNetworkQualityProhibitivelySlow(network_quality_estimator)
+                       ? LOFI_STATUS_ACTIVE
+                       : LOFI_STATUS_INACTIVE;
+    RecordAutoLoFiRequestHeaderStateChange(
+        ShouldUseLoFiHeaderForRequests(previous_lofi_status),
+        ShouldUseLoFiHeaderForRequests(lofi_status_));
+    return;
+  }
+  // If Lo-Fi is not enabled through command line and the user is not in
+  // Lo-Fi field trials, we set Lo-Fi to permanent off.
+  lofi_status_ = LOFI_STATUS_OFF;
+}
+
 void DataReductionProxyConfig::GetNetworkList(
     net::NetworkInterfaceList* interfaces,
     int policy) {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
index 53e9e7bd..074f913 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_CONFIG_H_
 #define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_DATA_REDUCTION_PROXY_CONFIG_H_
 
+#include <stdint.h>
+
 #include <string>
 
 #include "base/callback.h"
@@ -29,6 +31,7 @@
 namespace net {
 class HostPortPair;
 class NetLog;
+class NetworkQualityEstimator;
 class URLFetcher;
 class URLRequest;
 class URLRequestContextGetter;
@@ -78,21 +81,36 @@
   SECURE_PROXY_CHECK_FETCH_RESULT_COUNT
 };
 
-// Auto LoFi current status.
-enum AutoLoFiStatus {
-  // Auto LoFi is either off or the current network conditions are not worse
-  // than the ones specified in Auto LoFi field trial parameters.
-  AUTO_LOFI_STATUS_DISABLED = 0,
+// Values of the |lofi_status_|.
+// Default state is |LOFI_STATUS_TEMPORARILY_OFF|.
+enum LoFiStatus {
+  // Used if Lo-Fi is permanently off.
+  LOFI_STATUS_OFF = 0,
 
-  // Auto LoFi is off but the current network conditions are worse than the
-  // ones specified in Auto LoFi field trial parameters.
-  AUTO_LOFI_STATUS_OFF,
+  // Used if Lo-Fi is disabled temporarily through direct or indirect user
+  // action. The state would be reset on next main frame request.
+  LOFI_STATUS_TEMPORARILY_OFF,
 
-  // Auto LoFi is on and but the current network conditions are worse than the
-  // ones specified in Auto LoFi field trial parameters.
-  AUTO_LOFI_STATUS_ON,
+  // Used if Lo-Fi is enabled through flags.
+  LOFI_STATUS_ACTIVE_FROM_FLAGS,
 
-  AUTO_LOFI_STATUS_LAST = AUTO_LOFI_STATUS_ON
+  // Session is in Auto Lo-Fi Control group and the current conditions are
+  // suitable to use Lo-Fi "q=low" header.
+  LOFI_STATUS_ACTIVE_CONTROL,
+
+  // Session is in Auto Lo-Fi Control group and the current conditions are
+  // not suitable to use Lo-Fi "q=low" header.
+  LOFI_STATUS_INACTIVE_CONTROL,
+
+  // Session is in Auto Lo-Fi enabled group and the current conditions are
+  // suitable to use Lo-Fi "q=low" header.
+  LOFI_STATUS_ACTIVE,
+
+  // Session is in Auto Lo-Fi enabled group and the current conditions are
+  // not suitable to use Lo-Fi "q=low" header.
+  LOFI_STATUS_INACTIVE,
+
+  LOFI_STATUS_LAST = LOFI_STATUS_INACTIVE
 };
 
 // Central point for holding the Data Reduction Proxy configuration.
@@ -208,9 +226,21 @@
   // tied to whether the Data Reduction Proxy is enabled.
   bool promo_allowed() const;
 
-  // Returns the Auto LoFi status. Enabling LoFi from command line switch has
-  // no effect on Auto LoFi.
-  AutoLoFiStatus GetAutoLoFiStatus() const;
+  // Returns the Lo-Fi status.
+  LoFiStatus GetLoFiStatus() const;
+
+  // Returns true only if Lo-Fi "q=low" header should be added to the Chrome
+  // Proxy header.
+  // Should be called on all URL requests (main frame and non main frame).
+  bool ShouldUseLoFiHeaderForRequests() const;
+
+  // Updates |lofi_status_| based on the arguments provided and the current
+  // value of |lofi_status_|.
+  // |network_quality_estimator| may be NULL.
+  // Should be called only on main frame loads.
+  void UpdateLoFiStatusOnMainFrameRequest(
+      bool user_temporarily_disabled_lofi,
+      const net::NetworkQualityEstimator* network_quality_estimator);
 
  protected:
   // Writes a warning to the log that is used in backend processing of
@@ -247,6 +277,8 @@
                            TestMaybeDisableIfVPNTrialDisabled);
   FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigTest,
                            TestMaybeDisableIfVPNTrialEnabled);
+  FRIEND_TEST_ALL_PREFIXES(DataReductionProxyConfigTest,
+                           PopulateAutoLoFiParams);
 
   // NetworkChangeNotifier::IPAddressObserver:
   void OnIPAddressChanged() override;
@@ -257,6 +289,10 @@
                                   bool restricted,
                                   bool at_startup);
 
+  // Populates the parameters for the Lo-Fi field trial if the session is part
+  // of either Lo-Fi enabled or Lo-Fi control field trial group.
+  void PopulateAutoLoFiParams();
+
   // Requests the given |secure_proxy_check_url|. Upon completion, returns the
   // results to the caller via the |fetcher_callback|. Virtualized for unit
   // testing.
@@ -290,18 +326,25 @@
       bool is_https,
       base::TimeDelta* min_retry_delay) const;
 
-  // Returns true if this client is part of LoFi enabled field trial.
-  // Virtualized for mocking.
+  // Returns true if this client is part of Lo-Fi enabled field trial.
+  // Virtualized for unit testing.
   virtual bool IsIncludedInLoFiEnabledFieldTrial() const;
 
-  // Returns true if this client is part of LoFi control field trial.
-  // Virtualized for mocking.
+  // Returns true if this client is part of Lo-Fi control field trial.
+  // Virtualized for unit testing.
   virtual bool IsIncludedInLoFiControlFieldTrial() const;
 
-  // Returns true if current network conditions are worse than the ones
-  // specified in the enabled or control field trial group parameters.
-  // Virtualized for mocking.
-  virtual bool IsNetworkBad() const;
+  // Returns true if expected throughput is lower than the one specified in the
+  // Auto Lo-Fi field trial parameters OR if the expected round trip time is
+  // higher than the one specified in the Auto Lo-Fi field trial parameters.
+  // |network_quality_estimator| may be NULL.
+  // Virtualized for unit testing.
+  virtual bool IsNetworkQualityProhibitivelySlow(
+      const net::NetworkQualityEstimator* network_quality_estimator) const;
+
+  // Returns true only if Lo-Fi "q=low" header should be added to the Chrome
+  // Proxy header based on the value of |lofi_status|.
+  static bool ShouldUseLoFiHeaderForRequests(LoFiStatus lofi_status);
 
   scoped_ptr<SecureProxyChecker> secure_proxy_checker_;
 
@@ -333,6 +376,23 @@
   // Enforce usage on the IO thread.
   base::ThreadChecker thread_checker_;
 
+  // Thresholds from the field trial at which auto Lo-Fi is turned on.
+  // If the expected round trip time is higher than |auto_lofi_minimum_rtt_|,
+  // auto Lo-Fi would be turned on.
+  base::TimeDelta auto_lofi_minimum_rtt_;
+
+  // If the expected throughput in Kbps is lower than
+  // |auto_lofi_maximum_kbps_|, auto Lo-Fi would be turned on.
+  uint64_t auto_lofi_maximum_kbps_;
+
+  // State of auto Lo-Fi is not changed more than once in any period of
+  // duration shorter than |auto_lofi_hysteresis_|.
+  base::TimeDelta auto_lofi_hysteresis_;
+
+  // Current Lo-Fi status.
+  // The value changes only on main frame load.
+  LoFiStatus lofi_status_;
+
   DISALLOW_COPY_AND_ASSIGN(DataReductionProxyConfig);
 };
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
index a9950ce6..e5714e4 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
@@ -13,6 +13,10 @@
 
 using testing::_;
 
+namespace net {
+class NetworkQualityEstimator;
+}
+
 namespace data_reduction_proxy {
 
 TestDataReductionProxyConfig::TestDataReductionProxyConfig(
@@ -38,13 +42,20 @@
     : DataReductionProxyConfig(net_log,
                                config_values.Pass(),
                                configurator,
-                               event_creator) {
+                               event_creator),
+      auto_lofi_enabled_group_(false),
+      network_quality_prohibitively_slow_(false) {
   network_interfaces_.reset(new net::NetworkInterfaceList());
 }
 
 TestDataReductionProxyConfig::~TestDataReductionProxyConfig() {
 }
 
+bool TestDataReductionProxyConfig::IsNetworkQualityProhibitivelySlow(
+    const net::NetworkQualityEstimator* network_quality_estimator) const {
+  return network_quality_prohibitively_slow_;
+}
+
 void TestDataReductionProxyConfig::GetNetworkList(
     net::NetworkInterfaceList* interfaces,
     int policy) {
@@ -83,6 +94,24 @@
   secure_proxy_allowed_ = secure_proxy_allowed;
 }
 
+void TestDataReductionProxyConfig::ResetLoFiStatusForTest() {
+  lofi_status_ = LoFiStatus::LOFI_STATUS_TEMPORARILY_OFF;
+}
+
+bool TestDataReductionProxyConfig::IsIncludedInLoFiEnabledFieldTrial() const {
+  return auto_lofi_enabled_group_;
+}
+
+void TestDataReductionProxyConfig::SetIncludedInLoFiEnabledFieldTrial(
+    bool auto_lofi_enabled_group) {
+  auto_lofi_enabled_group_ = auto_lofi_enabled_group;
+}
+
+void TestDataReductionProxyConfig::SetNetworkProhibitivelySlow(
+    bool network_quality_prohibitively_slow) {
+  network_quality_prohibitively_slow_ = network_quality_prohibitively_slow;
+}
+
 MockDataReductionProxyConfig::MockDataReductionProxyConfig(
     scoped_ptr<DataReductionProxyConfigValues> config_values,
     net::NetLog* net_log,
@@ -107,4 +136,8 @@
       enabled, alternative_enabled, secure_proxy_allowed, at_startup);
 }
 
+void MockDataReductionProxyConfig::ResetLoFiStatusForTest() {
+  lofi_status_ = LoFiStatus::LOFI_STATUS_TEMPORARILY_OFF;
+}
+
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
index 5758ef4..d31ed9a 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
@@ -11,6 +11,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace net {
+class NetworkQualityEstimator;
 class NetLog;
 }
 
@@ -67,12 +68,33 @@
                        bool alternative_enabled_by_user,
                        bool secure_proxy_enabled);
 
+  // Resets the Lo-Fi status to default state.
+  void ResetLoFiStatusForTest();
+
+  bool IsIncludedInLoFiEnabledFieldTrial() const override;
+
+  // Allows tests to set the session as part of Lo-Fi enabled field trial.
+  void SetIncludedInLoFiEnabledFieldTrial(bool included_in_lofi_enabled);
+
+  // Allows tests to mark the network as prohibitively slow.
+  void SetNetworkProhibitivelySlow(bool network_quality_prohibitively_slow);
+
+  bool IsNetworkQualityProhibitivelySlow(
+      const net::NetworkQualityEstimator* network_quality_estimator)
+      const override;
+
   net::NetworkInterfaceList* interfaces() {
     return network_interfaces_.get();
   }
 
  private:
   scoped_ptr<net::NetworkInterfaceList> network_interfaces_;
+
+  // True if this session is part of Auto Lo-Fi enabled field trial.
+  bool auto_lofi_enabled_group_;
+
+  // True if network quality is slow enough to turn Auto Lo-Fi ON.
+  bool network_quality_prohibitively_slow_;
 };
 
 // A |TestDataReductionProxyConfig| which permits mocking of methods for
@@ -111,7 +133,9 @@
   MOCK_METHOD2(SecureProxyCheck,
                void(const GURL& secure_proxy_check_url,
                     FetcherResponseCallback fetcher_callback));
-  MOCK_CONST_METHOD0(IsNetworkBad, bool());
+  MOCK_CONST_METHOD1(
+      IsNetworkQualityProhibitivelySlow,
+      bool(const net::NetworkQualityEstimator* network_quality_estimator));
   MOCK_CONST_METHOD0(IsIncludedInLoFiEnabledFieldTrial, bool());
   MOCK_CONST_METHOD0(IsIncludedInLoFiControlFieldTrial, bool());
 
@@ -120,6 +144,9 @@
                           bool alternative_enabled,
                           bool restricted,
                           bool at_startup) override;
+
+  // Resets the Lo-Fi status to default state.
+  void ResetLoFiStatusForTest();
 };
 
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
index 54afe92..b1e63166 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
@@ -7,7 +7,9 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/metrics/field_trial.h"
 #include "base/strings/string_util.h"
+#include "base/time/time.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_test_utils.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h"
@@ -16,6 +18,7 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
+#include "components/variations/variations_associated_data.h"
 #include "net/http/http_status_code.h"
 #include "net/log/test_net_log.h"
 #include "net/proxy/proxy_server.h"
@@ -1105,4 +1108,135 @@
   }
 }
 
+TEST_F(DataReductionProxyConfigTest, LoFiOn) {
+  const struct {
+    bool lofi_switch_enabled;
+    bool lofi_enabled_field_trial_group;
+    bool network_prohibitively_slow;
+    bool expect_lofi_header;
+
+  } tests[] = {
+      {
+       // Lo-Fi off.
+       false,
+       false,
+       false,
+       false,
+      },
+      {
+       // In enabled field trial group but network quality is not bad.
+       false,
+       true,
+       false,
+       false,
+      },
+      {
+       // Not in enabled field trial group and network quality is bad.
+       false,
+       false,
+       true,
+       false,
+      },
+      {
+       // In enabled field trial group and network quality is bad.
+       false,
+       true,
+       true,
+       true,
+      },
+      {
+       // Lo-Fi enabled through command line switch.
+       true,
+       false,
+       false,
+       true,
+      },
+  };
+  for (size_t i = 0; i < arraysize(tests); ++i) {
+    config()->ResetLoFiStatusForTest();
+    if (tests[i].lofi_switch_enabled) {
+      base::CommandLine::ForCurrentProcess()->AppendSwitch(
+          data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
+    }
+
+    EXPECT_CALL(*config(), IsIncludedInLoFiEnabledFieldTrial())
+        .WillRepeatedly(
+            testing::Return(tests[i].lofi_enabled_field_trial_group));
+
+    EXPECT_CALL(*config(), IsNetworkQualityProhibitivelySlow(_))
+        .WillRepeatedly(testing::Return(tests[i].network_prohibitively_slow));
+
+    config()->UpdateLoFiStatusOnMainFrameRequest(false, nullptr);
+
+    EXPECT_EQ(tests[i].expect_lofi_header,
+              config()->ShouldUseLoFiHeaderForRequests())
+        << i;
+  }
+}
+
+TEST_F(DataReductionProxyConfigTest, LoFiStatusTransition) {
+  const struct {
+    bool lofi_switch_enabled;
+  } tests[] = {
+      {
+       false,
+      },
+      {
+       true,
+      },
+  };
+
+  for (size_t i = 0; i < arraysize(tests); ++i) {
+    config()->ResetLoFiStatusForTest();
+    if (tests[i].lofi_switch_enabled) {
+      base::CommandLine::ForCurrentProcess()->AppendSwitch(
+          data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
+    } else {
+      EXPECT_CALL(*config(), IsIncludedInLoFiEnabledFieldTrial())
+          .WillRepeatedly(testing::Return(true));
+
+      EXPECT_CALL(*config(), IsNetworkQualityProhibitivelySlow(_))
+          .WillRepeatedly(testing::Return(true));
+    }
+
+    // First, set the status to enabled.
+    config()->UpdateLoFiStatusOnMainFrameRequest(false, nullptr);
+    EXPECT_EQ(true, config()->ShouldUseLoFiHeaderForRequests()) << i;
+
+    // Full page reload with Lo-Fi disabled (main frame request).
+    config()->UpdateLoFiStatusOnMainFrameRequest(true, nullptr);
+    EXPECT_FALSE(config()->ShouldUseLoFiHeaderForRequests()) << i;
+
+    // New page load (main frame request).
+    config()->UpdateLoFiStatusOnMainFrameRequest(false, nullptr);
+    EXPECT_EQ(true, config()->ShouldUseLoFiHeaderForRequests()) << i;
+  }
+}
+
+TEST_F(DataReductionProxyConfigTest, PopulateAutoLoFiParams) {
+  variations::testing::ClearAllVariationParams();
+  std::map<std::string, std::string> variation_params;
+  variation_params["rtt_msec"] = "120";
+  variation_params["kbps"] = "240";
+  variation_params["hysteresis_period_seconds"] = "360";
+  variation_params["spurious_field"] = "480";
+
+  ASSERT_TRUE(variations::AssociateVariationParams(
+      DataReductionProxyParams::GetLoFiFieldTrialName(), "Enabled",
+      variation_params));
+  EXPECT_CALL(*config(), IsIncludedInLoFiEnabledFieldTrial())
+      .WillRepeatedly(testing::Return(true));
+
+  base::FieldTrialList field_trial_list(nullptr);
+  base::FieldTrialList::CreateFieldTrial(
+      DataReductionProxyParams::GetLoFiFieldTrialName(), "Enabled");
+
+  config()->PopulateAutoLoFiParams();
+
+  EXPECT_EQ(config()->auto_lofi_minimum_rtt_,
+            base::TimeDelta::FromMilliseconds(120));
+  EXPECT_EQ(config()->auto_lofi_maximum_kbps_, 240U);
+  EXPECT_EQ(config()->auto_lofi_hysteresis_, base::TimeDelta::FromSeconds(360));
+}
+
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
index 7c8ebf5..0c21098 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
@@ -278,6 +278,15 @@
                  data_reduction_proxy_enabled, request_type));
 }
 
+void DataReductionProxyIOData::SetLoFiModeActiveOnMainFrame(
+    bool lo_fi_mode_active) {
+  DCHECK(io_task_runner_->BelongsToCurrentThread());
+  ui_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&DataReductionProxyService::SetLoFiModeActiveOnMainFrame,
+                 service_, lo_fi_mode_active));
+}
+
 void DataReductionProxyIOData::AddEvent(scoped_ptr<base::Value> event) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   ui_task_runner_->PostTask(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
index ad533c0..d63529f8 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h
@@ -93,6 +93,7 @@
                             int64 original_content_length,
                             bool data_reduction_proxy_enabled,
                             DataReductionProxyRequestType request_type);
+  void SetLoFiModeActiveOnMainFrame(bool lo_fi_mode_active);
 
   // Overrides of DataReductionProxyEventStorageDelegate. Bridges to the UI
   // thread objects.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
index 0338194..164f082 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -23,14 +23,24 @@
 #include "net/proxy/proxy_server.h"
 #include "net/proxy/proxy_service.h"
 #include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_status.h"
 
 namespace {
 
-void RecordContentLengthHistograms(
-    int64 received_content_length,
-    int64 original_content_length,
-    const base::TimeDelta& freshness_lifetime) {
+class NetworkQualityEstimator;
+
+// |lofi_low_header_added| is set to true iff Lo-Fi "q=low" request header can
+// be added to the Chrome proxy headers.
+// |received_content_length| is the number of prefilter bytes received.
+// |original_content_length| is the length of resource if accessed directly
+// without data saver proxy.
+// |freshness_lifetime| contains information on how long the resource will be
+// fresh for and how long is the usability.
+void RecordContentLengthHistograms(bool lofi_low_header_added,
+                                   int64 received_content_length,
+                                   int64 original_content_length,
+                                   const base::TimeDelta& freshness_lifetime) {
   // Add the current resource to these histograms only when a valid
   // X-Original-Content-Length header is present.
   if (original_content_length >= 0) {
@@ -40,6 +50,17 @@
                          original_content_length);
     UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthDifferenceWithValidOCL",
                          original_content_length - received_content_length);
+
+    // Populate Lo-Fi content length histograms.
+    if (lofi_low_header_added) {
+      UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthWithValidOCL.LoFiOn",
+                           received_content_length);
+      UMA_HISTOGRAM_COUNTS("Net.HttpOriginalContentLengthWithValidOCL.LoFiOn",
+                           original_content_length);
+      UMA_HISTOGRAM_COUNTS("Net.HttpContentLengthDifferenceWithValidOCL.LoFiOn",
+                           original_content_length - received_content_length);
+    }
+
   } else {
     // Presume the original content length is the same as the received content
     // length if the X-Original-Content-Header is not present.
@@ -153,6 +174,25 @@
     net::URLRequest* request,
     const net::ProxyInfo& proxy_info,
     net::HttpRequestHeaders* headers) {
+  DCHECK(data_reduction_proxy_config_);
+  DCHECK(request);
+
+  // TODO(bengr): Investigate a better approach to update the network
+  // quality so that state of Lo-Fi is stored per page.
+  net::NetworkQualityEstimator* network_quality_estimator = nullptr;
+  if (request->context())
+    network_quality_estimator = request->context()->network_quality_estimator();
+
+  if (request->load_flags() & net::LOAD_MAIN_FRAME) {
+    data_reduction_proxy_config_->UpdateLoFiStatusOnMainFrameRequest(
+        ((request->load_flags() & net::LOAD_BYPASS_CACHE) != 0),
+        network_quality_estimator);
+    if (data_reduction_proxy_io_data_) {
+      data_reduction_proxy_io_data_->SetLoFiModeActiveOnMainFrame(
+          data_reduction_proxy_config_->ShouldUseLoFiHeaderForRequests());
+    }
+  }
+
   if (data_reduction_proxy_request_options_) {
     data_reduction_proxy_request_options_->MaybeAddRequestHeader(
         request, proxy_info.proxy_server(), headers);
@@ -198,9 +238,17 @@
     AccumulateContentLength(received_content_length,
                             adjusted_original_content_length,
                             request_type);
-    RecordContentLengthHistograms(received_content_length,
-                                  original_content_length,
-                                  freshness_lifetime);
+
+    DCHECK(data_reduction_proxy_config_);
+
+    // TODO(bengr): Investigate a better approach to record the Lo-Fi
+    // histogram. State of Lo-Fi should be stored per page.
+    RecordContentLengthHistograms(
+        // |data_reduction_proxy_io_data_| can be NULL for Webview.
+        data_reduction_proxy_io_data_ &&
+            data_reduction_proxy_io_data_->IsEnabled() &&
+            data_reduction_proxy_config_->ShouldUseLoFiHeaderForRequests(),
+        received_content_length, original_content_length, freshness_lifetime);
     experiments_stats_->RecordBytes(request->request_time(), request_type,
                                     received_content_length,
                                     original_content_length);
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
index 11e4246..c016af2 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -4,11 +4,15 @@
 
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h"
 
+#include <string>
+
+#include "base/command_line.h"
 #include "base/metrics/field_trial.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/histogram_tester.h"
 #include "base/test/mock_entropy_provider.h"
 #include "base/time/time.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h"
@@ -16,6 +20,7 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_response_headers.h"
@@ -85,12 +90,37 @@
             test_context_->configurator(),
             test_context_->io_data()->experiments_stats(),
             test_context_->net_log(), test_context_->event_creator()));
+
+    bypass_stats_.reset(new DataReductionProxyBypassStats(
+        config(), test_context_->unreachable_callback()));
+
+    data_reduction_proxy_network_delegate_->InitIODataAndUMA(
+        test_context_->io_data(), bypass_stats_.get());
   }
 
   const net::ProxyConfig& GetProxyConfig() const {
     return config_;
   }
 
+  MockDataReductionProxyConfig* config() const {
+    return test_context_->mock_config();
+  }
+
+  static void VerifyLoFiHeader(bool expected_lofi_used,
+                               const net::HttpRequestHeaders& headers) {
+    EXPECT_TRUE(headers.HasHeader(kChromeProxyHeader));
+    std::string header_value;
+    headers.GetHeader(kChromeProxyHeader, &header_value);
+    EXPECT_EQ(expected_lofi_used,
+              header_value.find("q=low") != std::string::npos);
+  }
+
+  void VerifyWasLoFiModeActiveOnMainFrame(bool expected_value) {
+    test_context_->RunUntilIdle();
+    EXPECT_EQ(expected_value,
+              test_context_->settings()->WasLoFiModeActiveOnMainFrame());
+  }
+
  protected:
   scoped_ptr<net::URLRequest> FetchURLRequest(
       const GURL& url,
@@ -151,6 +181,7 @@
   net::ProxyConfig config_;
   net::NetworkDelegate* network_delegate_;
   scoped_ptr<DataReductionProxyTestContext> test_context_;
+  scoped_ptr<DataReductionProxyBypassStats> bypass_stats_;
 };
 
 TEST_F(DataReductionProxyNetworkDelegateTest, AuthenticationTest) {
@@ -174,6 +205,133 @@
   EXPECT_TRUE(header_value.find("sid=") != std::string::npos);
 }
 
+TEST_F(DataReductionProxyNetworkDelegateTest, LoFiTransitions) {
+  set_network_delegate(data_reduction_proxy_network_delegate_.get());
+  // Enable Lo-Fi.
+  const struct {
+    bool lofi_switch_enabled;
+    bool auto_lofi_enabled;
+  } tests[] = {
+      {
+       // Lo-Fi enabled through switch.
+       false,
+       true,
+      },
+      {
+       // Lo-Fi enabled through field trial.
+       true,
+       false,
+      },
+  };
+
+  for (size_t i = 0; i < arraysize(tests); ++i) {
+    if (tests[i].lofi_switch_enabled) {
+      base::CommandLine::ForCurrentProcess()->AppendSwitch(
+          data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
+    }
+    config()->SetIncludedInLoFiEnabledFieldTrial(tests[i].auto_lofi_enabled);
+    config()->SetNetworkProhibitivelySlow(tests[i].auto_lofi_enabled);
+
+    net::ProxyInfo data_reduction_proxy_info;
+    std::string data_reduction_proxy;
+    base::TrimString(params()->DefaultOrigin(), "/", &data_reduction_proxy);
+    data_reduction_proxy_info.UseNamedProxy(data_reduction_proxy);
+
+    {
+      // Main frame loaded. Lo-Fi should be used.
+      net::HttpRequestHeaders headers;
+
+      scoped_ptr<net::URLRequest> fake_request(
+          FetchURLRequest(GURL("http://www.google.com/"), std::string(), 0));
+      fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME);
+      data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders(
+          fake_request.get(), data_reduction_proxy_info, &headers);
+      VerifyLoFiHeader(true, headers);
+      VerifyWasLoFiModeActiveOnMainFrame(true);
+    }
+
+    {
+      // Bypass cache flag used. Lo-Fi should not be used.
+      net::HttpRequestHeaders headers;
+      scoped_ptr<net::URLRequest> fake_request(
+          FetchURLRequest(GURL("http://www.google.com/"), std::string(), 0));
+      fake_request->SetLoadFlags(net::LOAD_BYPASS_CACHE);
+      data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders(
+          fake_request.get(), data_reduction_proxy_info, &headers);
+      VerifyLoFiHeader(false, headers);
+      // Not a mainframe request, WasLoFiModeActiveOnMainFrame should still be
+      // true.
+      VerifyWasLoFiModeActiveOnMainFrame(true);
+    }
+
+    {
+      // Bypass cache flag not used. Lo-Fi should be used.
+      net::HttpRequestHeaders headers;
+      scoped_ptr<net::URLRequest> fake_request(
+          FetchURLRequest(GURL("http://www.google.com/"), std::string(), 0));
+
+      data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders(
+          fake_request.get(), data_reduction_proxy_info, &headers);
+      VerifyLoFiHeader(true, headers);
+      // Not a mainframe request, WasLoFiModeActiveOnMainFrame should still be
+      // true.
+      VerifyWasLoFiModeActiveOnMainFrame(true);
+    }
+
+    {
+      // Bypass cache flag used. Lo-Fi should not be used.
+      net::HttpRequestHeaders headers;
+      scoped_ptr<net::URLRequest> fake_request(
+          FetchURLRequest(GURL("http://www.google.com/"), std::string(), 0));
+      fake_request->SetLoadFlags(net::LOAD_BYPASS_CACHE);
+      data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders(
+          fake_request.get(), data_reduction_proxy_info, &headers);
+      VerifyLoFiHeader(false, headers);
+      // Not a mainframe request, WasLoFiModeActiveOnMainFrame should still be
+      // true.
+      VerifyWasLoFiModeActiveOnMainFrame(true);
+    }
+
+    {
+      // Main frame request with bypass cache flag. Lo-Fi should not be used.
+      // State of Lo-Fi should persist until next page load.
+      net::HttpRequestHeaders headers;
+      scoped_ptr<net::URLRequest> fake_request(
+          FetchURLRequest(GURL("http://www.google.com/"), std::string(), 0));
+      fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME | net::LOAD_BYPASS_CACHE);
+      data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders(
+          fake_request.get(), data_reduction_proxy_info, &headers);
+      VerifyLoFiHeader(false, headers);
+      VerifyWasLoFiModeActiveOnMainFrame(false);
+    }
+
+    {
+      // Bypass cache flag not used. Lo-Fi is still not used.
+      net::HttpRequestHeaders headers;
+      scoped_ptr<net::URLRequest> fake_request(
+          FetchURLRequest(GURL("http://www.google.com/"), std::string(), 0));
+      data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders(
+          fake_request.get(), data_reduction_proxy_info, &headers);
+      VerifyLoFiHeader(false, headers);
+      // Not a mainframe request, WasLoFiModeActiveOnMainFrame should still be
+      // false.
+      VerifyWasLoFiModeActiveOnMainFrame(false);
+    }
+
+    {
+      // Main frame request. Lo-Fi should be used.
+      net::HttpRequestHeaders headers;
+      scoped_ptr<net::URLRequest> fake_request(
+          FetchURLRequest(GURL("http://www.google.com/"), std::string(), 0));
+      fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME);
+      data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders(
+          fake_request.get(), data_reduction_proxy_info, &headers);
+      VerifyLoFiHeader(true, headers);
+      VerifyWasLoFiModeActiveOnMainFrame(true);
+    }
+  }
+}
+
 TEST_F(DataReductionProxyNetworkDelegateTest, NetHistograms) {
   const std::string kReceivedValidOCLHistogramName =
       "Net.HttpContentLengthWithValidOCL";
@@ -181,6 +339,15 @@
       "Net.HttpOriginalContentLengthWithValidOCL";
   const std::string kDifferenceValidOCLHistogramName =
       "Net.HttpContentLengthDifferenceWithValidOCL";
+
+  // Lo-Fi histograms.
+  const std::string kReceivedValidOCLLoFiOnHistogramName =
+      "Net.HttpContentLengthWithValidOCL.LoFiOn";
+  const std::string kOriginalValidOCLLoFiOnHistogramName =
+      "Net.HttpOriginalContentLengthWithValidOCL.LoFiOn";
+  const std::string kDifferenceValidOCLLoFiOnHistogramName =
+      "Net.HttpContentLengthDifferenceWithValidOCL.LoFiOn";
+
   const std::string kReceivedHistogramName = "Net.HttpContentLength";
   const std::string kOriginalHistogramName = "Net.HttpOriginalContentLength";
   const std::string kDifferenceHistogramName =
@@ -239,6 +406,82 @@
                                       kResponseContentLength, 1);
   histogram_tester.ExpectUniqueSample(kCacheable24HoursHistogramName,
                                       kResponseContentLength, 1);
+
+  // Check Lo-Fi histograms.
+  const struct {
+    bool lofi_enabled_through_switch;
+    bool auto_lofi_enabled;
+    int expected_count;
+
+  } tests[] = {
+      {
+       // Lo-Fi disabled.
+       false,
+       false,
+       0,
+      },
+      {
+       // Auto Lo-Fi enabled.
+       // This should populate Lo-Fi content length histogram.
+       false,
+       true,
+       1,
+      },
+      {
+       // Lo-Fi enabled through switch.
+       // This should populate Lo-Fi content length histogram.
+       true,
+       false,
+       1,
+      },
+      {
+       // Lo-Fi enabled through switch and Auto Lo-Fi also enabled.
+       // This should populate Lo-Fi content length histogram.
+       true,
+       true,
+       1,
+      },
+  };
+
+  for (size_t i = 0; i < arraysize(tests); ++i) {
+    config()->ResetLoFiStatusForTest();
+    config()->SetIncludedInLoFiEnabledFieldTrial(tests[i].auto_lofi_enabled);
+    config()->SetNetworkProhibitivelySlow(tests[i].auto_lofi_enabled);
+
+    if (tests[i].lofi_enabled_through_switch) {
+      base::CommandLine::ForCurrentProcess()->AppendSwitch(
+          data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
+    }
+
+    config()->UpdateLoFiStatusOnMainFrameRequest(false, nullptr);
+
+    fake_request = (FetchURLRequest(GURL("http://www.example.com/"),
+                                    raw_headers, kResponseContentLength));
+
+    // Histograms are accumulative, so get the sum of all the tests so far.
+    int expected_count = 0;
+    for (size_t j = 0; j <= i; ++j)
+      expected_count += tests[j].expected_count;
+
+    if (expected_count == 0) {
+      histogram_tester.ExpectTotalCount(kReceivedValidOCLLoFiOnHistogramName,
+                                        expected_count);
+      histogram_tester.ExpectTotalCount(kOriginalValidOCLLoFiOnHistogramName,
+                                        expected_count);
+      histogram_tester.ExpectTotalCount(kDifferenceValidOCLLoFiOnHistogramName,
+                                        expected_count);
+    } else {
+      histogram_tester.ExpectUniqueSample(kReceivedValidOCLLoFiOnHistogramName,
+                                          kResponseContentLength,
+                                          expected_count);
+      histogram_tester.ExpectUniqueSample(kOriginalValidOCLLoFiOnHistogramName,
+                                          kOriginalContentLength,
+                                          expected_count);
+      histogram_tester.ExpectUniqueSample(
+          kDifferenceValidOCLLoFiOnHistogramName,
+          kOriginalContentLength - kResponseContentLength, expected_count);
+    }
+  }
 }
 
 TEST_F(DataReductionProxyNetworkDelegateTest, OnResolveProxyHandler) {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
index 96017f44..6ddc62a 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.cc
@@ -17,7 +17,6 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_client_config_parser.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
@@ -40,12 +39,6 @@
   return name + "=" + value;
 }
 
-bool ShouldForceDisableLoFi(const net::URLRequest* request) {
-  if (!request)
-    return false;
-  return (request->load_flags() & net::LOAD_BYPASS_CACHE) != 0;
-}
-
 }  // namespace
 
 const char kSessionHeaderOption[] = "ps";
@@ -136,7 +129,6 @@
 void DataReductionProxyRequestOptions::Init() {
   key_ = GetDefaultKey(),
   UpdateCredentials();
-  UpdateLoFi(false);
   UpdateVersion();
   UpdateExperiments();
 }
@@ -166,24 +158,29 @@
   RegenerateRequestHeaderValue();
 }
 
-void DataReductionProxyRequestOptions::UpdateLoFi(bool force_disable_lo_fi) {
-  if (force_disable_lo_fi) {
-    if (lofi_.empty())
-      return;
-    lofi_ = std::string();
-    RegenerateRequestHeaderValue();
+void DataReductionProxyRequestOptions::MayRegenerateHeaderBasedOnLoFi(
+    const net::URLRequest* request) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (!data_reduction_proxy_config_)
     return;
-  }
-  // LoFi was not enabled, but now is. Add the header option.
-  if (lofi_.empty() && DataReductionProxyParams::IsLoFiEnabled()) {
+
+  bool lofi_now_enabled =
+      !(request && request->load_flags() & net::LOAD_BYPASS_CACHE) &&
+      data_reduction_proxy_config_->ShouldUseLoFiHeaderForRequests();
+
+  // Lo-Fi was not enabled, but now is. Add the header option.
+  if (lofi_.empty() && lofi_now_enabled) {
     lofi_ = "low";
     RegenerateRequestHeaderValue();
     return;
   }
-  // LoFi was enabled, but no longer is. Remove the header option.
-  if (!lofi_.empty() && !DataReductionProxyParams::IsLoFiEnabled()) {
+
+  // Lo-Fi was enabled, but no longer is. Remove the header option.
+  if (!lofi_.empty() && !lofi_now_enabled) {
     lofi_ = std::string();
     RegenerateRequestHeaderValue();
+    return;
   }
 }
 
@@ -232,25 +229,25 @@
     return;
   if (proxy_server.is_direct())
     return;
-  MaybeAddRequestHeaderImpl(proxy_server.host_port_pair(), false,
-                            request_headers, ShouldForceDisableLoFi(request));
+  MaybeAddRequestHeaderImpl(request, proxy_server.host_port_pair(), false,
+                            request_headers);
 }
 
 void DataReductionProxyRequestOptions::MaybeAddProxyTunnelRequestHandler(
     const net::HostPortPair& proxy_server,
     net::HttpRequestHeaders* request_headers) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  MaybeAddRequestHeaderImpl(proxy_server, true, request_headers, false);
+  MaybeAddRequestHeaderImpl(nullptr, proxy_server, true, request_headers);
 }
 
 void DataReductionProxyRequestOptions::SetHeader(
-    net::HttpRequestHeaders* headers,
-    bool force_disable_lo_fi) {
+    const net::URLRequest* request,
+    net::HttpRequestHeaders* headers) {
   base::Time now = Now();
   // Authorization credentials must be regenerated if they are expired.
   if (!use_assigned_credentials_ && (now > credentials_expiration_time_))
     UpdateCredentials();
-  UpdateLoFi(force_disable_lo_fi);
+  MayRegenerateHeaderBasedOnLoFi(request);
   const char kChromeProxyHeader[] = "Chrome-Proxy";
   std::string header_value;
   if (headers->HasHeader(kChromeProxyHeader)) {
@@ -367,16 +364,16 @@
 }
 
 void DataReductionProxyRequestOptions::MaybeAddRequestHeaderImpl(
+    const net::URLRequest* request,
     const net::HostPortPair& proxy_server,
     bool expect_ssl,
-    net::HttpRequestHeaders* request_headers,
-    bool force_disable_lo_fi) {
+    net::HttpRequestHeaders* request_headers) {
   if (proxy_server.IsEmpty())
     return;
   if (data_reduction_proxy_config_->IsDataReductionProxy(proxy_server, NULL) &&
       data_reduction_proxy_config_->UsingHTTPTunnel(proxy_server) ==
           expect_ssl) {
-    SetHeader(request_headers, force_disable_lo_fi);
+    SetHeader(request, request_headers);
   }
 }
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h
index a07007b..dadbe72 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h
@@ -135,7 +135,8 @@
   void Invalidate();
 
  protected:
-  void SetHeader(net::HttpRequestHeaders* headers, bool force_disable_lo_fi);
+  void SetHeader(const net::URLRequest* request,
+                 net::HttpRequestHeaders* headers);
 
   // Returns a UTF16 string that's the hash of the configured authentication
   // |key| and |salt|. Returns an empty UTF16 string if no key is configured or
@@ -173,9 +174,8 @@
   // Updates client type, build, and patch.
   void UpdateVersion();
 
-  // Updates the value of LoFi and regenerates the header if necessary. The LoFi
-  // header is not added if the request bypasses the cache.
-  void UpdateLoFi(bool force_disable_lo_fi);
+  // May regenerate the Chrome Proxy header based on changes in Lo-Fi status.
+  void MayRegenerateHeaderBasedOnLoFi(const net::URLRequest* request);
 
   // Update the value of the experiments to be run and regenerate the header if
   // necessary.
@@ -194,10 +194,10 @@
   // |proxy_server| is a data reduction proxy used for ssl tunneling via
   // HTTP CONNECT, or |expect_ssl| is false and |proxy_server| is a data
   // reduction proxy for HTTP traffic.
-  void MaybeAddRequestHeaderImpl(const net::HostPortPair& proxy_server,
+  void MaybeAddRequestHeaderImpl(const net::URLRequest* request,
+                                 const net::HostPortPair& proxy_server,
                                  bool expect_ssl,
-                                 net::HttpRequestHeaders* request_headers,
-                                 bool force_disable_lo_fi);
+                                 net::HttpRequestHeaders* request_headers);
 
   // Regenerates the |header_value_| string which is concatenated to the
   // Chrome-proxy header.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
index 0fb71d3..4b26de7 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options_unittest.cc
@@ -280,57 +280,83 @@
   VerifyExpectedHeader(params()->DefaultOrigin(), expected_header);
 }
 
-TEST_F(DataReductionProxyRequestOptionsTest, AuthorizationLoFi) {
-  std::string expected_header;
-  SetHeaderExpectations(kExpectedSession, kExpectedCredentials, std::string(),
-                        kClientStr, std::string(), std::string(), "low",
-                        std::vector<std::string>(), &expected_header);
-
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
-
-  CreateRequestOptions(kBogusVersion);
-  VerifyExpectedHeader(params()->DefaultOrigin(), expected_header);
-}
-
-TEST_F(DataReductionProxyRequestOptionsTest, LoFiOn) {
-  // Add the LoFi command line switch.
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
-
-  std::string expected_header;
-  SetHeaderExpectations(kExpectedSession, kExpectedCredentials, std::string(),
-                        kClientStr, std::string(), std::string(), "low",
-                        std::vector<std::string>(), &expected_header);
-
-  CreateRequestOptions(kBogusVersion);
-  VerifyExpectedHeader(params()->DefaultOrigin(), expected_header);
-}
-
-TEST_F(DataReductionProxyRequestOptionsTest, LoFiReloadSingleImage) {
-  // Add the LoFi command line switch.
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
-
+TEST_F(DataReductionProxyRequestOptionsTest, LoFiOnThroughCommandLineSwitch) {
+  test_context_->config()->ResetLoFiStatusForTest();
   std::string expected_header;
   SetHeaderExpectations(kExpectedSession, kExpectedCredentials, std::string(),
                         kClientStr, std::string(), std::string(), std::string(),
                         std::vector<std::string>(), &expected_header);
 
-  CreateRequest(net::LOAD_BYPASS_CACHE);
+  test_context_->config()->UpdateLoFiStatusOnMainFrameRequest(false, nullptr);
   CreateRequestOptions(kBogusVersion);
   VerifyExpectedHeader(params()->DefaultOrigin(), expected_header);
 
-  // Check that LoFi turns back on.
+  test_context_->config()->ResetLoFiStatusForTest();
+  // Add the LoFi command line switch.
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
+
   SetHeaderExpectations(kExpectedSession, kExpectedCredentials, std::string(),
                         kClientStr, std::string(), std::string(), "low",
                         std::vector<std::string>(), &expected_header);
 
-  CreateRequest(net::LOAD_NORMAL);
+  test_context_->config()->UpdateLoFiStatusOnMainFrameRequest(false, nullptr);
   CreateRequestOptions(kBogusVersion);
   VerifyExpectedHeader(params()->DefaultOrigin(), expected_header);
 }
 
+TEST_F(DataReductionProxyRequestOptionsTest, AutoLoFi) {
+  const struct {
+    bool auto_lofi_enabled_group;
+    bool network_prohibitively_slow;
+
+  } tests[] = {
+      {
+       false, false,
+      },
+      {
+       false, true,
+      },
+      {
+       true, false,
+      },
+      {
+       true, true,
+      },
+  };
+
+  for (size_t i = 0; i < arraysize(tests); ++i) {
+    test_context_->config()->ResetLoFiStatusForTest();
+    // Lo-Fi header is expected only if session is part of Lo-Fi enabled field
+    // trial and network is prohibitively slow.
+    bool expect_lofi_header =
+        tests[i].auto_lofi_enabled_group && tests[i].network_prohibitively_slow;
+
+    std::string expected_header;
+    if (!expect_lofi_header) {
+      SetHeaderExpectations(kExpectedSession, kExpectedCredentials,
+                            std::string(), kClientStr, std::string(),
+                            std::string(), std::string(),
+                            std::vector<std::string>(), &expected_header);
+    } else {
+      SetHeaderExpectations(kExpectedSession, kExpectedCredentials,
+                            std::string(), kClientStr, std::string(),
+                            std::string(), "low", std::vector<std::string>(),
+                            &expected_header);
+    }
+    test_context_->config()->SetIncludedInLoFiEnabledFieldTrial(
+        tests[i].auto_lofi_enabled_group);
+    test_context_->config()->SetNetworkProhibitivelySlow(
+        tests[i].network_prohibitively_slow);
+
+    // Force update Lo-Fi status.
+    test_context_->config()->UpdateLoFiStatusOnMainFrameRequest(false, nullptr);
+
+    CreateRequestOptions(kBogusVersion);
+    VerifyExpectedHeader(params()->DefaultOrigin(), expected_header);
+  }
+}
+
 TEST_F(DataReductionProxyRequestOptionsTest, SecureSession) {
   std::string expected_header;
   SetHeaderExpectations(std::string(), std::string(), kSecureSession,
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
index 71b78af2..8490a55c 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
@@ -119,6 +119,12 @@
   settings_->SetUnreachable(unreachable);
 }
 
+void DataReductionProxyService::SetLoFiModeActiveOnMainFrame(
+    bool lo_fi_mode_active) {
+  DCHECK(CalledOnValidThread());
+  settings_->SetLoFiModeActiveOnMainFrame(lo_fi_mode_active);
+}
+
 void DataReductionProxyService::SetInt64Pref(const std::string& pref_path,
                                              int64 value) {
   if (prefs_)
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
index 46dce7c..9ef540e 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h
@@ -91,6 +91,10 @@
   // Records whether the Data Reduction Proxy is unreachable or not.
   void SetUnreachable(bool unreachable);
 
+  // Sets if Lo-Fi was active on the last main frame load in
+  // DataReductionProxySettings.
+  void SetLoFiModeActiveOnMainFrame(bool lo_fi_mode_active);
+
   // Stores an int64 value in |prefs_|.
   void SetInt64Pref(const std::string& pref_path, int64 value);
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
index 7d66e29..a53b660 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
@@ -18,17 +18,11 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
 
 namespace {
+
 // Key of the UMA DataReductionProxy.StartupState histogram.
 const char kUMAProxyStartupStateHistogram[] =
     "DataReductionProxy.StartupState";
 
-bool IsLoFiEnabledOnCommandLine() {
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  return command_line.HasSwitch(
-      data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
-}
-
 }  // namespace
 
 namespace data_reduction_proxy {
@@ -42,6 +36,8 @@
       allowed_(false),
       alternative_allowed_(false),
       promo_allowed_(false),
+      lo_fi_mode_active_(false),
+      lo_fi_show_image_requested_(false),
       prefs_(NULL),
       config_(nullptr) {
 }
@@ -174,8 +170,25 @@
   return prefs_;
 }
 
-bool DataReductionProxySettings::IsLoFiEnabled() const {
-  return IsDataReductionProxyEnabled() && IsLoFiEnabledOnCommandLine();
+void DataReductionProxySettings::SetLoFiModeActiveOnMainFrame(
+    bool lo_fi_mode_active) {
+  lo_fi_show_image_requested_ = false;
+  lo_fi_mode_active_ = lo_fi_mode_active;
+  if (!register_synthetic_field_trial_.is_null()) {
+    RegisterLoFiFieldTrial();
+  }
+}
+
+bool DataReductionProxySettings::WasLoFiModeActiveOnMainFrame() const {
+  return lo_fi_mode_active_;
+}
+
+bool DataReductionProxySettings::WasLoFiShowImageRequestedBefore() {
+  return lo_fi_show_image_requested_;
+}
+
+void DataReductionProxySettings::SetLoFiShowImageRequested() {
+  lo_fi_show_image_requested_ = true;
 }
 
 void DataReductionProxySettings::RegisterDataReductionProxyFieldTrial() {
@@ -187,7 +200,9 @@
 void DataReductionProxySettings::RegisterLoFiFieldTrial() {
   register_synthetic_field_trial_.Run(
       "SyntheticDataReductionProxyLoFiSetting",
-      IsLoFiEnabled() ? "Enabled" : "Disabled");
+      IsDataReductionProxyEnabled() && WasLoFiModeActiveOnMainFrame()
+          ? "Enabled"
+          : "Disabled");
 }
 
 void DataReductionProxySettings::OnProxyEnabledPrefChange() {
@@ -218,7 +233,8 @@
   data_reduction_proxy_service_->SetProxyPrefs(
       IsDataReductionProxyEnabled(), IsDataReductionProxyAlternativeEnabled(),
       at_startup);
-  data_reduction_proxy_service_->RetrieveConfig();
+  if (IsDataReductionProxyEnabled())
+    data_reduction_proxy_service_->RetrieveConfig();
 }
 
 void DataReductionProxySettings::MaybeActivateDataReductionProxy(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
index d4c53de5..8e65315f 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
@@ -99,8 +99,21 @@
   // Enables or disables the alternative data reduction proxy configuration.
   void SetDataReductionProxyAlternativeEnabled(bool enabled);
 
-  // Returns true if both LoFi and the proxy are enabled.
-  bool IsLoFiEnabled() const;
+  // Sets |lo_fi_mode_active_| to true if Lo-Fi is currently active, meaning
+  // requests are being sent with "q=low" headers. Set from the IO thread only
+  // on main frame requests.
+  void SetLoFiModeActiveOnMainFrame(bool lo_fi_mode_active);
+
+  // Returns true if Lo-Fi was active on the main frame request.
+  bool WasLoFiModeActiveOnMainFrame() const;
+
+  // Returns true if a "Show image" context menu request has not been made since
+  // the last main frame request.
+  bool WasLoFiShowImageRequestedBefore();
+
+  // Sets |lo_fi_show_image_requested_| to true, which means a "Show image"
+  // context menu request has been made since the last main frame request.
+  void SetLoFiShowImageRequested();
 
   // Returns the time in microseconds that the last update was made to the
   // daily original and received content lengths.
@@ -143,7 +156,7 @@
   }
 
   // Returns true if the data reduction proxy promo may be shown.
-  // This is idependent of whether the data reduction proxy is allowed.
+  // This is independent of whether the data reduction proxy is allowed.
   bool PromoAllowed() const {
     return promo_allowed_;
   }
@@ -213,11 +226,12 @@
   void RegisterDataReductionProxyFieldTrial();
 
   // Registers the trial "SyntheticDataReductionProxyLoFiSetting" with the group
-  // "Enabled" or "Disabled". Indicates whether LoFi is turned on or not.
-  // The group won't be reported if it changes while compiling the report. LoFi
-  // has its own field trial because it is expected that the user will be
-  // switching states often. It can be assumed that when no LoFi group is
-  // reported, the user was in a mixed LoFi state.
+  // "Enabled" or "Disabled". Indicates whether Lo-Fi is turned on or not.
+  // The group won't be reported if it changes while compiling the report. It
+  // can be assumed that when no Lo-Fi group is reported, the user was in a
+  // mixed Lo-Fi state.
+  // TODO(tbansal): State of the Lo-Fi synthetic field trial should change
+  // based on Auto Lo-Fi status.
   void RegisterLoFiFieldTrial();
 
   void OnProxyEnabledPrefChange();
@@ -244,6 +258,13 @@
   bool alternative_allowed_;
   bool promo_allowed_;
 
+  // True if Lo-Fi is active.
+  bool lo_fi_mode_active_;
+
+  // True if a "Show image" context menu request has not been made since the
+  // last main frame request.
+  bool lo_fi_show_image_requested_;
+
   BooleanPrefMember spdy_proxy_auth_enabled_;
   BooleanPrefMember data_reduction_proxy_alternative_enabled_;
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
index c5cd1a0c..8c9d34e 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
@@ -301,8 +301,7 @@
   EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED));
   test_context_->pref_service()->SetBoolean(prefs::kDataReductionProxyEnabled,
                                             true);
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableDataReductionProxyLoFi);
+  settings->SetLoFiModeActiveOnMainFrame(true);
   InitDataReductionProxy(true);
 
   ExpectSetProxyPrefs(false, false, false);
@@ -317,25 +316,23 @@
   CheckDataReductionProxyLoFiSyntheticTrial(true);
 }
 
-TEST_F(DataReductionProxySettingsTest, TestEnableLoFiFromCommandLineProxyOn) {
+TEST_F(DataReductionProxySettingsTest, TestEnableLoFiSyntheticTrial) {
   MockSettings* settings = static_cast<MockSettings*>(settings_.get());
   EXPECT_CALL(*settings, RecordStartupState(PROXY_ENABLED));
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableDataReductionProxyLoFi);
   test_context_->pref_service()->SetBoolean(prefs::kDataReductionProxyEnabled,
                                             true);
   InitDataReductionProxy(true);
-  CheckDataReductionProxyLoFiSyntheticTrial(true);
-}
 
-TEST_F(DataReductionProxySettingsTest, TestEnableLoFiFromCommandLineProxyOff) {
-  MockSettings* settings = static_cast<MockSettings*>(settings_.get());
-  EXPECT_CALL(*settings, RecordStartupState(PROXY_DISABLED));
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kEnableDataReductionProxyLoFi);
-  test_context_->pref_service()->SetBoolean(prefs::kDataReductionProxyEnabled,
-                                            false);
-  InitDataReductionProxy(false);
+  // The Lo-Fi field trial will be set to "Disabled" until the first main frame
+  // request with Lo-Fi active.
+  CheckDataReductionProxyLoFiSyntheticTrial(false);
+
+  // Turn Lo-Fi on.
+  settings->SetLoFiModeActiveOnMainFrame(true);
+  CheckDataReductionProxyLoFiSyntheticTrial(true);
+
+  // Now turn it off.
+  settings->SetLoFiModeActiveOnMainFrame(false);
   CheckDataReductionProxyLoFiSyntheticTrial(false);
 }
 
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.cc
index b84e0f9..f837eb4 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.cc
@@ -257,8 +257,8 @@
   PostBoundNetLogSecureProxyCheckEvent(
       net_log, net::NetLog::TYPE_DATA_REDUCTION_PROXY_CANARY_REQUEST,
       net::NetLog::PHASE_END,
-      net_error == 0 ? DataReductionProxyEventStorageDelegate::CHECK_SUCCESS
-                     : DataReductionProxyEventStorageDelegate::CHECK_FAILED,
+      succeeded ? DataReductionProxyEventStorageDelegate::CHECK_SUCCESS
+                : DataReductionProxyEventStorageDelegate::CHECK_FAILED,
       parameters_callback);
 }
 
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc
index bd324124..b1616da1 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc
@@ -42,6 +42,12 @@
     return entries[0];
   }
 
+  net::TestNetLogEntry GetLatestEntry() const {
+    net::TestNetLogEntry::List entries;
+    net_log_->GetEntries(&entries);
+    return entries.back();
+  }
+
   DataReductionProxyEventStore* event_store() { return event_store_.get(); }
 
   DataReductionProxyEventCreator* event_creator() {
@@ -157,4 +163,47 @@
             secure_proxy_check_state());
 }
 
+TEST_F(DataReductionProxyEventStoreTest, TestEndSecureProxyCheckFailed) {
+  const struct {
+    const char* test_case;
+    int net_error;
+    int http_response_code;
+    bool secure_proxy_check_succeeded;
+    bool expected_proxy_check_succeeded;
+  } tests[] = {
+      {
+       "Succeeded", net::OK, net::HTTP_OK, true, true,
+      },
+      {
+       "Net failure", net::ERR_CONNECTION_RESET, -1, false, false,
+      },
+      {
+       "HTTP failure", net::OK, net::HTTP_NOT_FOUND, false, false,
+      },
+      {
+       "Bad content", net::OK, net::HTTP_OK, false, false,
+      },
+  };
+  size_t expected_event_count = 0;
+  EXPECT_EQ(expected_event_count, net_log()->GetSize());
+  EXPECT_EQ(expected_event_count++, event_count());
+  EXPECT_EQ(DataReductionProxyEventStorageDelegate::CHECK_UNKNOWN,
+            secure_proxy_check_state());
+  for (const auto& test : tests) {
+    event_creator()->EndSecureProxyCheck(bound_net_log(), test.net_error,
+                                         test.http_response_code,
+                                         test.secure_proxy_check_succeeded);
+    EXPECT_EQ(expected_event_count, net_log()->GetSize()) << test.test_case;
+    EXPECT_EQ(expected_event_count++, event_count()) << test.test_case;
+    net::TestNetLogEntry entry = GetLatestEntry();
+    EXPECT_EQ(net::NetLog::TYPE_DATA_REDUCTION_PROXY_CANARY_REQUEST, entry.type)
+        << test.test_case;
+    EXPECT_EQ(test.secure_proxy_check_succeeded
+                  ? DataReductionProxyEventStorageDelegate::CHECK_SUCCESS
+                  : DataReductionProxyEventStorageDelegate::CHECK_FAILED,
+              secure_proxy_check_state())
+        << test.test_case;
+  }
+}
+
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
index 3754c9e6..612ed38 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
@@ -45,6 +45,8 @@
 
 const char kQuicFieldTrial[] = "DataReductionProxyUseQuic";
 
+const char kLoFiFieldTrial[] = "DataReductionProxyLoFi";
+
 const char kConfigScheme[] = "scheme";
 const char kConfigHost[] = "host";
 const char kConfigPort[] = "port";
@@ -104,7 +106,12 @@
 }
 
 // static
-bool DataReductionProxyParams::IsLoFiEnabled() {
+std::string DataReductionProxyParams::GetLoFiFieldTrialName() {
+  return kLoFiFieldTrial;
+}
+
+// static
+bool DataReductionProxyParams::IsLoFiEnabledThroughSwitch() {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
       data_reduction_proxy::switches::kEnableDataReductionProxyLoFi);
 }
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
index 20d26ee..111abe04 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
@@ -98,7 +98,7 @@
 
   // Returns true if this client has the command line switch to enable Lo-Fi
   // mode.
-  static bool IsLoFiEnabled();
+  static bool IsLoFiEnabledThroughSwitch();
 
   // Returns true if this client has the command line switch to show
   // interstitials for data reduction proxy bypasses.
@@ -112,6 +112,9 @@
   // proxy server as quic://proxy.googlezip.net.
   static bool IsIncludedInQuicFieldTrial();
 
+  // Returns the name of the Lo-Fi field trial.
+  static std::string GetLoFiFieldTrialName();
+
   static std::string GetQuicFieldTrialName();
 
   // Returns true if this client is part of a field trial that allows Data Saver
diff --git a/components/devtools_service/BUILD.gn b/components/devtools_service/BUILD.gn
index 7b16038..1dc5c46 100644
--- a/components/devtools_service/BUILD.gn
+++ b/components/devtools_service/BUILD.gn
@@ -6,6 +6,10 @@
 
 source_set("lib") {
   sources = [
+    "devtools_http_server.cc",
+    "devtools_http_server.h",
+    "devtools_registry_impl.cc",
+    "devtools_registry_impl.h",
     "devtools_service.cc",
     "devtools_service.h",
     "devtools_service_delegate.cc",
diff --git a/components/devtools_service/devtools_http_server.cc b/components/devtools_service/devtools_http_server.cc
new file mode 100644
index 0000000..7199f2b
--- /dev/null
+++ b/components/devtools_service/devtools_http_server.cc
@@ -0,0 +1,151 @@
+// 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/devtools_service/devtools_http_server.h"
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "components/devtools_service/devtools_service.h"
+#include "mojo/application/public/cpp/application_impl.h"
+#include "mojo/services/network/public/interfaces/http_message.mojom.h"
+#include "mojo/services/network/public/interfaces/net_address.mojom.h"
+#include "mojo/services/network/public/interfaces/network_service.mojom.h"
+
+namespace devtools_service {
+
+class DevToolsHttpServer::HttpConnectionDelegateImpl
+    : public mojo::HttpConnectionDelegate,
+      public mojo::ErrorHandler {
+ public:
+  HttpConnectionDelegateImpl(
+      DevToolsHttpServer* owner,
+      mojo::HttpConnectionPtr connection,
+      mojo::InterfaceRequest<HttpConnectionDelegate> delegate_request)
+      : owner_(owner),
+        connection_(connection.Pass()),
+        binding_(this, delegate_request.Pass()) {
+    DCHECK(owner_);
+    DCHECK(connection_);
+    DCHECK(binding_.is_bound());
+
+    connection_.set_error_handler(this);
+    binding_.set_error_handler(this);
+  }
+
+  mojo::HttpConnection* connection() { return connection_.get(); }
+
+ private:
+  // mojo::HttpConnectionDelegate implementation:
+  void OnReceivedRequest(mojo::HttpRequestPtr request,
+                         const OnReceivedRequestCallback& callback) override {
+    owner_->OnReceivedRequest(this, request.Pass(), callback);
+  }
+
+  void OnReceivedWebSocketRequest(
+      mojo::HttpRequestPtr request,
+      const OnReceivedWebSocketRequestCallback& callback) override {
+    owner_->OnReceivedWebSocketRequest(this, request.Pass(), callback);
+  }
+
+  // mojo::ErrorHandler implementation.
+  void OnConnectionError() override { owner_->OnConnectionClosed(this); }
+
+  DevToolsHttpServer* const owner_;
+  mojo::HttpConnectionPtr connection_;
+  mojo::Binding<HttpConnectionDelegate> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(HttpConnectionDelegateImpl);
+};
+
+DevToolsHttpServer::DevToolsHttpServer(DevToolsService* service,
+                                       uint16_t remote_debugging_port)
+    : service_(service) {
+  VLOG(1) << "Remote debugging HTTP server is started on port "
+          << remote_debugging_port << ".";
+  mojo::NetworkServicePtr network_service;
+  mojo::URLRequestPtr request(mojo::URLRequest::New());
+  request->url = "mojo:network_service";
+  service_->application()->ConnectToService(request.Pass(), &network_service);
+
+  mojo::NetAddressPtr local_address(mojo::NetAddress::New());
+  local_address->family = mojo::NET_ADDRESS_FAMILY_IPV4;
+  local_address->ipv4 = mojo::NetAddressIPv4::New();
+  local_address->ipv4->port = remote_debugging_port;
+  local_address->ipv4->addr.resize(4);
+  local_address->ipv4->addr[0] = 127;
+  local_address->ipv4->addr[1] = 0;
+  local_address->ipv4->addr[2] = 0;
+  local_address->ipv4->addr[3] = 1;
+
+  mojo::HttpServerDelegatePtr http_server_delegate;
+  http_server_delegate_binding_.reset(
+      new mojo::Binding<mojo::HttpServerDelegate>(this, &http_server_delegate));
+  network_service->CreateHttpServer(
+      local_address.Pass(), http_server_delegate.Pass(),
+      mojo::NetworkService::CreateHttpServerCallback());
+}
+
+DevToolsHttpServer::~DevToolsHttpServer() {
+  STLDeleteElements(&connections_);
+}
+
+void DevToolsHttpServer::OnConnected(
+    mojo::HttpConnectionPtr connection,
+    mojo::InterfaceRequest<mojo::HttpConnectionDelegate> delegate) {
+  connections_.insert(
+      new HttpConnectionDelegateImpl(this, connection.Pass(), delegate.Pass()));
+}
+
+void DevToolsHttpServer::OnReceivedRequest(
+    HttpConnectionDelegateImpl* connection,
+    mojo::HttpRequestPtr request,
+    const OnReceivedRequestCallback& callback) {
+  DCHECK(connections_.find(connection) != connections_.end());
+
+  // TODO(yzshen): Implement it.
+  static const char kNotImplemented[] = "Not implemented yet!";
+  mojo::HttpResponsePtr response(mojo::HttpResponse::New());
+  response->headers.resize(2);
+  response->headers[0] = mojo::HttpHeader::New();
+  response->headers[0]->name = "Content-Length";
+  response->headers[0]->value = base::StringPrintf(
+      "%lu", static_cast<unsigned long>(sizeof(kNotImplemented)));
+  response->headers[1] = mojo::HttpHeader::New();
+  response->headers[1]->name = "Content-Type";
+  response->headers[1]->value = "text/html";
+
+  uint32_t num_bytes = sizeof(kNotImplemented);
+  MojoCreateDataPipeOptions options;
+  options.struct_size = sizeof(MojoCreateDataPipeOptions);
+  options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
+  options.element_num_bytes = 1;
+  options.capacity_num_bytes = num_bytes;
+  mojo::DataPipe data_pipe(options);
+  response->body = data_pipe.consumer_handle.Pass();
+  WriteDataRaw(data_pipe.producer_handle.get(), kNotImplemented, &num_bytes,
+               MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
+
+  callback.Run(response.Pass());
+}
+
+void DevToolsHttpServer::OnReceivedWebSocketRequest(
+    HttpConnectionDelegateImpl* connection,
+    mojo::HttpRequestPtr request,
+    const OnReceivedWebSocketRequestCallback& callback) {
+  DCHECK(connections_.find(connection) != connections_.end());
+
+  // TODO(yzshen): Implement it.
+  NOTIMPLEMENTED();
+}
+
+void DevToolsHttpServer::OnConnectionClosed(
+    HttpConnectionDelegateImpl* connection) {
+  DCHECK(connections_.find(connection) != connections_.end());
+
+  delete connection;
+  connections_.erase(connection);
+}
+
+}  // namespace devtools_service
diff --git a/components/devtools_service/devtools_http_server.h b/components/devtools_service/devtools_http_server.h
new file mode 100644
index 0000000..6a9a1a9b
--- /dev/null
+++ b/components/devtools_service/devtools_http_server.h
@@ -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.
+
+#ifndef COMPONENTS_DEVTOOLS_SERVICE_DEVTOOLS_HTTP_SERVER_H_
+#define COMPONENTS_DEVTOOLS_SERVICE_DEVTOOLS_HTTP_SERVER_H_
+
+#include <set>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "mojo/services/network/public/interfaces/http_connection.mojom.h"
+#include "mojo/services/network/public/interfaces/http_server.mojom.h"
+
+namespace devtools_service {
+
+class DevToolsService;
+
+class DevToolsHttpServer : public mojo::HttpServerDelegate {
+ public:
+  // |service| must outlive this object.
+  DevToolsHttpServer(DevToolsService* service, uint16_t remote_debugging_port);
+  ~DevToolsHttpServer() override;
+
+ private:
+  class HttpConnectionDelegateImpl;
+
+  // mojo::HttpServerDelegate implementation.
+  void OnConnected(
+      mojo::HttpConnectionPtr connection,
+      mojo::InterfaceRequest<mojo::HttpConnectionDelegate> delegate) override;
+
+  // The following methods are called by HttpConnectionDelegateImpl.
+  using OnReceivedRequestCallback =
+      mojo::HttpConnectionDelegate::OnReceivedRequestCallback;
+  void OnReceivedRequest(HttpConnectionDelegateImpl* connection,
+                         mojo::HttpRequestPtr request,
+                         const OnReceivedRequestCallback& callback);
+
+  using OnReceivedWebSocketRequestCallback =
+      mojo::HttpConnectionDelegate::OnReceivedWebSocketRequestCallback;
+  void OnReceivedWebSocketRequest(
+      HttpConnectionDelegateImpl* connection,
+      mojo::HttpRequestPtr request,
+      const OnReceivedWebSocketRequestCallback& callback);
+
+  void OnConnectionClosed(HttpConnectionDelegateImpl* connection);
+
+  // Not owned by this object.
+  DevToolsService* const service_;
+
+  scoped_ptr<mojo::Binding<mojo::HttpServerDelegate>>
+      http_server_delegate_binding_;
+
+  // Owns the elements.
+  std::set<HttpConnectionDelegateImpl*> connections_;
+
+  DISALLOW_COPY_AND_ASSIGN(DevToolsHttpServer);
+};
+
+}  // namespace devtools_service
+
+#endif  // COMPONENTS_DEVTOOLS_SERVICE_DEVTOOLS_HTTP_SERVER_H_
diff --git a/components/devtools_service/devtools_registry_impl.cc b/components/devtools_service/devtools_registry_impl.cc
new file mode 100644
index 0000000..130f20f
--- /dev/null
+++ b/components/devtools_service/devtools_registry_impl.cc
@@ -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.
+
+#include "components/devtools_service/devtools_registry_impl.h"
+
+#include "base/logging.h"
+
+namespace devtools_service {
+
+DevToolsRegistryImpl::DevToolsRegistryImpl(DevToolsService* service)
+    : service_(service) {
+}
+
+DevToolsRegistryImpl::~DevToolsRegistryImpl() {
+}
+
+void DevToolsRegistryImpl::BindToRegistryRequest(
+    mojo::InterfaceRequest<DevToolsRegistry> request) {
+  bindings_.AddBinding(this, request.Pass());
+}
+
+void DevToolsRegistryImpl::RegisterAgent(DevToolsAgentPtr agent) {
+  // TODO(yzshen): Implement it.
+  NOTIMPLEMENTED();
+}
+
+}  // namespace devtools_service
diff --git a/components/devtools_service/devtools_registry_impl.h b/components/devtools_service/devtools_registry_impl.h
new file mode 100644
index 0000000..c12c0de
--- /dev/null
+++ b/components/devtools_service/devtools_registry_impl.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 COMPONENTS_DEVTOOLS_SERVICE_DEVTOOLS_REGISTRY_IMPL_H_
+#define COMPONENTS_DEVTOOLS_SERVICE_DEVTOOLS_REGISTRY_IMPL_H_
+
+#include "base/macros.h"
+#include "components/devtools_service/public/interfaces/devtools_service.mojom.h"
+#include "mojo/common/weak_binding_set.h"
+
+namespace devtools_service {
+
+class DevToolsService;
+
+class DevToolsRegistryImpl : public DevToolsRegistry {
+ public:
+  // |service| must outlive this object.
+  explicit DevToolsRegistryImpl(DevToolsService* service);
+  ~DevToolsRegistryImpl() override;
+
+  void BindToRegistryRequest(mojo::InterfaceRequest<DevToolsRegistry> request);
+
+ private:
+  // DevToolsRegistry implementation.
+  void RegisterAgent(DevToolsAgentPtr agent) override;
+
+  DevToolsService* const service_;
+
+  mojo::WeakBindingSet<DevToolsRegistry> bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(DevToolsRegistryImpl);
+};
+
+}  // namespace devtools_service
+
+#endif  // COMPONENTS_DEVTOOLS_SERVICE_DEVTOOLS_REGISTRY_IMPL_H_
diff --git a/components/devtools_service/devtools_service.cc b/components/devtools_service/devtools_service.cc
index 479da5c..6cc0ede 100644
--- a/components/devtools_service/devtools_service.cc
+++ b/components/devtools_service/devtools_service.cc
@@ -5,77 +5,18 @@
 #include "components/devtools_service/devtools_service.h"
 
 #include "base/logging.h"
-#include "base/stl_util.h"
-#include "base/strings/stringprintf.h"
+#include "components/devtools_service/devtools_http_server.h"
+#include "components/devtools_service/devtools_registry_impl.h"
 #include "mojo/application/public/cpp/application_impl.h"
-#include "mojo/services/network/public/interfaces/http_message.mojom.h"
-#include "mojo/services/network/public/interfaces/net_address.mojom.h"
-#include "mojo/services/network/public/interfaces/network_service.mojom.h"
 
 namespace devtools_service {
 
-class DevToolsService::HttpConnectionDelegateImpl
-    : public mojo::HttpConnectionDelegate,
-      public mojo::ErrorHandler {
- public:
-  HttpConnectionDelegateImpl(
-      DevToolsService* owner,
-      mojo::HttpConnectionPtr connection,
-      mojo::InterfaceRequest<HttpConnectionDelegate> delegate_request)
-      : owner_(owner),
-        connection_(connection.Pass()),
-        binding_(this, delegate_request.Pass()) {
-    DCHECK(owner_);
-    DCHECK(connection_);
-    DCHECK(binding_.is_bound());
-
-    connection_.set_error_handler(this);
-    binding_.set_error_handler(this);
-  }
-
-  mojo::HttpConnection* connection() { return connection_.get(); }
-
- private:
-  // mojo::HttpConnectionDelegate implementation:
-  void OnReceivedRequest(mojo::HttpRequestPtr request,
-                         const OnReceivedRequestCallback& callback) override {
-    owner_->OnReceivedRequest(this, request.Pass(), callback);
-  }
-
-  void OnReceivedWebSocketRequest(
-      mojo::HttpRequestPtr request,
-      const OnReceivedWebSocketRequestCallback& callback) override {
-    owner_->OnReceivedWebSocketRequest(this, request.Pass(), callback);
-  }
-
-  // mojo::ErrorHandler implementation.
-  void OnConnectionError() override { owner_->OnConnectionClosed(this); }
-
-  DevToolsService* const owner_;
-  mojo::HttpConnectionPtr connection_;
-  mojo::Binding<HttpConnectionDelegate> binding_;
-
-  DISALLOW_COPY_AND_ASSIGN(HttpConnectionDelegateImpl);
-};
-
 DevToolsService::DevToolsService(mojo::ApplicationImpl* application)
     : application_(application) {
   DCHECK(application_);
 }
 
 DevToolsService::~DevToolsService() {
-  STLDeleteElements(&connections_);
-}
-
-void DevToolsService::BindToRegistryRequest(
-    mojo::InterfaceRequest<DevToolsRegistry> request) {
-  if (!IsInitialized()) {
-    // Ignore the request if remote debugging is not needed.
-    return;
-  }
-
-  // TODO(yzshen): Implement it.
-  NOTIMPLEMENTED();
 }
 
 void DevToolsService::BindToCoordinatorRequest(
@@ -91,91 +32,8 @@
     return;
   }
 
-  VLOG(1) << "Remote debugging HTTP server is started on port "
-          << remote_debugging_port << ".";
-  mojo::NetworkServicePtr network_service;
-  mojo::URLRequestPtr request(mojo::URLRequest::New());
-  request->url = "mojo:network_service";
-  application_->ConnectToService(request.Pass(), &network_service);
-
-  mojo::NetAddressPtr local_address(mojo::NetAddress::New());
-  local_address->family = mojo::NET_ADDRESS_FAMILY_IPV4;
-  local_address->ipv4 = mojo::NetAddressIPv4::New();
-  local_address->ipv4->port = remote_debugging_port;
-  local_address->ipv4->addr.resize(4);
-  local_address->ipv4->addr[0] = 127;
-  local_address->ipv4->addr[1] = 0;
-  local_address->ipv4->addr[2] = 0;
-  local_address->ipv4->addr[3] = 1;
-
-  mojo::HttpServerDelegatePtr http_server_delegate;
-  http_server_delegate_binding_.reset(
-      new mojo::Binding<mojo::HttpServerDelegate>(this, &http_server_delegate));
-  network_service->CreateHttpServer(
-      local_address.Pass(), http_server_delegate.Pass(),
-      mojo::NetworkService::CreateHttpServerCallback());
-}
-
-void DevToolsService::RegisterAgent(DevToolsAgentPtr agent) {
-  // TODO(yzshen): Implement it.
-  NOTIMPLEMENTED();
-}
-
-void DevToolsService::OnConnected(
-    mojo::HttpConnectionPtr connection,
-    mojo::InterfaceRequest<mojo::HttpConnectionDelegate> delegate) {
-  connections_.insert(
-      new HttpConnectionDelegateImpl(this, connection.Pass(), delegate.Pass()));
-}
-
-void DevToolsService::OnReceivedRequest(
-    HttpConnectionDelegateImpl* connection,
-    mojo::HttpRequestPtr request,
-    const OnReceivedRequestCallback& callback) {
-  DCHECK(connections_.find(connection) != connections_.end());
-
-  // TODO(yzshen): Implement it.
-  static const char kNotImplemented[] = "Not implemented yet!";
-  mojo::HttpResponsePtr response(mojo::HttpResponse::New());
-  response->headers.resize(2);
-  response->headers[0] = mojo::HttpHeader::New();
-  response->headers[0]->name = "Content-Length";
-  response->headers[0]->value = base::StringPrintf(
-      "%lu", static_cast<unsigned long>(sizeof(kNotImplemented)));
-  response->headers[1] = mojo::HttpHeader::New();
-  response->headers[1]->name = "Content-Type";
-  response->headers[1]->value = "text/html";
-
-  uint32_t num_bytes = sizeof(kNotImplemented);
-  MojoCreateDataPipeOptions options;
-  options.struct_size = sizeof(MojoCreateDataPipeOptions);
-  options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
-  options.element_num_bytes = 1;
-  options.capacity_num_bytes = num_bytes;
-  mojo::DataPipe data_pipe(options);
-  response->body = data_pipe.consumer_handle.Pass();
-  WriteDataRaw(data_pipe.producer_handle.get(), kNotImplemented, &num_bytes,
-               MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
-
-  callback.Run(response.Pass());
-}
-
-void DevToolsService::OnReceivedWebSocketRequest(
-    HttpConnectionDelegateImpl* connection,
-    mojo::HttpRequestPtr request,
-    const OnReceivedWebSocketRequestCallback& callback) {
-  DCHECK(connections_.find(connection) != connections_.end());
-
-  // TODO(yzshen): Implement it.
-  NOTIMPLEMENTED();
-}
-
-void DevToolsService::OnConnectionClosed(
-    HttpConnectionDelegateImpl* connection) {
-  DCHECK(connections_.find(connection) != connections_.end());
-
-  delete connection;
-  connections_.erase(connection);
+  http_server_.reset(new DevToolsHttpServer(this, remote_debugging_port));
+  registry_.reset(new DevToolsRegistryImpl(this));
 }
 
 }  // namespace devtools_service
diff --git a/components/devtools_service/devtools_service.h b/components/devtools_service/devtools_service.h
index 9234848..a1385a6f 100644
--- a/components/devtools_service/devtools_service.h
+++ b/components/devtools_service/devtools_service.h
@@ -5,14 +5,10 @@
 #ifndef COMPONENTS_DEVTOOLS_SERVICE_DEVTOOLS_SERVICE_H_
 #define COMPONENTS_DEVTOOLS_SERVICE_DEVTOOLS_SERVICE_H_
 
-#include <set>
-
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "components/devtools_service/public/interfaces/devtools_service.mojom.h"
 #include "mojo/common/weak_binding_set.h"
-#include "mojo/services/network/public/interfaces/http_connection.mojom.h"
-#include "mojo/services/network/public/interfaces/http_server.mojom.h"
 
 namespace mojo {
 class ApplicationImpl;
@@ -20,63 +16,39 @@
 
 namespace devtools_service {
 
+class DevToolsHttpServer;
+class DevToolsRegistryImpl;
+
 // DevToolsService is the central control. It manages the communication with
 // DevTools agents (e.g., Web page renderers). It also starts an HTTP server to
 // speak the Chrome remote debugging protocol.
-class DevToolsService : public DevToolsRegistry,
-                        public DevToolsCoordinator,
-                        public mojo::HttpServerDelegate {
+class DevToolsService : public DevToolsCoordinator {
  public:
   // Doesn't take ownership of |application|, which must outlive this object.
   explicit DevToolsService(mojo::ApplicationImpl* application);
   ~DevToolsService() override;
 
-  void BindToRegistryRequest(mojo::InterfaceRequest<DevToolsRegistry> request);
   void BindToCoordinatorRequest(
       mojo::InterfaceRequest<DevToolsCoordinator> request);
 
- private:
-  class HttpConnectionDelegateImpl;
+  mojo::ApplicationImpl* application() { return application_; }
 
+  bool IsInitialized() const { return !!http_server_; }
+
+  // Non-null if initialized.
+  DevToolsRegistryImpl* registry() { return registry_.get(); }
+
+ private:
   // DevToolsCoordinator implementation.
   void Initialize(uint16_t remote_debugging_port) override;
 
-  // DevToolsRegistry implementation.
-  void RegisterAgent(DevToolsAgentPtr agent) override;
-
-  // mojo::HttpServerDelegate implementation.
-  void OnConnected(
-      mojo::HttpConnectionPtr connection,
-      mojo::InterfaceRequest<mojo::HttpConnectionDelegate> delegate) override;
-
-  bool IsInitialized() const { return !!http_server_delegate_binding_; }
-
-  // The following methods are called by HttpConnectionDelegateImpl.
-  using OnReceivedRequestCallback =
-      mojo::HttpConnectionDelegate::OnReceivedRequestCallback;
-  void OnReceivedRequest(HttpConnectionDelegateImpl* connection,
-                         mojo::HttpRequestPtr request,
-                         const OnReceivedRequestCallback& callback);
-
-  using OnReceivedWebSocketRequestCallback =
-      mojo::HttpConnectionDelegate::OnReceivedWebSocketRequestCallback;
-  void OnReceivedWebSocketRequest(
-      HttpConnectionDelegateImpl* connection,
-      mojo::HttpRequestPtr request,
-      const OnReceivedWebSocketRequestCallback& callback);
-
-  void OnConnectionClosed(HttpConnectionDelegateImpl* connection);
-
   // Not owned by this object.
   mojo::ApplicationImpl* const application_;
 
   mojo::WeakBindingSet<DevToolsCoordinator> coordinator_bindings_;
 
-  scoped_ptr<mojo::Binding<mojo::HttpServerDelegate>>
-      http_server_delegate_binding_;
-
-  // Owns the elements.
-  std::set<HttpConnectionDelegateImpl*> connections_;
+  scoped_ptr<DevToolsHttpServer> http_server_;
+  scoped_ptr<DevToolsRegistryImpl> registry_;
 
   DISALLOW_COPY_AND_ASSIGN(DevToolsService);
 };
diff --git a/components/devtools_service/devtools_service_delegate.cc b/components/devtools_service/devtools_service_delegate.cc
index 7f0d230..137d06d2 100644
--- a/components/devtools_service/devtools_service_delegate.cc
+++ b/components/devtools_service/devtools_service_delegate.cc
@@ -5,6 +5,7 @@
 #include "components/devtools_service/devtools_service_delegate.h"
 
 #include "base/logging.h"
+#include "components/devtools_service/devtools_registry_impl.h"
 #include "components/devtools_service/devtools_service.h"
 #include "mojo/application/public/cpp/application_connection.h"
 #include "mojo/application/public/cpp/application_impl.h"
@@ -51,7 +52,8 @@
 void DevToolsServiceDelegate::Create(
     mojo::ApplicationConnection* connection,
     mojo::InterfaceRequest<DevToolsRegistry> request) {
-  service_->BindToRegistryRequest(request.Pass());
+  if (service_->IsInitialized())
+    service_->registry()->BindToRegistryRequest(request.Pass());
 }
 
 void DevToolsServiceDelegate::Create(
diff --git a/components/dom_distiller/content/distiller_page_web_contents.cc b/components/dom_distiller/content/distiller_page_web_contents.cc
index feaa259b..cfa408c 100644
--- a/components/dom_distiller/content/distiller_page_web_contents.cc
+++ b/components/dom_distiller/content/distiller_page_web_contents.cc
@@ -189,7 +189,8 @@
 void DistillerPageWebContents::OnWebContentsDistillationDone(
     const GURL& page_url,
     const base::Value* value) {
-  DCHECK(state_ == PAGELOAD_FAILED || state_ == EXECUTING_JAVASCRIPT);
+  DCHECK(state_ == IDLE || state_ == LOADING_PAGE ||  // TODO(nyquist): 493795.
+         state_ == PAGELOAD_FAILED || state_ == EXECUTING_JAVASCRIPT);
   state_ = IDLE;
   DistillerPage::OnDistillationDone(page_url, value);
 }
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 8a5266f..b51ba84 100644
--- a/components/dom_distiller/core/dom_distiller_request_view_base.cc
+++ b/components/dom_distiller/core/dom_distiller_request_view_base.cc
@@ -57,9 +57,6 @@
     SendJavaScript(viewer::GetUnsafeArticleContentJs(article_proto));
     // If any content was loaded, show the feedback form.
     SendJavaScript(viewer::GetShowFeedbackFormJs());
-  } else if (page_count_ == article_proto->pages_size()) {
-    // We may still be showing the "Loading" indicator.
-    SendJavaScript(viewer::GetToggleLoadingIndicatorJs(true));
   } else {
     // It's possible that we didn't get some incremental updates from the
     // distiller. Ensure all remaining pages are flushed to the viewer.
@@ -69,6 +66,8 @@
           &page, page_count_ == article_proto->pages_size()));
     }
   }
+  // We may still be showing the "Loading" indicator.
+  SendJavaScript(viewer::GetToggleLoadingIndicatorJs(true));
   // No need to hold on to the ViewerHandle now that distillation is complete.
   viewer_handle_.reset();
 }
@@ -81,7 +80,8 @@
         article_update.GetDistilledPage(page_count_);
     // Send the page content to the client. This will execute after the page is
     // ready.
-    SendJavaScript(viewer::GetUnsafeIncrementalDistilledPageJs(&page, false));
+    SendJavaScript(viewer::GetUnsafeIncrementalDistilledPageJs(
+        &page, !article_update.HasNextPage()));
 
     if (page_count_ == 0) {
       // This is the first page, so send the title and text direction to the
diff --git a/components/enhanced_bookmarks.gypi b/components/enhanced_bookmarks.gypi
index 3f0dc83..da543552 100644
--- a/components/enhanced_bookmarks.gypi
+++ b/components/enhanced_bookmarks.gypi
@@ -98,8 +98,8 @@
     ['OS=="android"', {
       'targets': [
         {
-          # GN: //components/enhanced_bookmarks:enhanced_bookmarks_launch_location_srcjar
-          'target_name': 'enhanced_bookmarks_launch_location_srcjar',
+          # GN: //components/enhanced_bookmarks:enhanced_bookmarks_java_enums_srcjar
+          'target_name': 'enhanced_bookmarks_java_enums_srcjar',
           'type': 'none',
           'variables': {
             'source_file': 'enhanced_bookmarks/enhanced_bookmark_utils.h',
diff --git a/components/enhanced_bookmarks/BUILD.gn b/components/enhanced_bookmarks/BUILD.gn
index 7395daa8..ad558161 100644
--- a/components/enhanced_bookmarks/BUILD.gn
+++ b/components/enhanced_bookmarks/BUILD.gn
@@ -59,13 +59,14 @@
 }
 
 if (is_android) {
-  # GYP: //components/enhanced_bookmarks.gypi:enhanced_bookmarks_launch_location_srcjar
-  java_cpp_enum("enhanced_bookmarks_launch_location_srcjar") {
+  # GYP: //components/enhanced_bookmarks.gypi:enhanced_bookmarks_java_enums_srcjar
+  java_cpp_enum("enhanced_bookmarks_java_enums_srcjar") {
     sources = [
       "enhanced_bookmark_utils.h",
     ]
     outputs = [
       "org/chromium/chrome/browser/enhanced_bookmarks/LaunchLocation.java",
+      "org/chromium/chrome/browser/enhanced_bookmarks/ViewMode.java",
     ]
   }
 }
diff --git a/components/enhanced_bookmarks/DEPS b/components/enhanced_bookmarks/DEPS
index 114b12c..1a3fa5a 100644
--- a/components/enhanced_bookmarks/DEPS
+++ b/components/enhanced_bookmarks/DEPS
@@ -4,6 +4,7 @@
   "+components/pref_registry",
   "+components/signin",
   "+components/sync_driver",
+  "+components/variations",
   "+google_apis/gaia",
   "+jni",
   "+net",
diff --git a/components/enhanced_bookmarks/enhanced_bookmark_utils.cc b/components/enhanced_bookmarks/enhanced_bookmark_utils.cc
index 1ca96cad..7108d98c 100644
--- a/components/enhanced_bookmarks/enhanced_bookmark_utils.cc
+++ b/components/enhanced_bookmarks/enhanced_bookmark_utils.cc
@@ -5,12 +5,15 @@
 #include "components/enhanced_bookmarks/enhanced_bookmark_utils.h"
 
 #include "components/bookmarks/browser/bookmark_model.h"
+#include "components/variations/variations_associated_data.h"
 
 using bookmarks::BookmarkModel;
 using bookmarks::BookmarkNode;
 
 namespace enhanced_bookmarks {
 
+const char kFieldTrialName[] = "EnhancedBookmarks";
+
 std::vector<const BookmarkNode*> PrimaryPermanentNodes(BookmarkModel* model) {
   DCHECK(model->loaded());
   std::vector<const BookmarkNode*> nodes;
@@ -63,4 +66,19 @@
   return top;
 }
 
+ViewMode GetDefaultViewMode() {
+  std::string default_view_mode = variations::GetVariationParamValue(
+      enhanced_bookmarks::kFieldTrialName, "DefaultViewMode");
+
+  if (default_view_mode == "List") {
+    return ViewMode::LIST;
+  } else if (default_view_mode == "Grid") {
+    return ViewMode::GRID;
+  }
+
+  // If finch data is not available or has an invalid value, we fall back to
+  // ViewMode::GRID.
+  return ViewMode::GRID;
+}
+
 }  // namespace enhanced_bookmarks
diff --git a/components/enhanced_bookmarks/enhanced_bookmark_utils.h b/components/enhanced_bookmarks/enhanced_bookmark_utils.h
index c66fa9a..81476eb 100644
--- a/components/enhanced_bookmarks/enhanced_bookmark_utils.h
+++ b/components/enhanced_bookmarks/enhanced_bookmark_utils.h
@@ -16,6 +16,8 @@
 
 namespace enhanced_bookmarks {
 
+extern const char kFieldTrialName[];
+
 // Possible locations where a bookmark can be opened from.
 // Please sync with the corresponding histograms.xml.
 //
@@ -31,6 +33,16 @@
   COUNT = 6,
 };
 
+// View modes of enhanced bookmarks' main items UI.
+//
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.enhanced_bookmarks
+enum ViewMode {
+  DEFAULT = 0,
+  LIST = 1,
+  GRID = 2,
+};
+
 // Returns the permanent nodes whose url children are considered uncategorized
 // and whose folder children should be shown in the bookmark menu.
 // |model| must be loaded.
@@ -54,6 +66,11 @@
     const bookmarks::BookmarkNode* node,
     bookmarks::BookmarkModel* model);
 
+// Returns the default view mode for main items UI.
+// The default is controlled by a finch experiment. If finch is not available or
+// has an invalid value, it returns a hard coded default view mode.
+ViewMode GetDefaultViewMode();
+
 }  // namespace enhanced_bookmarks
 
 #endif  // COMPONENTS_ENHANCED_BOOKMARKS_ENHANCED_BOOKMARK_UTILS_H_
diff --git a/components/gcm_driver/gcm_client_impl.cc b/components/gcm_driver/gcm_client_impl.cc
index 7777402b..1c3f8bf 100644
--- a/components/gcm_driver/gcm_client_impl.cc
+++ b/components/gcm_driver/gcm_client_impl.cc
@@ -943,7 +943,13 @@
       InstanceIDTokenInfo::FromRegistrationInfo(registration_info.get());
   if (instance_id_token_info) {
     auto instance_id_iter = instance_id_data_.find(registration_info->app_id);
-    DCHECK(instance_id_iter != instance_id_data_.end());
+    if (instance_id_iter == instance_id_data_.end()) {
+      // This should not be reached since we should not delete tokens when
+      // an InstanceID has not been created yet.
+      NOTREACHED();
+      return;
+    }
+
     std::string instance_id = instance_id_iter->second.first;
     std::string app_id = instance_id_token_info->app_id;
 
diff --git a/components/gcm_driver/instance_id/instance_id_driver.cc b/components/gcm_driver/instance_id/instance_id_driver.cc
index d2f156d..e671fef 100644
--- a/components/gcm_driver/instance_id/instance_id_driver.cc
+++ b/components/gcm_driver/instance_id/instance_id_driver.cc
@@ -46,4 +46,16 @@
   return instance_id;
 }
 
+void InstanceIDDriver::RemoveInstanceID(const std::string& app_id) {
+  auto iter = instance_id_map_.find(app_id);
+  if (iter == instance_id_map_.end())
+    return;
+  delete iter->second;
+  instance_id_map_.erase(iter);
+}
+
+bool InstanceIDDriver::ExistsInstanceID(const std::string& app_id) const {
+  return instance_id_map_.find(app_id) != instance_id_map_.end();
+}
+
 }  // namespace instance_id
diff --git a/components/gcm_driver/instance_id/instance_id_driver.h b/components/gcm_driver/instance_id/instance_id_driver.h
index 496964f..4bb9fd7 100644
--- a/components/gcm_driver/instance_id/instance_id_driver.h
+++ b/components/gcm_driver/instance_id/instance_id_driver.h
@@ -33,6 +33,14 @@
   // application. The lifetime of InstanceID will be managed by this class.
   InstanceID* GetInstanceID(const std::string& app_id);
 
+  // Removes the InstanceID when it is not longer needed, i.e. the app is being
+  // uninstalled.
+  void RemoveInstanceID(const std::string& app_id);
+
+  // Returns true if the InstanceID for the given application has been created.
+  // This is currently only used for testing purpose.
+  bool ExistsInstanceID(const std::string& app_id) const;
+
  private:
   gcm::GCMDriver* gcm_driver_;  // Not owned.
   typedef std::map<std::string, InstanceID*> InstanceIDMap;
diff --git a/components/gcm_driver/instance_id/instance_id_driver_unittest.cc b/components/gcm_driver/instance_id/instance_id_driver_unittest.cc
index 5e793313..af638666 100644
--- a/components/gcm_driver/instance_id/instance_id_driver_unittest.cc
+++ b/components/gcm_driver/instance_id/instance_id_driver_unittest.cc
@@ -221,6 +221,17 @@
     async_operation_completed_callback_.Run();
 }
 
+TEST_F(InstanceIDDriverTest, GetAndRemoveInstanceID) {
+  EXPECT_FALSE(driver()->ExistsInstanceID(kTestAppID1));
+
+  InstanceID* instance_id = driver()->GetInstanceID(kTestAppID1);
+  EXPECT_TRUE(instance_id);
+  EXPECT_TRUE(driver()->ExistsInstanceID(kTestAppID1));
+
+  driver()->RemoveInstanceID(kTestAppID1);
+  EXPECT_FALSE(driver()->ExistsInstanceID(kTestAppID1));
+}
+
 TEST_F(InstanceIDDriverTest, NewID) {
   // Creation time should not be set when the ID is not created.
   InstanceID* instance_id1 = driver()->GetInstanceID(kTestAppID1);
diff --git a/components/google.gypi b/components/google.gypi
index 5fb0dd0..9ab6bac8 100644
--- a/components/google.gypi
+++ b/components/google.gypi
@@ -14,6 +14,7 @@
         '../url/url.gyp:url_lib',
         'components_strings.gyp:components_strings',
         'keyed_service_core',
+        'pref_registry',
         'url_fixer',
       ],
       'include_dirs': [
diff --git a/components/google/core/browser/BUILD.gn b/components/google/core/browser/BUILD.gn
index 9af9ff6..f499496 100644
--- a/components/google/core/browser/BUILD.gn
+++ b/components/google/core/browser/BUILD.gn
@@ -22,6 +22,7 @@
     "//base",
     "//base:prefs",
     "//components/keyed_service/core",
+    "//components/pref_registry",
     "//components/strings",
     "//components/url_fixer",
     "//net",
diff --git a/components/google/core/browser/DEPS b/components/google/core/browser/DEPS
index f0bf3d9..7a27ff5 100644
--- a/components/google/core/browser/DEPS
+++ b/components/google/core/browser/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
   "+components/keyed_service/core",
+  "+components/pref_registry",
 ]
diff --git a/components/google/core/browser/google_pref_names.cc b/components/google/core/browser/google_pref_names.cc
index eeb8de1..92787d0 100644
--- a/components/google/core/browser/google_pref_names.cc
+++ b/components/google/core/browser/google_pref_names.cc
@@ -11,4 +11,7 @@
 // correct Google domain/country code for whatever location the user is in.
 const char kLastKnownGoogleURL[] = "browser.last_known_google_url";
 
+// String containing the last prompted Google URL.
+const char kLastPromptedGoogleURL[] = "browser.last_prompted_google_url";
+
 }  // namespace prefs
diff --git a/components/google/core/browser/google_pref_names.h b/components/google/core/browser/google_pref_names.h
index 4307c92..2c58dd2 100644
--- a/components/google/core/browser/google_pref_names.h
+++ b/components/google/core/browser/google_pref_names.h
@@ -10,6 +10,7 @@
 // Alphabetical list of preference names specific to the Google
 // component. Keep alphabetized, and document each in the .cc file.
 extern const char kLastKnownGoogleURL[];
+extern const char kLastPromptedGoogleURL[];
 
 }  // namespace prefs
 
diff --git a/components/google/core/browser/google_url_tracker.cc b/components/google/core/browser/google_url_tracker.cc
index dabfc40..0b834308 100644
--- a/components/google/core/browser/google_url_tracker.cc
+++ b/components/google/core/browser/google_url_tracker.cc
@@ -14,6 +14,7 @@
 #include "components/google/core/browser/google_pref_names.h"
 #include "components/google/core/browser/google_switches.h"
 #include "components/google/core/browser/google_util.h"
+#include "components/pref_registry/pref_registry_syncable.h"
 #include "net/base/load_flags.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_status.h"
@@ -59,6 +60,14 @@
 GoogleURLTracker::~GoogleURLTracker() {
 }
 
+// static
+void GoogleURLTracker::RegisterProfilePrefs(
+    user_prefs::PrefRegistrySyncable* registry) {
+  registry->RegisterStringPref(prefs::kLastKnownGoogleURL,
+                               GoogleURLTracker::kDefaultGoogleHomepage);
+  registry->RegisterStringPref(prefs::kLastPromptedGoogleURL, std::string());
+}
+
 void GoogleURLTracker::RequestServerCheck(bool force) {
   // If this instance already has a fetcher, SetNeedToFetch() is unnecessary,
   // and changing |already_fetched_| is wrong.
diff --git a/components/google/core/browser/google_url_tracker.h b/components/google/core/browser/google_url_tracker.h
index d59b85a..70dde41 100644
--- a/components/google/core/browser/google_url_tracker.h
+++ b/components/google/core/browser/google_url_tracker.h
@@ -22,6 +22,10 @@
 class InfoBar;
 }
 
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
 // This object is responsible for checking the Google URL once per network
 // change.  The current value is saved to prefs.
 //
@@ -57,6 +61,10 @@
 
   ~GoogleURLTracker() override;
 
+  // Register user preferences for GoogleURLTracker.
+  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
+
   // Returns the current Google homepage URL.
   const GURL& google_url() const { return google_url_; }
 
diff --git a/components/google/core/browser/google_util.h b/components/google/core/browser/google_util.h
index a96622db..0d668314 100644
--- a/components/google/core/browser/google_util.h
+++ b/components/google/core/browser/google_util.h
@@ -4,8 +4,8 @@
 //
 // Some Google related utility functions.
 
-#ifndef COMPONENTS_GOOGLE_CORE_BROWSER_GOOGLE_UTIL_H__
-#define COMPONENTS_GOOGLE_CORE_BROWSER_GOOGLE_UTIL_H__
+#ifndef COMPONENTS_GOOGLE_CORE_BROWSER_GOOGLE_UTIL_H_
+#define COMPONENTS_GOOGLE_CORE_BROWSER_GOOGLE_UTIL_H_
 
 #include <string>
 
@@ -111,4 +111,4 @@
 
 }  // namespace google_util
 
-#endif  // COMPONENTS_GOOGLE_CORE_BROWSER_GOOGLE_UTIL_H__
+#endif  // COMPONENTS_GOOGLE_CORE_BROWSER_GOOGLE_UTIL_H_
diff --git a/components/html_viewer/BUILD.gn b/components/html_viewer/BUILD.gn
index 54f8c71..2d79209 100644
--- a/components/html_viewer/BUILD.gn
+++ b/components/html_viewer/BUILD.gn
@@ -71,6 +71,8 @@
     "blink_url_request_type_converters.h",
     "discardable_memory_allocator.cc",
     "discardable_memory_allocator.h",
+    "frame_tree_manager.cc",
+    "frame_tree_manager.h",
     "html_document.cc",
     "html_document.h",
     "media_factory.cc",
@@ -120,6 +122,7 @@
     "//components/webcrypto",
     "//gin",
     "//mandoline/services/navigation/public/interfaces",
+    "//mandoline/tab/public/interfaces",
     "//media",
     "//media/blink",
     "//media/mojo",
diff --git a/components/html_viewer/DEPS b/components/html_viewer/DEPS
index baf64b8..159ccb1 100644
--- a/components/html_viewer/DEPS
+++ b/components/html_viewer/DEPS
@@ -12,10 +12,12 @@
   "+components/webcrypto",
   "+gin",
   "+mandoline/services",
+  "+mandoline/tab/public/interfaces",
   "+media",
   "+mojo/application",
   "+mojo/cc",
   "+mojo/common",
+  "+mojo/converters/geometry",
   "+mojo/converters/surfaces",
   "+mojo/platform_handle",
   "+mojo/public",
diff --git a/components/html_viewer/ax_provider_impl_unittest.cc b/components/html_viewer/ax_provider_impl_unittest.cc
index bfbd9a7e..7f9736a 100644
--- a/components/html_viewer/ax_provider_impl_unittest.cc
+++ b/components/html_viewer/ax_provider_impl_unittest.cc
@@ -51,6 +51,7 @@
         renderer_scheduler_(scheduler::RendererScheduler::Create()) {
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
     gin::V8Initializer::LoadV8Snapshot();
+    gin::V8Initializer::LoadV8Natives();
 #endif
     blink::initialize(
         new html_viewer::BlinkPlatformImpl(nullptr, renderer_scheduler_.get()));
diff --git a/components/html_viewer/blink_platform_impl.cc b/components/html_viewer/blink_platform_impl.cc
index a1bacdd1..7c37000 100644
--- a/components/html_viewer/blink_platform_impl.cc
+++ b/components/html_viewer/blink_platform_impl.cc
@@ -71,7 +71,10 @@
   if (app) {
     mojo::URLRequestPtr request(mojo::URLRequest::New());
     request->url = mojo::String::From("mojo:network_service");
-    app->ConnectToService(request.Pass(), &network_service_);
+    mojo::ApplicationConnection* connection =
+        app->ConnectToApplication(request.Pass());
+    connection->ConnectToService(&network_service_);
+    connection->ConnectToService(&url_loader_factory_);
 
     mojo::CookieStorePtr cookie_store;
     network_service_->GetCookieStore(GetProxy(&cookie_store));
@@ -204,7 +207,7 @@
 }
 
 blink::WebURLLoader* BlinkPlatformImpl::createURLLoader() {
-  return new WebURLLoaderImpl(network_service_.get(), &blob_registry_);
+  return new WebURLLoaderImpl(url_loader_factory_.get(), &blob_registry_);
 }
 
 blink::WebSocketHandle* BlinkPlatformImpl::createWebSocketHandle() {
diff --git a/components/html_viewer/blink_platform_impl.h b/components/html_viewer/blink_platform_impl.h
index 09a149c6..36cdb1f2 100644
--- a/components/html_viewer/blink_platform_impl.h
+++ b/components/html_viewer/blink_platform_impl.h
@@ -16,6 +16,7 @@
 #include "components/html_viewer/web_theme_engine_impl.h"
 #include "components/webcrypto/webcrypto_impl.h"
 #include "mojo/services/network/public/interfaces/network_service.mojom.h"
+#include "mojo/services/network/public/interfaces/url_loader_factory.mojom.h"
 #include "third_party/WebKit/public/platform/Platform.h"
 #include "third_party/WebKit/public/platform/WebScrollbarBehavior.h"
 
@@ -111,6 +112,7 @@
   blink::WebScrollbarBehavior scrollbar_behavior_;
   BlinkResourceMap blink_resource_map_;
   mojo::NetworkServicePtr network_service_;
+  mojo::URLLoaderFactoryPtr url_loader_factory_;
   MockWebBlobRegistryImpl blob_registry_;
   scoped_ptr<WebCookieJarImpl> cookie_jar_;
   scoped_ptr<WebClipboardImpl> clipboard_;
diff --git a/components/html_viewer/frame_tree_manager.cc b/components/html_viewer/frame_tree_manager.cc
new file mode 100644
index 0000000..6f0c531
--- /dev/null
+++ b/components/html_viewer/frame_tree_manager.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 "components/html_viewer/frame_tree_manager.h"
+
+namespace html_viewer {
+
+FrameTreeManager::FrameTreeManager() {
+}
+
+FrameTreeManager::~FrameTreeManager() {
+}
+
+void FrameTreeManager::OnConnect(mandoline::FrameTreeServerPtr server,
+                                 mojo::Array<mandoline::FrameDataPtr> frames) {
+}
+
+void FrameTreeManager::OnFrameAdded(mandoline::FrameDataPtr frame) {
+}
+
+void FrameTreeManager::OnFrameRemoved(uint32_t frame_id) {
+}
+
+}  // namespace mojo
diff --git a/components/html_viewer/frame_tree_manager.h b/components/html_viewer/frame_tree_manager.h
new file mode 100644
index 0000000..6c129636
--- /dev/null
+++ b/components/html_viewer/frame_tree_manager.h
@@ -0,0 +1,33 @@
+// 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_HTML_VIEWER_FRAME_TREE_MANAGER_H_
+#define COMPONENTS_HTML_VIEWER_FRAME_TREE_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "mandoline/tab/public/interfaces/frame_tree.mojom.h"
+
+namespace html_viewer {
+
+// FrameTreeManager is the FrameTreeClient implementation for an HTMLDocument.
+// It keeps the blink frame tree in sync with that of the FrameTreeServer.
+// TODO(sky): make it actually do this.
+class FrameTreeManager : public mandoline::FrameTreeClient {
+ public:
+  FrameTreeManager();
+  ~FrameTreeManager() override;
+
+ private:
+  // mandoline::FrameTreeClient:
+  void OnConnect(mandoline::FrameTreeServerPtr server,
+                 mojo::Array<mandoline::FrameDataPtr> frames) override;
+  void OnFrameAdded(mandoline::FrameDataPtr frame) override;
+  void OnFrameRemoved(uint32_t frame_id) override;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameTreeManager);
+};
+
+}  // namespace html_viewer
+
+#endif  // COMPONENTS_HTML_VIEWER_FRAME_TREE_MANAGER_H_
diff --git a/components/html_viewer/html_document.cc b/components/html_viewer/html_document.cc
index 0ef5068..62ef9cb 100644
--- a/components/html_viewer/html_document.cc
+++ b/components/html_viewer/html_document.cc
@@ -26,6 +26,7 @@
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/application/public/cpp/connect.h"
 #include "mojo/application/public/interfaces/shell.mojom.h"
+#include "mojo/converters/geometry/geometry_type_converters.h"
 #include "skia/ext/refptr.h"
 #include "third_party/WebKit/public/platform/Platform.h"
 #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
@@ -142,21 +143,26 @@
 
 }  // namespace
 
-HTMLDocument::HTMLDocument(
-    mojo::InterfaceRequest<mojo::ServiceProvider> services,
-    URLResponsePtr response,
-    mojo::ShellPtr shell,
-    Setup* setup)
-    : app_refcount_(setup->app()->app_lifetime_helper()->CreateAppRefCount()),
+HTMLDocument::HTMLDocument(mojo::ApplicationImpl* html_document_app,
+                           mojo::ApplicationConnection* connection,
+                           URLResponsePtr response,
+                           Setup* setup)
+    : app_refcount_(
+          html_document_app->app_lifetime_helper()->CreateAppRefCount()),
+      html_document_app_(html_document_app),
       response_(response.Pass()),
-      shell_(shell.Pass()),
       web_view_(nullptr),
       root_(nullptr),
-      view_manager_client_factory_(shell_.get(), this),
-      setup_(setup) {
-  exported_services_.AddService(this);
-  exported_services_.AddService(&view_manager_client_factory_);
-  exported_services_.Bind(services.Pass());
+      view_manager_client_factory_(html_document_app->shell(), this),
+      setup_(setup),
+      frame_tree_manager_binding_(&frame_tree_manager_) {
+  embedder_exported_services_.AddService(
+      static_cast<mojo::InterfaceFactory<mandoline::FrameTreeClient>*>(this));
+
+  connection->AddService(
+      static_cast<InterfaceFactory<mojo::AxProvider>*>(this));
+  connection->AddService(&view_manager_client_factory_);
+
   if (setup_->did_init())
     Load(response_.Pass());
 }
@@ -181,6 +187,8 @@
   embedder_service_provider_ = exposed_services.Pass();
   navigator_host_.set_service_provider(embedder_service_provider_.get());
 
+  embedder_exported_services_.Bind(services.Pass());
+
   InitSetupAndLoadIfNecessary();
 }
 
@@ -201,6 +209,12 @@
   }
 }
 
+void HTMLDocument::Create(
+    mojo::ApplicationConnection* connection,
+    mojo::InterfaceRequest<mandoline::FrameTreeClient> request) {
+  frame_tree_manager_binding_.Bind(request.Pass());
+}
+
 void HTMLDocument::Load(URLResponsePtr response) {
   DCHECK(!web_view_);
   web_view_ = blink::WebView::create(this);
@@ -248,9 +262,9 @@
     return;
 
   if (!web_view_) {
-    setup_->InitIfNecessary(gfx::Size(root_->viewport_metrics().size->width,
-                                      root_->viewport_metrics().size->height),
-                            root_->viewport_metrics().device_pixel_ratio);
+    setup_->InitIfNecessary(
+        root_->viewport_metrics().size_in_pixels.To<gfx::Size>(),
+        root_->viewport_metrics().device_pixel_ratio);
     Load(response_.Pass());
   }
 
@@ -272,13 +286,13 @@
   mojo::URLRequestPtr request(mojo::URLRequest::New());
   request->url = mojo::String::From("mojo:surfaces_service");
   mojo::SurfacePtr surface;
-  setup_->app()->ConnectToService(request.Pass(), &surface);
+  html_document_app_->ConnectToService(request.Pass(), &surface);
 
   // TODO(jamesr): Should be mojo:gpu_service
   mojo::URLRequestPtr request2(mojo::URLRequest::New());
   request2->url = mojo::String::From("mojo:view_manager");
   mojo::GpuPtr gpu_service;
-  setup_->app()->ConnectToService(request2.Pass(), &gpu_service);
+  html_document_app_->ConnectToService(request2.Pass(), &gpu_service);
   web_layer_tree_view_impl_.reset(new WebLayerTreeViewImpl(
       setup_->compositor_thread(), surface.Pass(), gpu_service.Pass()));
 }
@@ -292,8 +306,8 @@
     const blink::WebURL& url,
     blink::WebMediaPlayerClient* client,
     blink::WebContentDecryptionModule* initial_cdm) {
-  return setup_->media_factory()->CreateMediaPlayer(frame, url, client,
-                                                    initial_cdm, shell_.get());
+  return setup_->media_factory()->CreateMediaPlayer(
+      frame, url, client, initial_cdm, html_document_app_->shell());
 }
 
 blink::WebFrame* HTMLDocument::createChildFrame(
@@ -409,7 +423,6 @@
 void HTMLDocument::OnViewDestroyed(View* view) {
   DCHECK_EQ(view, root_);
   root_ = nullptr;
-  shell_->QuitApplication();
 }
 
 void HTMLDocument::OnViewInputEvent(View* view, const mojo::EventPtr& event) {
diff --git a/components/html_viewer/html_document.h b/components/html_viewer/html_document.h
index c082ac1..2ddaf04 100644
--- a/components/html_viewer/html_document.h
+++ b/components/html_viewer/html_document.h
@@ -11,11 +11,13 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "components/html_viewer/ax_provider_impl.h"
+#include "components/html_viewer/frame_tree_manager.h"
 #include "components/html_viewer/touch_handler.h"
 #include "components/view_manager/public/cpp/view_manager_client_factory.h"
 #include "components/view_manager/public/cpp/view_manager_delegate.h"
 #include "components/view_manager/public/cpp/view_observer.h"
 #include "mandoline/services/navigation/public/interfaces/navigation.mojom.h"
+#include "mandoline/tab/public/interfaces/frame_tree.mojom.h"
 #include "mojo/application/public/cpp/app_lifetime_helper.h"
 #include "mojo/application/public/cpp/interface_factory.h"
 #include "mojo/application/public/cpp/lazy_interface_ptr.h"
@@ -48,19 +50,16 @@
                      public blink::WebFrameClient,
                      public mojo::ViewManagerDelegate,
                      public mojo::ViewObserver,
-                     public mojo::InterfaceFactory<mojo::AxProvider> {
+                     public mojo::InterfaceFactory<mojo::AxProvider>,
+                     public mojo::InterfaceFactory<mandoline::FrameTreeClient> {
  public:
   // Load a new HTMLDocument with |response|.
-  //
-  // |services| should be used to implement a ServiceProvider which exposes
-  // services to the connecting application.
-  // Commonly, the connecting application is the ViewManager and it will
-  // request ViewManagerClient.
-  //
-  // |shell| is the Shell connection for this mojo::Application.
-  HTMLDocument(mojo::InterfaceRequest<mojo::ServiceProvider> services,
+  // |html_document_app| is the application this app was created in, and
+  // |connection| the specific connection triggering this new instance.
+  // |setup| is used to obtain init type state (such as resources).
+  HTMLDocument(mojo::ApplicationImpl* html_document_app,
+               mojo::ApplicationConnection* connection,
                mojo::URLResponsePtr response,
-               mojo::ShellPtr shell,
                Setup* setup);
   ~HTMLDocument() override;
 
@@ -133,6 +132,11 @@
   void Create(mojo::ApplicationConnection* connection,
               mojo::InterfaceRequest<mojo::AxProvider> request) override;
 
+  // mojo::InterfaceFactory<mandoline::FrameTreeClient>
+  void Create(
+      mojo::ApplicationConnection* connection,
+      mojo::InterfaceRequest<mandoline::FrameTreeClient> request) override;
+
   void Load(mojo::URLResponsePtr response);
 
   // Converts a WebLocalFrame to a WebRemoteFrame. Used once we know the
@@ -140,10 +144,10 @@
   void ConvertLocalFrameToRemoteFrame(blink::WebLocalFrame* frame);
 
   scoped_ptr<mojo::AppRefCount> app_refcount_;
+  mojo::ApplicationImpl* html_document_app_;
   mojo::URLResponsePtr response_;
-  mojo::ServiceProviderImpl exported_services_;
   mojo::ServiceProviderPtr embedder_service_provider_;
-  mojo::ShellPtr shell_;
+  mojo::ServiceProviderImpl embedder_exported_services_;
   mojo::LazyInterfacePtr<mojo::NavigatorHost> navigator_host_;
   blink::WebView* web_view_;
   mojo::View* root_;
@@ -164,6 +168,9 @@
 
   FrameToViewMap frame_to_view_;
 
+  FrameTreeManager frame_tree_manager_;
+  mojo::Binding<mandoline::FrameTreeClient> frame_tree_manager_binding_;
+
   DISALLOW_COPY_AND_ASSIGN(HTMLDocument);
 };
 
diff --git a/components/html_viewer/html_viewer.cc b/components/html_viewer/html_viewer.cc
index fad2bc60..c891987 100644
--- a/components/html_viewer/html_viewer.cc
+++ b/components/html_viewer/html_viewer.cc
@@ -20,6 +20,7 @@
 #include "mojo/application/public/interfaces/content_handler.mojom.h"
 #include "mojo/common/common_type_converters.h"
 #include "mojo/services/network/public/interfaces/network_service.mojom.h"
+#include "mojo/services/network/public/interfaces/url_loader_factory.mojom.h"
 #include "third_party/WebKit/public/web/WebKit.h"
 #include "third_party/mojo/src/mojo/public/c/system/main.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
@@ -40,96 +41,108 @@
 
 class HTMLViewer;
 
-class HTMLViewerApplication : public mojo::Application {
+// ApplicationDelegate created by the content handler for a specific url.
+class HTMLDocumentApplicationDelegate : public mojo::ApplicationDelegate {
  public:
-  HTMLViewerApplication(InterfaceRequest<Application> request,
-                        URLResponsePtr response,
-                        Setup* setup)
-      : app_refcount_(setup->app()->app_lifetime_helper()->CreateAppRefCount()),
+  HTMLDocumentApplicationDelegate(
+      mojo::InterfaceRequest<mojo::Application> request,
+      mojo::URLResponsePtr response,
+      Setup* setup,
+      scoped_ptr<mojo::AppRefCount> parent_app_refcount)
+      : app_(this,
+             request.Pass(),
+             base::Bind(&HTMLDocumentApplicationDelegate::OnTerminate,
+                        base::Unretained(this))),
+        parent_app_refcount_(parent_app_refcount.Pass()),
         url_(response->url),
-        binding_(this, request.Pass()),
         initial_response_(response.Pass()),
-        setup_(setup) {
+        setup_(setup) {}
+
+ private:
+  ~HTMLDocumentApplicationDelegate() override {}
+
+  // Callback from the quit closure. We key off this rather than
+  // ApplicationDelegate::Quit() as we don't want to shut down the messageloop
+  // when we quit (the messageloop is shared among multiple
+  // HTMLDocumentApplicationDelegates).
+  void OnTerminate() {
+    delete this;
   }
 
-  ~HTMLViewerApplication() override {
-  }
-
-  void Initialize(ShellPtr shell, const String& url) override {
-    shell_ = shell.Pass();
+  // ApplicationDelegate;
+  void Initialize(mojo::ApplicationImpl* app) override {
     mojo::URLRequestPtr request(mojo::URLRequest::New());
     request->url = mojo::String::From("mojo:network_service");
-    setup_->app()->ConnectToService(request.Pass(), &network_service_);
+    mojo::ApplicationConnection* connection =
+        app_.ConnectToApplication(request.Pass());
+    connection->ConnectToService(&network_service_);
+    connection->ConnectToService(&url_loader_factory_);
   }
-
-  void AcceptConnection(const String& requestor_url,
-                        InterfaceRequest<ServiceProvider> services,
-                        ServiceProviderPtr exposed_services,
-                        const String& url) override {
+  bool ConfigureIncomingConnection(
+      mojo::ApplicationConnection* connection) override {
     if (initial_response_) {
-      OnResponseReceived(URLLoaderPtr(), services.Pass(),
-                         initial_response_.Pass());
+      OnResponseReceived(URLLoaderPtr(), connection, initial_response_.Pass());
     } else {
       URLLoaderPtr loader;
-      network_service_->CreateURLLoader(GetProxy(&loader));
+      url_loader_factory_->CreateURLLoader(GetProxy(&loader));
       mojo::URLRequestPtr request(mojo::URLRequest::New());
       request->url = url_;
       request->auto_follow_redirects = true;
 
-      // |loader| will be pass to the OnResponseReceived method through a
+      // |loader| will be passed to the OnResponseReceived method through a
       // callback. Because order of evaluation is undefined, a reference to the
       // raw pointer is needed.
       mojo::URLLoader* raw_loader = loader.get();
       raw_loader->Start(
           request.Pass(),
-          base::Bind(&HTMLViewerApplication::OnResponseReceived,
+          base::Bind(&HTMLDocumentApplicationDelegate::OnResponseReceived,
                      base::Unretained(this), base::Passed(&loader),
-                     base::Passed(&services)));
+                     connection));
     }
+    return true;
   }
 
-  void OnQuitRequested(const mojo::Callback<void(bool)>& callback) override {
-    callback.Run(true);
-    delete this;
-  }
-
- private:
   void OnResponseReceived(URLLoaderPtr loader,
-                          InterfaceRequest<ServiceProvider> services,
+                          mojo::ApplicationConnection* connection,
                           URLResponsePtr response) {
     // HTMLDocument is destroyed when the hosting view is destroyed.
     // TODO(sky): when headless, this leaks.
-    new HTMLDocument(services.Pass(), response.Pass(), shell_.Pass(), setup_);
+    // TODO(sky): this needs to delete if serviceprovider goes away too.
+    new HTMLDocument(&app_, connection, response.Pass(), setup_);
   }
 
-  scoped_ptr<mojo::AppRefCount> app_refcount_;
-  String url_;
-  mojo::StrongBinding<mojo::Application> binding_;
-  ShellPtr shell_;
+  mojo::ApplicationImpl app_;
+  // AppRefCount of the parent (HTMLViewer).
+  scoped_ptr<mojo::AppRefCount> parent_app_refcount_;
+  const String url_;
   mojo::NetworkServicePtr network_service_;
+  mojo::URLLoaderFactoryPtr url_loader_factory_;
   URLResponsePtr initial_response_;
   Setup* setup_;
 
-  DISALLOW_COPY_AND_ASSIGN(HTMLViewerApplication);
+  DISALLOW_COPY_AND_ASSIGN(HTMLDocumentApplicationDelegate);
 };
 
 class ContentHandlerImpl : public mojo::ContentHandler {
  public:
   ContentHandlerImpl(Setup* setup,
+                     mojo::ApplicationImpl* app,
                      mojo::InterfaceRequest<ContentHandler> request)
-      : setup_(setup),
-        binding_(this, request.Pass()) {}
+      : setup_(setup), app_(app), binding_(this, request.Pass()) {}
   ~ContentHandlerImpl() override {}
 
  private:
   // Overridden from ContentHandler:
   void StartApplication(InterfaceRequest<mojo::Application> request,
                         URLResponsePtr response) override {
-    // HTMLViewerApplication is owned by the binding.
-    new HTMLViewerApplication(request.Pass(), response.Pass(), setup_);
+    // HTMLDocumentApplicationDelegate deletes itself.
+    new HTMLDocumentApplicationDelegate(
+        request.Pass(), response.Pass(), setup_,
+        app_->app_lifetime_helper()->CreateAppRefCount());
   }
 
   Setup* setup_;
+  mojo::ApplicationImpl* app_;
   mojo::StrongBinding<mojo::ContentHandler> binding_;
 
   DISALLOW_COPY_AND_ASSIGN(ContentHandlerImpl);
@@ -138,12 +151,13 @@
 class HTMLViewer : public mojo::ApplicationDelegate,
                    public mojo::InterfaceFactory<ContentHandler> {
  public:
-  HTMLViewer() {}
+  HTMLViewer() : app_(nullptr) {}
   ~HTMLViewer() override {}
 
  private:
   // Overridden from ApplicationDelegate:
   void Initialize(mojo::ApplicationImpl* app) override {
+    app_ = app;
     setup_.reset(new Setup(app));
   }
 
@@ -162,10 +176,11 @@
   // Overridden from InterfaceFactory<ContentHandler>
   void Create(ApplicationConnection* connection,
               mojo::InterfaceRequest<ContentHandler> request) override {
-    new ContentHandlerImpl(setup_.get(), request.Pass());
+    new ContentHandlerImpl(setup_.get(), app_, request.Pass());
   }
 
   scoped_ptr<Setup> setup_;
+  mojo::ApplicationImpl* app_;
 
   DISALLOW_COPY_AND_ASSIGN(HTMLViewer);
 };
diff --git a/components/html_viewer/setup.cc b/components/html_viewer/setup.cc
index cdbf7323..76a6614 100644
--- a/components/html_viewer/setup.cc
+++ b/components/html_viewer/setup.cc
@@ -114,11 +114,12 @@
   renderer_scheduler_ = scheduler::RendererScheduler::Create();
   blink_platform_.reset(new BlinkPlatformImpl(app_, renderer_scheduler_.get()));
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
-  CHECK(gin::V8Initializer::LoadV8SnapshotFromFD(
-      resource_loader_.ReleaseFile(kResourceNativesBlob).TakePlatformFile(), 0u,
-      0u,
+  gin::V8Initializer::LoadV8SnapshotFromFD(
       resource_loader_.ReleaseFile(kResourceSnapshotBlob).TakePlatformFile(),
-      0u, 0u));
+      0u, 0u);
+  gin::V8Initializer::LoadV8NativesFromFD(
+      resource_loader_.ReleaseFile(kResourceNativesBlob).TakePlatformFile(), 0u,
+      0u);
 #endif
   blink::initialize(blink_platform_.get());
   base::i18n::InitializeICUWithFileDescriptor(
diff --git a/components/html_viewer/setup.h b/components/html_viewer/setup.h
index 07e54d38..ed32554 100644
--- a/components/html_viewer/setup.h
+++ b/components/html_viewer/setup.h
@@ -49,7 +49,6 @@
   void InitIfNecessary(const gfx::Size& screen_size_in_pixels,
                        float device_pixel_ratio);
 
-  mojo::ApplicationImpl* app() const { return app_; }
   bool is_headless() const { return is_headless_; }
   bool did_init() const { return did_init_; }
 
@@ -66,6 +65,9 @@
   MediaFactory* media_factory() { return media_factory_.get(); }
 
  private:
+  // App for HTMLViewer, not the document's app.
+  // WARNING: do not expose this. It's too easy to use the wrong one.
+  // HTMLDocument should be using the application it creates, not this one.
   mojo::ApplicationImpl* app_;
 
   resource_provider::ResourceLoader resource_loader_;
diff --git a/components/html_viewer/web_layer_tree_view_impl.h b/components/html_viewer/web_layer_tree_view_impl.h
index 0cb324b..d9cef8cf 100644
--- a/components/html_viewer/web_layer_tree_view_impl.h
+++ b/components/html_viewer/web_layer_tree_view_impl.h
@@ -67,6 +67,10 @@
   void DidCompleteSwapBuffers() override;
   void DidCompletePageScaleAnimation() override {}
   void RateLimitSharedMainThreadContext() override {}
+  void RecordFrameTimingEvents(
+      scoped_ptr<cc::FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<cc::FrameTimingTracker::MainFrameTimingSet> main_frame_events)
+      override {}
 
   // blink::WebLayerTreeView implementation.
   virtual void setRootLayer(const blink::WebLayer& layer);
diff --git a/components/html_viewer/web_url_loader_impl.cc b/components/html_viewer/web_url_loader_impl.cc
index a9632f4..ebaece9a 100644
--- a/components/html_viewer/web_url_loader_impl.cc
+++ b/components/html_viewer/web_url_loader_impl.cc
@@ -12,7 +12,7 @@
 #include "components/html_viewer/blink_url_request_type_converters.h"
 #include "mojo/common/common_type_converters.h"
 #include "mojo/common/url_type_converters.h"
-#include "mojo/services/network/public/interfaces/network_service.mojom.h"
+#include "mojo/services/network/public/interfaces/url_loader_factory.mojom.h"
 #include "net/base/net_errors.h"
 #include "third_party/WebKit/public/platform/WebURLError.h"
 #include "third_party/WebKit/public/platform/WebURLLoadTiming.h"
@@ -71,13 +71,13 @@
 WebURLRequestExtraData::~WebURLRequestExtraData() {
 }
 
-WebURLLoaderImpl::WebURLLoaderImpl(mojo::NetworkService* network_service,
+WebURLLoaderImpl::WebURLLoaderImpl(mojo::URLLoaderFactory* url_loader_factory,
                                    MockWebBlobRegistryImpl* web_blob_registry)
     : client_(NULL),
       web_blob_registry_(web_blob_registry),
       referrer_policy_(blink::WebReferrerPolicyDefault),
       weak_factory_(this) {
-  network_service->CreateURLLoader(GetProxy(&url_loader_));
+  url_loader_factory->CreateURLLoader(GetProxy(&url_loader_));
 }
 
 WebURLLoaderImpl::~WebURLLoaderImpl() {
diff --git a/components/html_viewer/web_url_loader_impl.h b/components/html_viewer/web_url_loader_impl.h
index 4a92a8aa..7ff3a4333 100644
--- a/components/html_viewer/web_url_loader_impl.h
+++ b/components/html_viewer/web_url_loader_impl.h
@@ -16,7 +16,7 @@
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
 
 namespace mojo {
-class NetworkService;
+class URLLoaderFactory;
 }
 
 namespace html_viewer {
@@ -32,7 +32,7 @@
 
 class WebURLLoaderImpl : public blink::WebURLLoader {
  public:
-  explicit WebURLLoaderImpl(mojo::NetworkService* network_service,
+  explicit WebURLLoaderImpl(mojo::URLLoaderFactory* url_loader_factory,
                             MockWebBlobRegistryImpl* web_blob_registry);
 
  private:
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index 5d5ff375..ec6cd82 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -62,9 +62,6 @@
     bool is_navigation_to_different_page;
     // True if the entry replaced the existing one.
     bool did_replace_entry;
-    // True for the main frame, false for a sub-frame.
-    bool is_main_frame;
-    bool is_reload;
     bool is_redirect;
   };
 
diff --git a/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc b/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc
index 7a7a6f0..03c99158 100644
--- a/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc
+++ b/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.cc
@@ -62,11 +62,6 @@
   return context;
 }
 
-void RefcountedBrowserContextKeyedServiceFactory::
-    RegisterUserPrefsOnBrowserContextForTest(content::BrowserContext* context) {
-  KeyedServiceBaseFactory::RegisterUserPrefsOnContextForTest(context);
-}
-
 bool RefcountedBrowserContextKeyedServiceFactory::
     ServiceIsCreatedWithBrowserContext() const {
   return KeyedServiceBaseFactory::ServiceIsCreatedWithContext();
diff --git a/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.h b/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.h
index 01fedff..f8350fd 100644
--- a/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.h
+++ b/components/keyed_service/content/refcounted_browser_context_keyed_service_factory.h
@@ -30,16 +30,6 @@
 class KEYED_SERVICE_EXPORT RefcountedBrowserContextKeyedServiceFactory
     : public RefcountedKeyedServiceFactory {
  public:
-  // Registers preferences used in this service on the pref service of
-  // |context|. This is the public interface and is safe to be called multiple
-  // times because testing code can have multiple services of the same type
-  // attached to a single |context|. Only test code is allowed to call this
-  // method.
-  // TODO(gab): This method can be removed entirely when
-  // PrefService::DeprecatedGetPrefRegistry() is phased out.
-  void RegisterUserPrefsOnBrowserContextForTest(
-      content::BrowserContext* context);
-
   // A function that supplies the instance of a KeyedService for a given
   // BrowserContext. This is used primarily for testing, where we want to feed
   // a specific mock into the BCKSF system.
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc
index 4c719fd..742e773d7 100644
--- a/components/nacl/browser/nacl_process_host.cc
+++ b/components/nacl/browser/nacl_process_host.cc
@@ -946,7 +946,10 @@
       DLOG(ERROR) << "Failed to allocate memory buffer";
       return false;
     }
-    base::ScopedFD memory_fd(dup(memory_buffer.handle().fd));
+    base::SharedMemoryHandle duped_handle =
+        base::SharedMemory::DuplicateHandle(memory_buffer.handle());
+    base::ScopedFD memory_fd(
+        base::SharedMemory::GetFdFromSharedMemoryHandle(duped_handle));
     if (!memory_fd.is_valid()) {
       DLOG(ERROR) << "Failed to dup() a file descriptor";
       return false;
diff --git a/components/nacl/loader/DEPS b/components/nacl/loader/DEPS
index 1b8ec2f..751e035 100644
--- a/components/nacl/loader/DEPS
+++ b/components/nacl/loader/DEPS
@@ -14,7 +14,8 @@
 
   "+native_client/src/include",
   "+native_client/src/public",
-  "+native_client/src/trusted/desc",
+  "+native_client/src/trusted/desc/nacl_desc_quota.h",
+  "+native_client/src/trusted/desc/nacl_desc_quota_interface.h",
   "+native_client/src/trusted/service_runtime/include",
   "+native_client/src/trusted/service_runtime/nacl_error_code.h",
   "+native_client/src/untrusted/irt/irt.h",
diff --git a/components/nacl/loader/nacl_ipc_adapter.cc b/components/nacl/loader/nacl_ipc_adapter.cc
index a9ea0b8d..f0b7658 100644
--- a/components/nacl/loader/nacl_ipc_adapter.cc
+++ b/components/nacl/loader/nacl_ipc_adapter.cc
@@ -19,12 +19,8 @@
 #include "ipc/ipc_platform_file.h"
 #include "native_client/src/public/nacl_desc.h"
 #include "native_client/src/public/nacl_desc_custom.h"
-#include "native_client/src/trusted/desc/nacl_desc_base.h"
-#include "native_client/src/trusted/desc/nacl_desc_imc_shm.h"
-#include "native_client/src/trusted/desc/nacl_desc_io.h"
 #include "native_client/src/trusted/desc/nacl_desc_quota.h"
 #include "native_client/src/trusted/desc/nacl_desc_quota_interface.h"
-#include "native_client/src/trusted/desc/nacl_desc_sync_socket.h"
 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
 #include "ppapi/c/ppb_file_io.h"
 #include "ppapi/proxy/ppapi_messages.h"
@@ -551,7 +547,7 @@
 #if defined(OS_WIN)
               shm_handle,
 #else
-              shm_handle.fd,
+              base::SharedMemory::GetFdFromSharedMemoryHandle(shm_handle),
 #endif
               static_cast<size_t>(size))));
           break;
@@ -569,7 +565,7 @@
         case ppapi::proxy::SerializedHandle::FILE: {
           // Create the NaClDesc for the file descriptor. If quota checking is
           // required, wrap it in a NaClDescQuota.
-          NaClDesc* desc = NaClDescIoDescFromHandleAllocCtor(
+          NaClDesc* desc = NaClDescIoMakeFromHandle(
 #if defined(OS_WIN)
               iter->descriptor(),
 #else
@@ -648,7 +644,7 @@
     scoped_ptr<IPC::Message> new_msg = CreateOpenResourceReply(orig_msg, sh);
 
     scoped_ptr<NaClDescWrapper> desc_wrapper(new NaClDescWrapper(
-        NaClDescIoDescFromHandleAllocCtor(
+        NaClDescIoMakeFromHandle(
 #if defined(OS_WIN)
             sh.descriptor(),
 #else
diff --git a/components/nacl/loader/nonsfi/DEPS b/components/nacl/loader/nonsfi/DEPS
index a7b6273f..dae642b 100644
--- a/components/nacl/loader/nonsfi/DEPS
+++ b/components/nacl/loader/nonsfi/DEPS
@@ -2,6 +2,8 @@
   "+ppapi/nacl_irt",
   "+sandbox/linux/seccomp-bpf-helpers",
   "+native_client/src/shared/platform/nacl_log.h",
+  "+native_client/src/trusted/desc/nacl_desc_base.h",
+  "+native_client/src/trusted/desc/nacl_desc_effector_trusted_mem.h",
   "+native_client/src/trusted/service_runtime/nacl_exception.h",
   "+native_client/src/trusted/service_runtime/nacl_signal.h",
   "+third_party/lss/linux_syscall_support.h",  # for BPF policy tests
diff --git a/components/nacl/loader/nonsfi/nonsfi_main.cc b/components/nacl/loader/nonsfi/nonsfi_main.cc
index 1b05d84..6781514a 100644
--- a/components/nacl/loader/nonsfi/nonsfi_main.cc
+++ b/components/nacl/loader/nonsfi/nonsfi_main.cc
@@ -17,8 +17,7 @@
 #include "components/nacl/loader/nonsfi/elf_loader.h"
 #include "components/nacl/loader/nonsfi/irt_interfaces.h"
 #include "native_client/src/include/nacl_macros.h"
-#include "native_client/src/trusted/desc/nacl_desc_base.h"
-#include "native_client/src/trusted/desc/nacl_desc_io.h"
+#include "native_client/src/public/nacl_desc.h"
 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
 #endif
 
@@ -83,7 +82,7 @@
       reinterpret_cast<EntryPointType>(NaClLoadElfFile(nexe_file));
 #else
   ::scoped_ptr<struct NaClDesc, NaClDescUnrefer> desc(
-       NaClDescIoDescFromDescAllocCtor(nexe_file, NACL_ABI_O_RDONLY));
+       NaClDescIoMakeFromHandle(nexe_file, NACL_ABI_O_RDONLY));
   ElfImage image;
   if (image.Read(desc.get()) != LOAD_OK) {
     LOG(ERROR) << "LoadModuleRpc: Failed to read binary.";
diff --git a/components/nacl/renderer/plugin/DEPS b/components/nacl/renderer/plugin/DEPS
index c98ba470..f24d4b8 100644
--- a/components/nacl/renderer/plugin/DEPS
+++ b/components/nacl/renderer/plugin/DEPS
@@ -4,7 +4,8 @@
   "+native_client/src/shared/imc/nacl_imc_c.h",
   "+native_client/src/shared/platform",
   "+native_client/src/shared/srpc",
-  "+native_client/src/trusted/desc",
+  "+native_client/src/trusted/desc/nacl_desc_wrapper.h",
+  "+native_client/src/trusted/desc/nrd_all_modules.h",
   "+native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h",
   "+native_client/src/trusted/service_runtime/include",
   "+native_client/src/trusted/service_runtime/nacl_error_code.h",
diff --git a/components/omnibox/base_search_provider.cc b/components/omnibox/base_search_provider.cc
index e0b6614..bb2db75 100644
--- a/components/omnibox/base_search_provider.cc
+++ b/components/omnibox/base_search_provider.cc
@@ -286,9 +286,10 @@
   if (!OmniboxFieldTrial::InZeroSuggestFieldTrial())
     return false;
 
-  // Make sure we are sending the suggest request through HTTPS to prevent
-  // exposing the current page URL or personalized results without encryption.
-  if (!suggest_url.SchemeIs(url::kHttpsScheme))
+  // Make sure we are sending the suggest request through a cryptographically
+  // secure channel to prevent exposing the current page URL or personalized
+  // results without encryption.
+  if (!suggest_url.SchemeIsCryptographic())
     return false;
 
   // Don't show zero suggest on the NTP.
diff --git a/components/proximity_auth/ble/BUILD.gn b/components/proximity_auth/ble/BUILD.gn
index 64fcef0..924d9c1d 100644
--- a/components/proximity_auth/ble/BUILD.gn
+++ b/components/proximity_auth/ble/BUILD.gn
@@ -32,6 +32,7 @@
   sources = [
     "bluetooth_low_energy_characteristics_finder_unittest.cc",
     "bluetooth_low_energy_connection_finder_unittest.cc",
+    "bluetooth_low_energy_connection_unittest.cc",
     "proximity_auth_ble_system_unittest.cc",
   ]
 
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.cc b/components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.cc
index 85f6a84..d0c2f9b 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.cc
+++ b/components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.cc
@@ -45,6 +45,10 @@
 }
 
 BluetoothLowEnergyCharacteristicsFinder::
+    BluetoothLowEnergyCharacteristicsFinder() {
+}
+
+BluetoothLowEnergyCharacteristicsFinder::
     ~BluetoothLowEnergyCharacteristicsFinder() {
   ResetCallbacks();
   if (adapter_) {
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h b/components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h
index da1a7bba..9c95eeb 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h
+++ b/components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h
@@ -68,6 +68,9 @@
       device::BluetoothAdapter* adapter,
       device::BluetoothGattCharacteristic* characteristic) override;
 
+  // For testing. Used to mock this class.
+  BluetoothLowEnergyCharacteristicsFinder();
+
  private:
   // Handles the discovery of a new characteristic.
   void HandleCharacteristicUpdate(
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_connection.cc b/components/proximity_auth/ble/bluetooth_low_energy_connection.cc
index 54ca0333..d5d7860 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_connection.cc
+++ b/components/proximity_auth/ble/bluetooth_low_energy_connection.cc
@@ -45,6 +45,7 @@
       remote_service_({remote_service_uuid, ""}),
       to_peripheral_char_({to_peripheral_char_uuid, ""}),
       from_peripheral_char_({from_peripheral_char_uuid, ""}),
+      connection_(gatt_connection.Pass()),
       sub_status_(SubStatus::DISCONNECTED),
       receiving_bytes_(false),
       write_remote_characteristic_pending_(false),
@@ -55,9 +56,6 @@
 
   start_time_ = base::TimeTicks::Now();
   adapter_->AddObserver(this);
-
-  if (gatt_connection && gatt_connection->IsConnected())
-    OnGattConnectionCreated(gatt_connection.Pass());
 }
 
 BluetoothLowEnergyConnection::~BluetoothLowEnergyConnection() {
@@ -69,6 +67,11 @@
 }
 
 void BluetoothLowEnergyConnection::Connect() {
+  if (connection_ && connection_->IsConnected()) {
+    OnGattConnectionCreated(connection_.Pass());
+    return;
+  }
+
   BluetoothDevice* remote_device = GetRemoteDevice();
   if (remote_device) {
     SetSubStatus(SubStatus::WAITING_GATT_CONNECTION);
@@ -84,15 +87,17 @@
 // connect to BLE devices advertising the SmartLock service (assuming this
 // device has no other connection).
 void BluetoothLowEnergyConnection::Disconnect() {
-  ClearWriteRequestsQueue();
-  StopNotifySession();
-  SetSubStatus(SubStatus::DISCONNECTED);
-  if (connection_) {
-    connection_.reset();
-    BluetoothDevice* device = GetRemoteDevice();
-    if (device) {
-      VLOG(1) << "Forget device " << device->GetAddress();
-      device->Forget(base::Bind(&base::DoNothing));
+  if (sub_status_ != SubStatus::DISCONNECTED) {
+    ClearWriteRequestsQueue();
+    StopNotifySession();
+    SetSubStatus(SubStatus::DISCONNECTED);
+    if (connection_) {
+      connection_.reset();
+      BluetoothDevice* device = GetRemoteDevice();
+      if (device) {
+        VLOG(1) << "Forget device " << device->GetAddress();
+        device->Forget(base::Bind(&base::DoNothing));
+      }
     }
   }
 }
@@ -213,16 +218,22 @@
     scoped_ptr<device::BluetoothGattConnection> gatt_connection) {
   connection_ = gatt_connection.Pass();
   SetSubStatus(SubStatus::WAITING_CHARACTERISTICS);
+  characteristic_finder_.reset(CreateCharacteristicsFinder(
+      base::Bind(&BluetoothLowEnergyConnection::OnCharacteristicsFound,
+                 weak_ptr_factory_.GetWeakPtr()),
+      base::Bind(&BluetoothLowEnergyConnection::OnCharacteristicsFinderError,
+                 weak_ptr_factory_.GetWeakPtr())));
+}
 
-  characteristic_finder_ =
-      make_scoped_ptr(new BluetoothLowEnergyCharacteristicsFinder(
-          adapter_, GetRemoteDevice(), remote_service_, to_peripheral_char_,
-          from_peripheral_char_,
-          base::Bind(&BluetoothLowEnergyConnection::OnCharacteristicsFound,
-                     weak_ptr_factory_.GetWeakPtr()),
-          base::Bind(
-              &BluetoothLowEnergyConnection::OnCharacteristicsFinderError,
-              weak_ptr_factory_.GetWeakPtr())));
+BluetoothLowEnergyCharacteristicsFinder*
+BluetoothLowEnergyConnection::CreateCharacteristicsFinder(
+    const BluetoothLowEnergyCharacteristicsFinder::SuccessCallback&
+        success_callback,
+    const BluetoothLowEnergyCharacteristicsFinder::ErrorCallback&
+        error_callback) {
+  return new BluetoothLowEnergyCharacteristicsFinder(
+      adapter_, GetRemoteDevice(), remote_service_, to_peripheral_char_,
+      from_peripheral_char_, success_callback, error_callback);
 }
 
 void BluetoothLowEnergyConnection::OnCharacteristicsFound(
@@ -355,7 +366,7 @@
 
   // Increases the number of failed attempts and retry.
   DCHECK(!write_requests_queue_.empty());
-  if (write_requests_queue_.front().number_of_failed_attempts++ >=
+  if (++write_requests_queue_.front().number_of_failed_attempts >=
       max_number_of_write_attempts_) {
     Disconnect();
     return;
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_connection.h b/components/proximity_auth/ble/bluetooth_low_energy_connection.h
index c2f88eb..41ff414 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_connection.h
+++ b/components/proximity_auth/ble/bluetooth_low_energy_connection.h
@@ -59,11 +59,25 @@
     kDisconnectSignal = 3,
   };
 
+  // The sub-state of a proximity_auth::BluetoothLowEnergyConnection class
+  // extends the IN_PROGRESS state of proximity_auth::Connection::Status.
+  enum class SubStatus {
+    DISCONNECTED,
+    WAITING_GATT_CONNECTION,
+    GATT_CONNECTION_ESTABLISHED,
+    WAITING_CHARACTERISTICS,
+    CHARACTERISTICS_FOUND,
+    WAITING_NOTIFY_SESSION,
+    NOTIFY_SESSION_READY,
+    WAITING_RESPONSE_SIGNAL,
+    CONNECTED,
+  };
+
   // Constructs a Bluetooth low energy connection to the service with
   // |remote_service_| on the |remote_device|. The |adapter| must be already
   // initaalized and ready. The GATT connection may alreaady be established and
-  // pass through |gatt_connection|. If |gatt_connection| is NULL, a subsequent
-  // call to Connect() must be made.
+  // pass through |gatt_connection|. A subsequent call to Connect() must be
+  // made.
   BluetoothLowEnergyConnection(
       const RemoteDevice& remote_device,
       scoped_refptr<device::BluetoothAdapter> adapter,
@@ -80,23 +94,17 @@
   void Disconnect() override;
 
  protected:
-  // The sub-state of a proximity_auth::BluetoothLowEnergyConnection class
-  // extends the IN_PROGRESS state of proximity_auth::Connection::Status.
-  enum class SubStatus {
-    DISCONNECTED,
-    WAITING_GATT_CONNECTION,
-    GATT_CONNECTION_ESTABLISHED,
-    WAITING_CHARACTERISTICS,
-    CHARACTERISTICS_FOUND,
-    WAITING_NOTIFY_SESSION,
-    NOTIFY_SESSION_READY,
-    WAITING_RESPONSE_SIGNAL,
-    CONNECTED,
-  };
-
+  // Exposed for testing.
   void SetSubStatus(SubStatus status);
   SubStatus sub_status() { return sub_status_; }
 
+  // Virtual for testing.
+  virtual BluetoothLowEnergyCharacteristicsFinder* CreateCharacteristicsFinder(
+      const BluetoothLowEnergyCharacteristicsFinder::SuccessCallback&
+          success_callback,
+      const BluetoothLowEnergyCharacteristicsFinder::ErrorCallback&
+          error_callback);
+
   // proximity_auth::Connection
   void SendMessageImpl(scoped_ptr<WireMessage> message) override;
   scoped_ptr<WireMessage> DeserializeWireMessage(
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_connection_finder.cc b/components/proximity_auth/ble/bluetooth_low_energy_connection_finder.cc
index d73629a4..7b05947 100644
--- a/components/proximity_auth/ble/bluetooth_low_energy_connection_finder.cc
+++ b/components/proximity_auth/ble/bluetooth_low_energy_connection_finder.cc
@@ -223,6 +223,7 @@
 
   connection_ = CreateConnection(gatt_connection.Pass());
   connection_->AddObserver(this);
+  connection_->Connect();
 
   StopDiscoverySession();
 }
diff --git a/components/proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc b/components/proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc
new file mode 100644
index 0000000..b989a35
--- /dev/null
+++ b/components/proximity_auth/ble/bluetooth_low_energy_connection_unittest.cc
@@ -0,0 +1,510 @@
+// 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/proximity_auth/ble/bluetooth_low_energy_connection.h"
+
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "components/proximity_auth/ble/bluetooth_low_energy_characteristics_finder.h"
+#include "components/proximity_auth/connection_finder.h"
+#include "components/proximity_auth/remote_device.h"
+#include "components/proximity_auth/wire_message.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/bluetooth/bluetooth_gatt_characteristic.h"
+#include "device/bluetooth/bluetooth_uuid.h"
+#include "device/bluetooth/test/mock_bluetooth_adapter.h"
+#include "device/bluetooth/test/mock_bluetooth_device.h"
+#include "device/bluetooth/test/mock_bluetooth_discovery_session.h"
+#include "device/bluetooth/test/mock_bluetooth_gatt_characteristic.h"
+#include "device/bluetooth/test/mock_bluetooth_gatt_connection.h"
+#include "device/bluetooth/test/mock_bluetooth_gatt_notify_session.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::AtLeast;
+using testing::NiceMock;
+using testing::Return;
+using testing::StrictMock;
+using testing::SaveArg;
+
+namespace proximity_auth {
+namespace {
+
+const char kDeviceName[] = "Device name";
+const char kBluetoothAddress[] = "11:22:33:44:55:66";
+
+const char kServiceUUID[] = "DEADBEEF-CAFE-FEED-FOOD-D15EA5EBEEEF";
+const char kToPeripheralCharUUID[] = "FBAE09F2-0482-11E5-8418-1697F925EC7B";
+const char kFromPeripheralCharUUID[] = "5539ED10-0483-11E5-8418-1697F925EC7B";
+
+const char kServiceID[] = "service id";
+const char kToPeripheralCharID[] = "to peripheral char id";
+const char kFromPeripheralCharID[] = "from peripheral char id";
+
+const device::BluetoothGattCharacteristic::Properties
+    kCharacteristicProperties =
+        device::BluetoothGattCharacteristic::PROPERTY_BROADCAST |
+        device::BluetoothGattCharacteristic::PROPERTY_READ |
+        device::BluetoothGattCharacteristic::PROPERTY_WRITE_WITHOUT_RESPONSE |
+        device::BluetoothGattCharacteristic::PROPERTY_INDICATE;
+
+const int kMaxNumberOfTries = 3;
+
+class MockBluetoothLowEnergyCharacteristicsFinder
+    : public BluetoothLowEnergyCharacteristicsFinder {
+ public:
+  MockBluetoothLowEnergyCharacteristicsFinder() {}
+  ~MockBluetoothLowEnergyCharacteristicsFinder() override {}
+};
+
+class MockBluetoothLowEnergyConnection : public BluetoothLowEnergyConnection {
+ public:
+  MockBluetoothLowEnergyConnection(
+      const RemoteDevice& remote_device,
+      scoped_refptr<device::BluetoothAdapter> adapter,
+      const device::BluetoothUUID remote_service_uuid,
+      const device::BluetoothUUID to_peripheral_char_uuid,
+      const device::BluetoothUUID from_peripheral_char_uuid,
+      scoped_ptr<device::BluetoothGattConnection> gatt_connection,
+      int max_number_of_write_attempts)
+      : BluetoothLowEnergyConnection(remote_device,
+                                     adapter,
+                                     remote_service_uuid,
+                                     to_peripheral_char_uuid,
+                                     from_peripheral_char_uuid,
+                                     gatt_connection.Pass(),
+                                     max_number_of_write_attempts) {}
+
+  ~MockBluetoothLowEnergyConnection() override {}
+
+  MOCK_METHOD2(
+      CreateCharacteristicsFinder,
+      BluetoothLowEnergyCharacteristicsFinder*(
+          const BluetoothLowEnergyCharacteristicsFinder::SuccessCallback&
+              success,
+          const BluetoothLowEnergyCharacteristicsFinder::ErrorCallback& error));
+
+  MOCK_METHOD2(OnDidSendMessage,
+               void(const WireMessage& message, bool success));
+
+  // Exposing inherited protected methods for testing.
+  using BluetoothLowEnergyConnection::GattCharacteristicValueChanged;
+
+  // Exposing inherited protected fields for testing.
+  using BluetoothLowEnergyConnection::status;
+  using BluetoothLowEnergyConnection::sub_status;
+};
+
+}  // namespace
+
+class ProximityAuthBluetoothLowEnergyConnectionTest : public testing::Test {
+ public:
+  ProximityAuthBluetoothLowEnergyConnectionTest()
+      : adapter_(new NiceMock<device::MockBluetoothAdapter>),
+        remote_device_({kDeviceName, kBluetoothAddress}),
+        service_uuid_(device::BluetoothUUID(kServiceUUID)),
+        to_peripheral_char_uuid_(device::BluetoothUUID(kToPeripheralCharUUID)),
+        from_peripheral_char_uuid_(
+            device::BluetoothUUID(kFromPeripheralCharUUID)),
+        gatt_connection_(new NiceMock<device::MockBluetoothGattConnection>(
+            kBluetoothAddress)),
+        gatt_connection_alias_(gatt_connection_.get()),
+        notify_session_alias_(NULL) {}
+
+  void SetUp() override {
+    device_ = make_scoped_ptr(new NiceMock<device::MockBluetoothDevice>(
+        adapter_.get(), 0, kDeviceName, kBluetoothAddress, false, false));
+
+    service_ = make_scoped_ptr(new NiceMock<device::MockBluetoothGattService>(
+        device_.get(), kServiceID, service_uuid_, true, false));
+    to_peripheral_char_ =
+        make_scoped_ptr(new NiceMock<device::MockBluetoothGattCharacteristic>(
+            service_.get(), kToPeripheralCharID, to_peripheral_char_uuid_,
+            false, kCharacteristicProperties,
+            device::BluetoothGattCharacteristic::PERMISSION_NONE));
+
+    from_peripheral_char_ =
+        make_scoped_ptr(new NiceMock<device::MockBluetoothGattCharacteristic>(
+            service_.get(), kFromPeripheralCharID, from_peripheral_char_uuid_,
+            false, kCharacteristicProperties,
+            device::BluetoothGattCharacteristic::PERMISSION_NONE));
+
+    device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
+
+    ON_CALL(*adapter_, GetDevice(kBluetoothAddress))
+        .WillByDefault(Return(device_.get()));
+    ON_CALL(*device_, GetGattService(kServiceID))
+        .WillByDefault(Return(service_.get()));
+    ON_CALL(*service_, GetCharacteristic(kFromPeripheralCharID))
+        .WillByDefault(Return(from_peripheral_char_.get()));
+    ON_CALL(*service_, GetCharacteristic(kToPeripheralCharID))
+        .WillByDefault(Return(to_peripheral_char_.get()));
+  }
+
+  // Creates a BluetoothLowEnergyConnection and verifies it's in DISCONNECTED
+  // state.
+  scoped_ptr<MockBluetoothLowEnergyConnection> CreateConnection() {
+    EXPECT_CALL(*adapter_, AddObserver(_));
+    EXPECT_CALL(*adapter_, RemoveObserver(_));
+
+    scoped_ptr<MockBluetoothLowEnergyConnection> connection(
+        new MockBluetoothLowEnergyConnection(
+            remote_device_, adapter_, service_uuid_, to_peripheral_char_uuid_,
+            from_peripheral_char_uuid_, gatt_connection_.Pass(),
+            kMaxNumberOfTries));
+
+    EXPECT_EQ(connection->sub_status(),
+              BluetoothLowEnergyConnection::SubStatus::DISCONNECTED);
+    EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+
+    return connection.Pass();
+  }
+
+  // Transitions |connection| from DISCONNECTED to WAITING_CHARACTERISTICS
+  // state, using an existing GATT connection.
+  void ConnectWithExistingGattConnection(
+      MockBluetoothLowEnergyConnection* connection) {
+    EXPECT_CALL(*gatt_connection_alias_, IsConnected()).WillOnce(Return(true));
+    EXPECT_CALL(*connection, CreateCharacteristicsFinder(_, _))
+        .WillOnce(
+            DoAll(SaveArg<0>(&characteristics_finder_success_callback_),
+                  SaveArg<1>(&characteristics_finder_error_callback_),
+                  Return(new MockBluetoothLowEnergyCharacteristicsFinder)));
+
+    connection->Connect();
+
+    EXPECT_EQ(connection->sub_status(),
+              BluetoothLowEnergyConnection::SubStatus::WAITING_CHARACTERISTICS);
+    EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+  }
+
+  // Transitions |connection| from DISCONNECTED to WAITING_CHARACTERISTICS
+  // state, without an existing GATT connection.
+  void ConnectWithoutExistingGattConnection(
+      MockBluetoothLowEnergyConnection* connection) {
+    // Preparing |connection| for a CreateGattConnection call.
+    EXPECT_CALL(*gatt_connection_alias_, IsConnected()).WillOnce(Return(false));
+    EXPECT_CALL(*device_, CreateGattConnection(_, _))
+        .WillOnce(DoAll(SaveArg<0>(&create_gatt_connection_success_callback_),
+                        SaveArg<1>(&create_gatt_connection_error_callback_)));
+
+    connection->Connect();
+
+    EXPECT_EQ(connection->sub_status(),
+              BluetoothLowEnergyConnection::SubStatus::WAITING_GATT_CONNECTION);
+    EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+
+    // Preparing |connection| to run |create_gatt_connection_success_callback_|.
+    EXPECT_FALSE(create_gatt_connection_error_callback_.is_null());
+    ASSERT_FALSE(create_gatt_connection_success_callback_.is_null());
+    EXPECT_CALL(*connection, CreateCharacteristicsFinder(_, _))
+        .WillOnce(DoAll(
+            SaveArg<0>(&characteristics_finder_success_callback_),
+            SaveArg<1>(&characteristics_finder_error_callback_),
+            Return(new NiceMock<MockBluetoothLowEnergyCharacteristicsFinder>)));
+
+    create_gatt_connection_success_callback_.Run(make_scoped_ptr(
+        new NiceMock<device::MockBluetoothGattConnection>(kBluetoothAddress)));
+
+    EXPECT_EQ(connection->sub_status(),
+              BluetoothLowEnergyConnection::SubStatus::WAITING_CHARACTERISTICS);
+    EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+  }
+
+  // Transitions |connection| from WAITING_CHARACTERISTICS to
+  // WAITING_NOTIFY_SESSION state.
+  void CharacteristicsFound(MockBluetoothLowEnergyConnection* connection) {
+    EXPECT_CALL(*from_peripheral_char_, StartNotifySession(_, _))
+        .WillOnce(DoAll(SaveArg<0>(&notify_session_success_callback_),
+                        SaveArg<1>(&notify_session_error_callback_)));
+    EXPECT_FALSE(characteristics_finder_error_callback_.is_null());
+    ASSERT_FALSE(characteristics_finder_success_callback_.is_null());
+
+    characteristics_finder_success_callback_.Run(
+        {service_uuid_, kServiceID},
+        {to_peripheral_char_uuid_, kToPeripheralCharID},
+        {from_peripheral_char_uuid_, kFromPeripheralCharID});
+
+    EXPECT_EQ(connection->sub_status(),
+              BluetoothLowEnergyConnection::SubStatus::WAITING_NOTIFY_SESSION);
+    EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+  }
+
+  // Transitions |connection| from WAITING_NOTIFY_SESSION to
+  // WAITING_RESPONSE_SIGNAL state.
+  void NotifySessionStarted(MockBluetoothLowEnergyConnection* connection) {
+    EXPECT_CALL(*to_peripheral_char_, WriteRemoteCharacteristic(_, _, _))
+        .WillOnce(
+            DoAll(SaveArg<0>(&last_value_written_on_to_peripheral_char_),
+                  SaveArg<1>(&write_remote_characteristic_success_callback_),
+                  SaveArg<2>(&write_remote_characteristic_error_callback_)));
+    EXPECT_FALSE(notify_session_error_callback_.is_null());
+    ASSERT_FALSE(notify_session_success_callback_.is_null());
+
+    // Store an alias for the notify session passed |connection|.
+    scoped_ptr<device::MockBluetoothGattNotifySession> notify_session(
+        new NiceMock<device::MockBluetoothGattNotifySession>(
+            kToPeripheralCharID));
+    notify_session_alias_ = notify_session.get();
+    notify_session_success_callback_.Run(notify_session.Pass());
+
+    EXPECT_EQ(connection->sub_status(),
+              BluetoothLowEnergyConnection::SubStatus::WAITING_RESPONSE_SIGNAL);
+    EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+  }
+
+  // Transitions |connection| from WAITING_RESPONSE_SIGNAL to CONNECTED state.
+  void ResponseSignalReceived(MockBluetoothLowEnergyConnection* connection) {
+    // Written value contains only the
+    // BluetoothLowEneryConnection::ControlSignal::kInviteToConnectSignal.
+    const std::vector<uint8> kInviteToConnectSignal = ToByteVector(static_cast<
+        uint32>(
+        BluetoothLowEnergyConnection::ControlSignal::kInviteToConnectSignal));
+    EXPECT_EQ(last_value_written_on_to_peripheral_char_,
+              kInviteToConnectSignal);
+
+    EXPECT_CALL(*connection, OnDidSendMessage(_, _)).Times(0);
+    EXPECT_FALSE(write_remote_characteristic_error_callback_.is_null());
+    ASSERT_FALSE(write_remote_characteristic_success_callback_.is_null());
+    write_remote_characteristic_success_callback_.Run();
+
+    // Received the
+    // BluetoothLowEneryConnection::ControlSignal::kInvitationResponseSignal.
+    const std::vector<uint8> kInvitationResponseSignal = ToByteVector(
+        static_cast<uint32>(BluetoothLowEnergyConnection::ControlSignal::
+                                kInvitationResponseSignal));
+    connection->GattCharacteristicValueChanged(
+        adapter_.get(), from_peripheral_char_.get(), kInvitationResponseSignal);
+
+    EXPECT_EQ(connection->sub_status(),
+              BluetoothLowEnergyConnection::SubStatus::CONNECTED);
+    EXPECT_EQ(connection->status(), Connection::CONNECTED);
+  }
+
+  // Transitions |connection| to a DISCONNECTED state regardless of its initial
+  // state.
+  void Disconnect(MockBluetoothLowEnergyConnection* connection) {
+    // A notify session was previously set.
+    if (notify_session_alias_)
+      EXPECT_CALL(*notify_session_alias_, Stop(_));
+
+    connection->Disconnect();
+
+    EXPECT_EQ(connection->sub_status(),
+              BluetoothLowEnergyConnection::SubStatus::DISCONNECTED);
+    EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+  }
+
+  std::vector<uint8> ToByteVector(uint32 value) {
+    std::vector<uint8> bytes(4, 0);
+    bytes[0] = static_cast<uint8>(value);
+    bytes[1] = static_cast<uint8>(value >> 8);
+    bytes[2] = static_cast<uint8>(value >> 16);
+    bytes[3] = static_cast<uint8>(value >> 24);
+    return bytes;
+  }
+
+ protected:
+  scoped_refptr<device::MockBluetoothAdapter> adapter_;
+  RemoteDevice remote_device_;
+  device::BluetoothUUID service_uuid_;
+  device::BluetoothUUID to_peripheral_char_uuid_;
+  device::BluetoothUUID from_peripheral_char_uuid_;
+  scoped_ptr<device::MockBluetoothGattConnection> gatt_connection_;
+  device::MockBluetoothGattConnection* gatt_connection_alias_;
+  scoped_ptr<device::MockBluetoothDevice> device_;
+  scoped_ptr<device::MockBluetoothGattService> service_;
+  scoped_ptr<device::MockBluetoothGattCharacteristic> to_peripheral_char_;
+  scoped_ptr<device::MockBluetoothGattCharacteristic> from_peripheral_char_;
+  std::vector<uint8> last_value_written_on_to_peripheral_char_;
+  device::MockBluetoothGattNotifySession* notify_session_alias_;
+
+  // Callbacks
+  device::BluetoothDevice::GattConnectionCallback
+      create_gatt_connection_success_callback_;
+  device::BluetoothDevice::ConnectErrorCallback
+      create_gatt_connection_error_callback_;
+
+  BluetoothLowEnergyCharacteristicsFinder::SuccessCallback
+      characteristics_finder_success_callback_;
+  BluetoothLowEnergyCharacteristicsFinder::ErrorCallback
+      characteristics_finder_error_callback_;
+
+  device::BluetoothGattCharacteristic::NotifySessionCallback
+      notify_session_success_callback_;
+  device::BluetoothGattCharacteristic::ErrorCallback
+      notify_session_error_callback_;
+
+  base::Closure write_remote_characteristic_success_callback_;
+  device::BluetoothGattCharacteristic::ErrorCallback
+      write_remote_characteristic_error_callback_;
+};
+
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       CreateAndDestroyWithouthConnectCallDoesntCrash) {
+  BluetoothLowEnergyConnection connection(
+      remote_device_, adapter_, service_uuid_, to_peripheral_char_uuid_,
+      from_peripheral_char_uuid_, gatt_connection_.Pass(), kMaxNumberOfTries);
+}
+
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       Disconect_WithoutConnectDoesntCrash) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  Disconnect(connection.get());
+}
+
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       Connect_Success_WithGattConnection) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  ConnectWithExistingGattConnection(connection.get());
+  CharacteristicsFound(connection.get());
+  NotifySessionStarted(connection.get());
+  ResponseSignalReceived(connection.get());
+}
+
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       Connect_Success_WithoutGattConnection) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  ConnectWithoutExistingGattConnection(connection.get());
+  CharacteristicsFound(connection.get());
+  NotifySessionStarted(connection.get());
+  ResponseSignalReceived(connection.get());
+}
+
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       Connect_Success_Disconnect) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  ConnectWithExistingGattConnection(connection.get());
+  CharacteristicsFound(connection.get());
+  NotifySessionStarted(connection.get());
+  ResponseSignalReceived(connection.get());
+  Disconnect(connection.get());
+}
+
+TEST_F(
+    ProximityAuthBluetoothLowEnergyConnectionTest,
+    Connect_Incomplete_Disconnect_FromWaitingCharacteristicsStateWithoutExistingGattConnection) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  ConnectWithoutExistingGattConnection(connection.get());
+  Disconnect(connection.get());
+}
+
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       Connect_Incomplete_Disconnect_FromWaitingCharacteristicsState) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  ConnectWithExistingGattConnection(connection.get());
+  Disconnect(connection.get());
+}
+
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       Connect_Incomplete_Disconnect_FromWaitingNotifySessionState) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  ConnectWithExistingGattConnection(connection.get());
+  CharacteristicsFound(connection.get());
+  Disconnect(connection.get());
+}
+
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       Connect_Incomplete_Disconnect_FromWaitingResponseSignalState) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  ConnectWithExistingGattConnection(connection.get());
+  CharacteristicsFound(connection.get());
+  NotifySessionStarted(connection.get());
+  Disconnect(connection.get());
+}
+
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       Connect_Fails_CharacteristicsNotFound) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  ConnectWithExistingGattConnection(connection.get());
+
+  EXPECT_CALL(*from_peripheral_char_, StartNotifySession(_, _)).Times(0);
+  EXPECT_FALSE(characteristics_finder_success_callback_.is_null());
+  ASSERT_FALSE(characteristics_finder_error_callback_.is_null());
+
+  characteristics_finder_error_callback_.Run(
+      {to_peripheral_char_uuid_, kToPeripheralCharID},
+      {from_peripheral_char_uuid_, kFromPeripheralCharID});
+
+  EXPECT_EQ(connection->sub_status(),
+            BluetoothLowEnergyConnection::SubStatus::DISCONNECTED);
+  EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+}
+
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       Connect_Fails_NotifySessionError) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  ConnectWithExistingGattConnection(connection.get());
+  CharacteristicsFound(connection.get());
+
+  EXPECT_CALL(*to_peripheral_char_, WriteRemoteCharacteristic(_, _, _))
+      .Times(0);
+  EXPECT_FALSE(notify_session_success_callback_.is_null());
+  ASSERT_FALSE(notify_session_error_callback_.is_null());
+
+  notify_session_error_callback_.Run(
+      device::BluetoothGattService::GATT_ERROR_UNKNOWN);
+
+  EXPECT_EQ(connection->sub_status(),
+            BluetoothLowEnergyConnection::SubStatus::DISCONNECTED);
+  EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+}
+
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       Connect_Fails_ErrorSendingInviteToConnectSignal) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  ConnectWithExistingGattConnection(connection.get());
+  CharacteristicsFound(connection.get());
+  NotifySessionStarted(connection.get());
+
+  // |connection| will call WriteRemoteCharacteristics(_,_) to try to send the
+  // message |kMaxNumberOfTries| times. There is alredy one EXPECTA_CALL for
+  // WriteRemoteCharacteristic(_,_,_) in NotifySessionStated, that's why we use
+  // |kMaxNumberOfTries-1| in the EXPECT_CALL statement.
+  EXPECT_CALL(*connection, OnDidSendMessage(_, _)).Times(0);
+  EXPECT_CALL(*to_peripheral_char_, WriteRemoteCharacteristic(_, _, _))
+      .Times(kMaxNumberOfTries - 1)
+      .WillRepeatedly(
+          DoAll(SaveArg<0>(&last_value_written_on_to_peripheral_char_),
+                SaveArg<1>(&write_remote_characteristic_success_callback_),
+                SaveArg<2>(&write_remote_characteristic_error_callback_)));
+
+  for (int i = 0; i < kMaxNumberOfTries; i++) {
+    const std::vector<uint8> kInviteToConnectSignal = ToByteVector(static_cast<
+        uint32>(
+        BluetoothLowEnergyConnection::ControlSignal::kInviteToConnectSignal));
+    EXPECT_EQ(last_value_written_on_to_peripheral_char_,
+              kInviteToConnectSignal);
+    ASSERT_FALSE(write_remote_characteristic_error_callback_.is_null());
+    EXPECT_FALSE(write_remote_characteristic_success_callback_.is_null());
+    write_remote_characteristic_error_callback_.Run(
+        device::BluetoothGattService::GATT_ERROR_UNKNOWN);
+  }
+
+  EXPECT_EQ(connection->sub_status(),
+            BluetoothLowEnergyConnection::SubStatus::DISCONNECTED);
+  EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+}
+
+TEST_F(ProximityAuthBluetoothLowEnergyConnectionTest,
+       Connect_Fails_CharacteristicsNotFound_WithoutExistingGattConnection) {
+  scoped_ptr<MockBluetoothLowEnergyConnection> connection(CreateConnection());
+  ConnectWithoutExistingGattConnection(connection.get());
+
+  EXPECT_CALL(*from_peripheral_char_, StartNotifySession(_, _)).Times(0);
+  EXPECT_FALSE(characteristics_finder_success_callback_.is_null());
+  ASSERT_FALSE(characteristics_finder_error_callback_.is_null());
+
+  characteristics_finder_error_callback_.Run(
+      {to_peripheral_char_uuid_, kToPeripheralCharID},
+      {from_peripheral_char_uuid_, kFromPeripheralCharID});
+
+  EXPECT_EQ(connection->sub_status(),
+            BluetoothLowEnergyConnection::SubStatus::DISCONNECTED);
+  EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+}
+
+}  // namespace proximity_auth
diff --git a/components/scheduler/BUILD.gn b/components/scheduler/BUILD.gn
index f55b542f..587516f3 100644
--- a/components/scheduler/BUILD.gn
+++ b/components/scheduler/BUILD.gn
@@ -60,3 +60,14 @@
     "//testing/gtest",
   ]
 }
+
+# GYP version: components/scheduler.gypi:scheduler_test_support
+static_library("test_support") {
+  sources = rebase_path(scheduler_gypi_values.scheduler_test_support_sources,
+                        ".",
+                        "//components/scheduler")
+
+  deps = [
+    "//base",
+  ]
+}
diff --git a/components/scheduler/child/idle_helper.cc b/components/scheduler/child/idle_helper.cc
index 43ed9e42..756fc1b8 100644
--- a/components/scheduler/child/idle_helper.cc
+++ b/components/scheduler/child/idle_helper.cc
@@ -252,9 +252,13 @@
       next_long_idle_period_delay = std::max(
           base::TimeDelta(), state_.idle_period_deadline() - helper_->Now());
     }
-    helper_->ControlTaskRunner()->PostDelayedTask(
-        FROM_HERE, enable_next_long_idle_period_closure_.callback(),
-        next_long_idle_period_delay);
+    if (next_long_idle_period_delay == base::TimeDelta()) {
+      EnableLongIdlePeriod();
+    } else {
+      helper_->ControlTaskRunner()->PostDelayedTask(
+          FROM_HERE, enable_next_long_idle_period_closure_.callback(),
+          next_long_idle_period_delay);
+    }
   }
 }
 
diff --git a/components/scheduler/child/idle_helper_unittest.cc b/components/scheduler/child/idle_helper_unittest.cc
index d89653e..1f93354 100644
--- a/components/scheduler/child/idle_helper_unittest.cc
+++ b/components/scheduler/child/idle_helper_unittest.cc
@@ -771,33 +771,28 @@
 }
 
 TEST_F(IdleHelperTest, TestLongIdlePeriodImmediatelyRestartsIfMaxDeadline) {
-  base::TimeTicks actual_deadline;
+  std::vector<base::TimeTicks> actual_deadlines;
   int run_count = 0;
 
-  base::TimeDelta idle_task_duration(base::TimeDelta::FromMilliseconds(10));
-  base::TimeTicks expected_deadline_1(clock_->Now() +
-                                      maximum_idle_period_duration());
-  base::TimeTicks expected_deadline_2(clock_->Now() + idle_task_duration +
-                                      maximum_idle_period_duration());
+  base::TimeTicks clock_before(clock_->Now());
+  base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10));
 
   // The second idle period should happen immediately after the first the
   // they have max deadlines.
   max_idle_task_reposts = 2;
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&RepostingIdleTestTask, idle_task_runner_,
-                            &run_count, &actual_deadline));
-  idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(UpdateClockIdleTestTask, clock_, &run_count,
-                            clock_->Now() + idle_task_duration));
+      FROM_HERE,
+      base::Bind(&RepostingUpdateClockIdleTestTask, idle_task_runner_,
+                 &run_count, clock_, idle_task_runtime, &actual_deadlines));
 
   idle_helper_->EnableLongIdlePeriod();
   RunUntilIdle();
   EXPECT_EQ(2, run_count);
-  EXPECT_EQ(expected_deadline_1, actual_deadline);
-
-  RunUntilIdle();
-  EXPECT_EQ(3, run_count);
-  EXPECT_EQ(expected_deadline_2, actual_deadline);
+  EXPECT_THAT(
+      actual_deadlines,
+      testing::ElementsAre(
+          clock_before + maximum_idle_period_duration(),
+          clock_before + idle_task_runtime + maximum_idle_period_duration()));
 }
 
 TEST_F(IdleHelperTest, TestLongIdlePeriodRestartWaitsIfNotMaxDeadline) {
@@ -1092,9 +1087,6 @@
 TEST_F(IdleHelperTest, NoShortIdlePeriodWhenDeadlineTooClose) {
   int run_count = 0;
   base::TimeTicks deadline_in_task;
-  EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _))
-      .Times(AnyNumber())
-      .WillRepeatedly(Return(true));
 
   idle_task_runner_->PostIdleTask(
       FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
@@ -1121,9 +1113,6 @@
 TEST_F(IdleHelperTest, NoLongIdlePeriodWhenDeadlineTooClose) {
   int run_count = 0;
   base::TimeTicks deadline_in_task;
-  EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _))
-      .Times(AnyNumber())
-      .WillRepeatedly(Return(true));
 
   base::TimeDelta half_a_ms(base::TimeDelta::FromMicroseconds(50));
   base::TimeDelta less_than_min_deadline_duration(
diff --git a/components/scheduler/child/scheduler_helper.cc b/components/scheduler/child/scheduler_helper.cc
index 5cacb76b..650ea85a 100644
--- a/components/scheduler/child/scheduler_helper.cc
+++ b/components/scheduler/child/scheduler_helper.cc
@@ -4,10 +4,10 @@
 
 #include "components/scheduler/child/scheduler_helper.h"
 
+#include "base/time/default_tick_clock.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "components/scheduler/child/nestable_single_thread_task_runner.h"
-#include "components/scheduler/child/time_source.h"
 
 namespace scheduler {
 
@@ -32,7 +32,7 @@
           QueueId::CONTROL_TASK_AFTER_WAKEUP_QUEUE)),
       default_task_runner_(
           task_queue_manager_->TaskRunnerForQueue(QueueId::DEFAULT_TASK_QUEUE)),
-      time_source_(new TimeSource),
+      time_source_(new base::DefaultTickClock),
       tracing_category_(tracing_category),
       disabled_by_default_tracing_category_(
           disabled_by_default_tracing_category) {
@@ -89,7 +89,7 @@
 }
 
 void SchedulerHelper::SetTimeSourceForTesting(
-    scoped_ptr<TimeSource> time_source) {
+    scoped_ptr<base::TickClock> time_source) {
   CheckOnValidThread();
   time_source_ = time_source.Pass();
 }
@@ -105,7 +105,7 @@
 }
 
 base::TimeTicks SchedulerHelper::Now() const {
-  return time_source_->Now();
+  return time_source_->NowTicks();
 }
 
 scoped_refptr<base::SingleThreadTaskRunner> SchedulerHelper::TaskRunnerForQueue(
diff --git a/components/scheduler/child/scheduler_helper.h b/components/scheduler/child/scheduler_helper.h
index a28e022..e781803 100644
--- a/components/scheduler/child/scheduler_helper.h
+++ b/components/scheduler/child/scheduler_helper.h
@@ -7,9 +7,12 @@
 
 #include "components/scheduler/child/prioritizing_task_queue_selector.h"
 #include "components/scheduler/child/task_queue_manager.h"
-#include "components/scheduler/child/time_source.h"
 #include "components/scheduler/scheduler_export.h"
 
+namespace base {
+class TickClock;
+}
+
 namespace scheduler {
 
 class NestableSingleThreadTaskRunner;
@@ -93,7 +96,7 @@
   uint64 GetAndClearTaskWasRunOnQueueBitmap();
 
   // Test helpers.
-  void SetTimeSourceForTesting(scoped_ptr<TimeSource> time_source);
+  void SetTimeSourceForTesting(scoped_ptr<base::TickClock> time_source);
   void SetWorkBatchSizeForTesting(size_t work_batch_size);
   TaskQueueManager* GetTaskQueueManagerForTesting();
 
@@ -110,7 +113,7 @@
   scoped_refptr<base::SingleThreadTaskRunner> control_after_wakeup_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
 
-  scoped_ptr<TimeSource> time_source_;
+  scoped_ptr<base::TickClock> time_source_;
 
   const char* tracing_category_;
   const char* disabled_by_default_tracing_category_;
diff --git a/components/scheduler/child/task_queue_manager.cc b/components/scheduler/child/task_queue_manager.cc
index d9fa47c..569c4fa 100644
--- a/components/scheduler/child/task_queue_manager.cc
+++ b/components/scheduler/child/task_queue_manager.cc
@@ -8,11 +8,11 @@
 #include <set>
 
 #include "base/bind.h"
+#include "base/time/default_tick_clock.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "components/scheduler/child/nestable_single_thread_task_runner.h"
 #include "components/scheduler/child/task_queue_selector.h"
-#include "components/scheduler/child/time_source.h"
 
 namespace {
 const int64_t kMaxTimeTicks = std::numeric_limits<int64>::max();
@@ -467,7 +467,7 @@
       task_was_run_bitmap_(0),
       pending_dowork_count_(0),
       work_batch_size_(1),
-      time_source_(new TimeSource),
+      time_source_(new base::DefaultTickClock),
       disabled_by_default_tracing_category_(
           disabled_by_default_tracing_category),
       deletion_sentinel_(new DeletionSentinel()),
@@ -724,7 +724,7 @@
 }
 
 void TaskQueueManager::SetTimeSourceForTesting(
-    scoped_ptr<TimeSource> time_source) {
+    scoped_ptr<base::TickClock> time_source) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   time_source_ = time_source.Pass();
 }
@@ -736,7 +736,7 @@
 }
 
 base::TimeTicks TaskQueueManager::Now() const {
-  return time_source_->Now();
+  return time_source_->NowTicks();
 }
 
 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
diff --git a/components/scheduler/child/task_queue_manager.h b/components/scheduler/child/task_queue_manager.h
index 5fcbf3f..c0766c21 100644
--- a/components/scheduler/child/task_queue_manager.h
+++ b/components/scheduler/child/task_queue_manager.h
@@ -15,7 +15,6 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
 #include "components/scheduler/child/task_queue_selector.h"
-#include "components/scheduler/child/time_source.h"
 #include "components/scheduler/scheduler_export.h"
 
 namespace base {
@@ -23,6 +22,7 @@
 class ConvertableToTraceFormat;
 class TracedValue;
 }
+class TickClock;
 }
 
 namespace scheduler {
@@ -32,7 +32,6 @@
 }
 class NestableSingleThreadTaskRunner;
 class TaskQueueSelector;
-class TimeSource;
 
 // The task queue manager provides N task queues and a selector interface for
 // choosing which task queue to service next. Each task queue consists of two
@@ -158,7 +157,7 @@
   void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer);
   void RemoveTaskObserver(base::MessageLoop::TaskObserver* task_observer);
 
-  void SetTimeSourceForTesting(scoped_ptr<TimeSource> time_source);
+  void SetTimeSourceForTesting(scoped_ptr<base::TickClock> time_source);
 
   // Returns a bitmap where a bit is set iff a task on the corresponding queue
   // was run since the last call to GetAndClearTaskWasRunOnQueueBitmap.
@@ -248,7 +247,7 @@
 
   int work_batch_size_;
 
-  scoped_ptr<TimeSource> time_source_;
+  scoped_ptr<base::TickClock> time_source_;
 
   base::ObserverList<base::MessageLoop::TaskObserver> task_observers_;
 
diff --git a/components/scheduler/child/test_time_source.cc b/components/scheduler/child/test_time_source.cc
index 3482bb5..0c17193 100644
--- a/components/scheduler/child/test_time_source.cc
+++ b/components/scheduler/child/test_time_source.cc
@@ -15,7 +15,7 @@
 TestTimeSource::~TestTimeSource() {
 }
 
-base::TimeTicks TestTimeSource::Now() const {
+base::TimeTicks TestTimeSource::NowTicks() {
   return time_source_->Now();
 }
 
diff --git a/components/scheduler/child/test_time_source.h b/components/scheduler/child/test_time_source.h
index 6219a4dbd..4190ea1 100644
--- a/components/scheduler/child/test_time_source.h
+++ b/components/scheduler/child/test_time_source.h
@@ -6,7 +6,7 @@
 #define COMPONENTS_SCHEDULER_CHILD_TEST_TIME_SOURCE_H_
 
 #include "base/memory/ref_counted.h"
-#include "components/scheduler/child/time_source.h"
+#include "base/time/tick_clock.h"
 
 namespace cc {
 class TestNowSource;
@@ -14,12 +14,12 @@
 
 namespace scheduler {
 
-class TestTimeSource : public TimeSource {
+class TestTimeSource : public base::TickClock {
  public:
   explicit TestTimeSource(scoped_refptr<cc::TestNowSource> time_source);
   ~TestTimeSource() override;
 
-  base::TimeTicks Now() const override;
+  base::TimeTicks NowTicks() override;
 
  private:
   scoped_refptr<cc::TestNowSource> time_source_;
diff --git a/components/scheduler/child/time_source.cc b/components/scheduler/child/time_source.cc
deleted file mode 100644
index f8cf6c43..0000000
--- a/components/scheduler/child/time_source.cc
+++ /dev/null
@@ -1,19 +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 "components/scheduler/child/time_source.h"
-
-namespace scheduler {
-
-TimeSource::TimeSource() {
-}
-
-TimeSource::~TimeSource() {
-}
-
-base::TimeTicks TimeSource::Now() const {
-  return base::TimeTicks::Now();
-}
-
-}  // namespace scheduler
diff --git a/components/scheduler/child/time_source.h b/components/scheduler/child/time_source.h
deleted file mode 100644
index 079e78dc..0000000
--- a/components/scheduler/child/time_source.h
+++ /dev/null
@@ -1,26 +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 COMPONENTS_SCHEDULER_CHILD_TIME_SOURCE_H_
-#define COMPONENTS_SCHEDULER_CHILD_TIME_SOURCE_H_
-
-#include "base/time/time.h"
-#include "components/scheduler/scheduler_export.h"
-
-namespace scheduler {
-
-class SCHEDULER_EXPORT TimeSource {
- public:
-  TimeSource();
-  virtual ~TimeSource();
-
-  virtual base::TimeTicks Now() const;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TimeSource);
-};
-
-}  // namespace scheduler
-
-#endif  // COMPONENTS_SCHEDULER_CHILD_TIME_SOURCE_H_
diff --git a/components/scheduler/scheduler.gyp b/components/scheduler/scheduler.gyp
index e77be85..cffc072 100644
--- a/components/scheduler/scheduler.gyp
+++ b/components/scheduler/scheduler.gyp
@@ -50,5 +50,16 @@
         '../../third_party/WebKit/public/blink.gyp:blink',
       ],
     },
+    {
+      # GN version: //components/scheduler:test_support
+      'target_name': 'scheduler_test_support',
+      'type': 'static_library',
+      'include_dirs': [
+        '../..',
+      ],
+      'sources': [
+        '<@(scheduler_test_support_sources)',
+      ],
+    },
   ],
 }
diff --git a/components/scheduler/scheduler.gypi b/components/scheduler/scheduler.gypi
index 684688c..e0d4beece 100644
--- a/components/scheduler/scheduler.gypi
+++ b/components/scheduler/scheduler.gypi
@@ -32,8 +32,6 @@
       'child/task_queue_manager.cc',
       'child/task_queue_manager.h',
       'child/task_queue_selector.h',
-      'child/time_source.cc',
-      'child/time_source.h',
       'child/web_scheduler_impl.cc',
       'child/web_scheduler_impl.h',
       'child/webthread_base.cc',
@@ -58,5 +56,9 @@
       'renderer/webthread_impl_for_renderer_scheduler.h',
       'scheduler_export.h',
     ],
+    'scheduler_test_support_sources': [
+      'test/lazy_scheduler_message_loop_delegate_for_tests.cc',
+      'test/lazy_scheduler_message_loop_delegate_for_tests.h',
+    ],
   },
 }
diff --git a/components/scheduler/test/DEPS b/components/scheduler/test/DEPS
new file mode 100644
index 0000000..7fba883
--- /dev/null
+++ b/components/scheduler/test/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+components/scheduler/child",
+]
diff --git a/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc b/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.cc
new file mode 100644
index 0000000..999d856
--- /dev/null
+++ b/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.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 "components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h"
+
+namespace scheduler {
+
+// static
+scoped_refptr<LazySchedulerMessageLoopDelegateForTests>
+LazySchedulerMessageLoopDelegateForTests::Create() {
+  return make_scoped_refptr(new LazySchedulerMessageLoopDelegateForTests());
+}
+
+LazySchedulerMessageLoopDelegateForTests::
+    LazySchedulerMessageLoopDelegateForTests()
+    : message_loop_(base::MessageLoop::current()),
+      thread_id_(base::PlatformThread::CurrentId()) {
+}
+
+LazySchedulerMessageLoopDelegateForTests::
+    ~LazySchedulerMessageLoopDelegateForTests() {
+}
+
+base::MessageLoop* LazySchedulerMessageLoopDelegateForTests::EnsureMessageLoop()
+    const {
+  if (message_loop_)
+    return message_loop_;
+  DCHECK(RunsTasksOnCurrentThread());
+  message_loop_ = base::MessageLoop::current();
+  DCHECK(message_loop_);
+  for (auto& observer : pending_observers_) {
+    message_loop_->AddTaskObserver(observer);
+  }
+  pending_observers_.clear();
+  return message_loop_;
+}
+
+bool LazySchedulerMessageLoopDelegateForTests::HasMessageLoop() const {
+  return message_loop_ != nullptr;
+}
+
+bool LazySchedulerMessageLoopDelegateForTests::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    base::TimeDelta delay) {
+  return EnsureMessageLoop()->task_runner()->PostDelayedTask(from_here, task,
+                                                             delay);
+}
+
+bool LazySchedulerMessageLoopDelegateForTests::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    base::TimeDelta delay) {
+  return EnsureMessageLoop()->task_runner()->PostNonNestableDelayedTask(
+      from_here, task, delay);
+}
+
+bool LazySchedulerMessageLoopDelegateForTests::RunsTasksOnCurrentThread()
+    const {
+  return thread_id_ == base::PlatformThread::CurrentId();
+}
+
+bool LazySchedulerMessageLoopDelegateForTests::IsNested() const {
+  return EnsureMessageLoop()->IsNested();
+}
+
+void LazySchedulerMessageLoopDelegateForTests::AddTaskObserver(
+    base::MessageLoop::TaskObserver* task_observer) {
+  if (!HasMessageLoop()) {
+    pending_observers_.insert(task_observer);
+    return;
+  }
+  EnsureMessageLoop()->AddTaskObserver(task_observer);
+}
+
+void LazySchedulerMessageLoopDelegateForTests::RemoveTaskObserver(
+    base::MessageLoop::TaskObserver* task_observer) {
+  if (!HasMessageLoop()) {
+    pending_observers_.erase(task_observer);
+    return;
+  }
+  EnsureMessageLoop()->RemoveTaskObserver(task_observer);
+}
+
+}  // namespace scheduler
diff --git a/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h b/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h
new file mode 100644
index 0000000..a727a6d
--- /dev/null
+++ b/components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h
@@ -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.
+
+#ifndef COMPONENTS_SCHEDULER_TEST_LAZY_SCHEDULER_MESSAGE_LOOP_DELEGATE_FOR_TESTS_H_
+#define COMPONENTS_SCHEDULER_TEST_LAZY_SCHEDULER_MESSAGE_LOOP_DELEGATE_FOR_TESTS_H_
+
+#include "base/message_loop/message_loop.h"
+#include "components/scheduler/child/nestable_single_thread_task_runner.h"
+
+namespace scheduler {
+
+// This class connects the scheduler to a MessageLoop, but unlike
+// SchedulerMessageLoopDelegate it allows the message loop to be created lazily
+// after the scheduler has been brought up. This is needed in testing scenarios
+// where Blink is initialized before a MessageLoop has been created.
+//
+// TODO(skyostil): Fix the relevant test suites and remove this class
+// (crbug.com/495659).
+class LazySchedulerMessageLoopDelegateForTests
+    : public NestableSingleThreadTaskRunner {
+ public:
+  static scoped_refptr<LazySchedulerMessageLoopDelegateForTests> Create();
+
+  // NestableSingleThreadTaskRunner implementation
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const base::Closure& task,
+                       base::TimeDelta delay) override;
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const base::Closure& task,
+                                  base::TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+  bool IsNested() const override;
+  void AddTaskObserver(base::MessageLoop::TaskObserver* task_observer) override;
+  void RemoveTaskObserver(
+      base::MessageLoop::TaskObserver* task_observer) override;
+
+ private:
+  LazySchedulerMessageLoopDelegateForTests();
+  ~LazySchedulerMessageLoopDelegateForTests() override;
+
+  bool HasMessageLoop() const;
+  base::MessageLoop* EnsureMessageLoop() const;
+
+  mutable base::MessageLoop* message_loop_;
+  base::PlatformThreadId thread_id_;
+
+  // Task observers which have not yet been registered to a message loop. Not
+  // owned.
+  mutable base::hash_set<base::MessageLoop::TaskObserver*> pending_observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(LazySchedulerMessageLoopDelegateForTests);
+};
+
+}  // namespace scheduler
+
+#endif  // COMPONENTS_SCHEDULER_TEST_LAZY_SCHEDULER_MESSAGE_LOOP_DELEGATE_FOR_TESTS_H_
diff --git a/components/search_engines/template_url.cc b/components/search_engines/template_url.cc
index 571b9d2..553c8f65 100644
--- a/components/search_engines/template_url.cc
+++ b/components/search_engines/template_url.cc
@@ -16,6 +16,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -104,11 +105,12 @@
   query.len = static_cast<int>(params.size());
   while (url::ExtractQueryKeyValue(params.c_str(), &query, &key, &value)) {
     if (key.is_nonempty() && value.is_nonempty()) {
-      std::string value_string = params.substr(value.begin, value.len);
+      const base::StringPiece value_string(params.c_str() + value.begin,
+                                           value.len);
       if (value_string.find(kSearchTermsParameterFull, 0) !=
-          std::string::npos ||
+          base::StringPiece::npos ||
           value_string.find(kGoogleUnescapedSearchTermsParameterFull, 0) !=
-          std::string::npos) {
+          base::StringPiece::npos) {
         return params.substr(key.begin, key.len);
       }
     }
@@ -541,12 +543,18 @@
          end != std::string::npos && end > start);
   size_t length = end - start - 1;
   bool optional = false;
-  if ((*url)[end - 1] == kOptional) {
+  // Make a copy of |url| that can be referenced in StringPieces below. |url| is
+  // modified, so that can't be used in StringPiece.
+  const std::string original_url(*url);
+  if (original_url[end - 1] == kOptional) {
     optional = true;
     length--;
   }
-  std::string parameter(url->substr(start + 1, length));
-  std::string full_parameter(url->substr(start, end - start + 1));
+
+  const base::StringPiece parameter(original_url.begin() + start + 1,
+                                    original_url.begin() + start + 1 + length);
+  const base::StringPiece full_parameter(original_url.begin() + start,
+                                         original_url.begin() + end + 1);
   // Remove the parameter from the string.  For parameters who replacement is
   // constant and already known, just replace them directly.  For other cases,
   // like parameters whose values may change over time, use |replacements|.
@@ -662,7 +670,7 @@
     // If it's a prepopulated URL, we know that it's safe to remove unknown
     // parameters, so just ignore this and return true below. Otherwise it could
     // be some garbage but can also be a javascript block. Put it back.
-    url->insert(start, full_parameter);
+    url->insert(start, full_parameter.data(), full_parameter.size());
     return false;
   }
   return true;
@@ -876,7 +884,7 @@
           search_terms_args_without_aqs.assisted_query_stats.clear();
           GURL base_url(ReplaceSearchTerms(
               search_terms_args_without_aqs, search_terms_data, NULL));
-          if (base_url.SchemeIs(url::kHttpsScheme)) {
+          if (base_url.SchemeIsCryptographic()) {
             HandleReplacement(
                 "aqs", search_terms_args.assisted_query_stats, *i, &url);
           }
diff --git a/components/search_engines/template_url_unittest.cc b/components/search_engines/template_url_unittest.cc
index 2ab7428..29f75a7e 100644
--- a/components/search_engines/template_url_unittest.cc
+++ b/components/search_engines/template_url_unittest.cc
@@ -797,6 +797,10 @@
       "/", std::string::npos },
     { "http://blah/?foo=bar#x={searchTerms}&b=x", url::Parsed::REF,
       "/", std::string::npos },
+    // searchTerms is a key, not a value, so this should result in an empty
+    // value.
+    { "http://blah/?foo=bar#x=012345678901234&a=b&{searchTerms}=x",
+      url::Parsed::QUERY, std::string(), std::string::npos },
 
     // Multiple search terms should result in empty values.
     { "http://blah/{searchTerms}?q={searchTerms}", url::Parsed::QUERY,
diff --git a/components/signin/core/browser/about_signin_internals.cc b/components/signin/core/browser/about_signin_internals.cc
index 2c7d3cb..7c139a0 100644
--- a/components/signin/core/browser/about_signin_internals.cc
+++ b/components/signin/core/browser/about_signin_internals.cc
@@ -54,9 +54,11 @@
 
 void AddCookieEntry(base::ListValue* accounts_list,
                      const std::string& field_email,
+                     const std::string& field_gaia_id,
                      const std::string& field_valid) {
   scoped_ptr<base::DictionaryValue> entry(new base::DictionaryValue());
   entry->SetString("email", field_email);
+  entry->SetString("gaia_id", field_gaia_id);
   entry->SetString("valid", field_valid);
   accounts_list->Append(entry.release());
 }
@@ -343,7 +345,7 @@
 }
 
 void AboutSigninInternals::OnGaiaAccountsInCookieUpdated(
-    const std::vector<std::pair<std::string, bool> >& gaia_accounts,
+    const std::vector<gaia::ListedAccount>& gaia_accounts,
     const GoogleServiceAuthError& error) {
   if (error.state() != GoogleServiceAuthError::NONE)
     return;
@@ -354,12 +356,17 @@
 
   for (size_t i = 0; i < gaia_accounts.size(); ++i) {
     AddCookieEntry(cookie_info,
-                   gaia_accounts[i].first,
-                   gaia_accounts[i].second ? "Valid" : "Invalid");
+                   gaia_accounts[i].raw_email,
+                   gaia_accounts[i].gaia_id,
+                   gaia_accounts[i].valid ? "Valid" : "Invalid");
   }
 
-  if (gaia_accounts.size() == 0)
-    AddCookieEntry(cookie_info, "No Accounts Present.", "");
+  if (gaia_accounts.size() == 0) {
+    AddCookieEntry(cookie_info,
+                   "No Accounts Present.",
+                   std::string(),
+                   std::string());
+  }
 
   // Update the observers that the cookie's accounts are updated.
   FOR_EACH_OBSERVER(AboutSigninInternals::Observer,
diff --git a/components/signin/core/browser/about_signin_internals.h b/components/signin/core/browser/about_signin_internals.h
index f14ed9d..01b0b15 100644
--- a/components/signin/core/browser/about_signin_internals.h
+++ b/components/signin/core/browser/about_signin_internals.h
@@ -90,7 +90,7 @@
 
   // GaiaCookieManagerService::Observer implementations.
   void OnGaiaAccountsInCookieUpdated(
-      const std::vector<std::pair<std::string, bool> >& gaia_accounts,
+      const std::vector<gaia::ListedAccount>& gaia_accounts,
       const GoogleServiceAuthError& error) override;
 
  private:
diff --git a/components/signin/core/browser/account_reconcilor.cc b/components/signin/core/browser/account_reconcilor.cc
index b4531971..34738b7 100644
--- a/components/signin/core/browser/account_reconcilor.cc
+++ b/components/signin/core/browser/account_reconcilor.cc
@@ -24,16 +24,16 @@
 
 namespace {
 
-class EmailEqualToFunc : public std::equal_to<std::pair<std::string, bool> > {
+class EmailEqualToFunc : public std::equal_to<gaia::ListedAccount> {
  public:
-  bool operator()(const std::pair<std::string, bool>& p1,
-                  const std::pair<std::string, bool>& p2) const;
+  bool operator()(const gaia::ListedAccount& p1,
+                  const gaia::ListedAccount& p2) const;
 };
 
 bool EmailEqualToFunc::operator()(
-    const std::pair<std::string, bool>& p1,
-    const std::pair<std::string, bool>& p2) const {
-  return p1.second == p2.second && gaia::AreEmailsSame(p1.first, p2.first);
+    const gaia::ListedAccount& p1,
+    const gaia::ListedAccount& p2) const {
+  return p1.valid == p2.valid && gaia::AreEmailsSame(p1.email, p2.email);
 }
 
 class AreEmailsSameFunc : public std::equal_to<std::string> {
@@ -48,6 +48,14 @@
   return gaia::AreEmailsSame(p1, p2);
 }
 
+gaia::ListedAccount AccountFromEmail(const std::string& email) {
+  gaia::ListedAccount account;
+  account.email = email;
+  account.gaia_id = std::string();
+  account.valid = true;
+  return account;
+}
+
 }  // namespace
 
 
@@ -281,7 +289,7 @@
 }
 
 void AccountReconcilor::OnGaiaAccountsInCookieUpdated(
-        const std::vector<std::pair<std::string, bool> >& accounts,
+        const std::vector<gaia::ListedAccount>& accounts,
         const GoogleServiceAuthError& error) {
   VLOG(1) << "AccountReconcilor::OnGaiaAccountsInCookieUpdated: "
           << "CookieJar " << accounts.size() << " accounts, "
@@ -331,15 +339,15 @@
   DCHECK(add_to_cookie_.empty());
   int number_gaia_accounts = gaia_accounts_.size();
   bool are_primaries_equal = number_gaia_accounts > 0 &&
-      gaia::AreEmailsSame(primary_account_, gaia_accounts_[0].first);
+      gaia::AreEmailsSame(primary_account_, gaia_accounts_[0].email);
 
   // If there are any accounts in the gaia cookie but not in chrome, then
   // those accounts need to be removed from the cookie.  This means we need
   // to blow the cookie away.
   int removed_from_cookie = 0;
   for (size_t i = 0; i < gaia_accounts_.size(); ++i) {
-    const std::string& gaia_account = gaia_accounts_[i].first;
-    if (gaia_accounts_[i].second &&
+    const std::string& gaia_account = gaia_accounts_[i].email;
+    if (gaia_accounts_[i].valid &&
         chrome_accounts_.end() ==
             std::find_if(chrome_accounts_.begin(),
                          chrome_accounts_.end(),
@@ -349,7 +357,7 @@
   }
 
   bool rebuild_cookie = !are_primaries_equal || removed_from_cookie > 0;
-  std::vector<std::pair<std::string, bool> > original_gaia_accounts =
+  std::vector<gaia::ListedAccount> original_gaia_accounts =
       gaia_accounts_;
   if (rebuild_cookie) {
     VLOG(1) << "AccountReconcilor::FinishReconcile: rebuild cookie";
@@ -380,8 +388,8 @@
             std::find_if(gaia_accounts_.begin(),
                          gaia_accounts_.end(),
                          std::bind1st(EmailEqualToFunc(),
-                                      std::make_pair(add_to_cookie_copy[i],
-                                                     true)))) {
+                                      AccountFromEmail(add_to_cookie_copy[i]
+                                                       )))) {
       cookie_manager_service_->SignalComplete(
           add_to_cookie_copy[i],
           GoogleServiceAuthError::AuthErrorNone());
@@ -391,8 +399,8 @@
               std::find_if(original_gaia_accounts.begin(),
                            original_gaia_accounts.end(),
                            std::bind1st(EmailEqualToFunc(),
-                                        std::make_pair(add_to_cookie_copy[i],
-                                                       true)))) {
+                                        AccountFromEmail(add_to_cookie_copy[i]
+                                                         )))) {
         added_to_cookie++;
       }
     }
diff --git a/components/signin/core/browser/account_reconcilor.h b/components/signin/core/browser/account_reconcilor.h
index 801be87..a6feb74 100644
--- a/components/signin/core/browser/account_reconcilor.h
+++ b/components/signin/core/browser/account_reconcilor.h
@@ -64,11 +64,6 @@
     return registered_with_token_service_;
   }
 
-  const std::vector<std::pair<std::string, bool> >& GetGaiaAccountsForTesting()
-      const {
-    return gaia_accounts_;
-  }
-
   friend class AccountReconcilorTest;
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, SigninManagerRegistration);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, Reauth);
@@ -140,7 +135,7 @@
       const std::string& account_id,
       const GoogleServiceAuthError& error) override;
   void OnGaiaAccountsInCookieUpdated(
-        const std::vector<std::pair<std::string, bool> >& accounts,
+        const std::vector<gaia::ListedAccount>& accounts,
         const GoogleServiceAuthError& error) override;
 
   // Overriden from OAuth2TokenService::Observer.
@@ -183,10 +178,9 @@
   // Used during reconcile action.
   // These members are used to validate the gaia cookie.  |gaia_accounts_|
   // holds the state of google accounts in the gaia cookie.  Each element is
-  // a pair that holds the email address of the account and a boolean that
-  // indicates whether the account is valid or not.  The accounts in the vector
-  // are ordered the in same way as the gaia cookie.
-  std::vector<std::pair<std::string, bool> > gaia_accounts_;
+  // holds the email address, gaia id and validity as returned from GAIA.  The
+  // accounts in the vector are ordered the in same way as the gaia cookie.
+  std::vector<gaia::ListedAccount> gaia_accounts_;
 
   // Used during reconcile action.
   // These members are used to validate the tokens in OAuth2TokenService.
diff --git a/components/signin/core/browser/account_tracker_service.cc b/components/signin/core/browser/account_tracker_service.cc
index be7f09a..ee5a8e7 100644
--- a/components/signin/core/browser/account_tracker_service.cc
+++ b/components/signin/core/browser/account_tracker_service.cc
@@ -152,9 +152,8 @@
   const int kMaxRetries = 3;
   gaia_oauth_client_->GetUserInfo(access_token, kMaxRetries, this);
 
-  gaia_auth_fetcher_.reset(
-      new GaiaAuthFetcher(
-          this, GaiaConstants::kChromeSource, request_context_getter_));
+  gaia_auth_fetcher_.reset(service_->signin_client_->CreateGaiaAuthFetcher(
+      this, GaiaConstants::kChromeSource, request_context_getter_));
   gaia_auth_fetcher_->StartOAuthLogin(
       access_token, GaiaConstants::kGaiaService);
 }
diff --git a/components/signin/core/browser/device_activity_fetcher.cc b/components/signin/core/browser/device_activity_fetcher.cc
index 75bed21d..f8806467 100644
--- a/components/signin/core/browser/device_activity_fetcher.cc
+++ b/components/signin/core/browser/device_activity_fetcher.cc
@@ -77,17 +77,17 @@
 }
 
 void DeviceActivityFetcher::StartFetchingListIdpSessions() {
-  gaia_auth_fetcher_.reset(
-      new GaiaAuthFetcher(this, GaiaConstants::kChromeSource,
-                          signin_client_->GetURLRequestContext()));
+  gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
+      this, GaiaConstants::kChromeSource,
+      signin_client_->GetURLRequestContext()));
   gaia_auth_fetcher_->StartListIDPSessions(kSyncListDevicesScope,
                                            kChromeDomain);
 }
 
 void DeviceActivityFetcher::StartFetchingGetTokenResponse() {
-  gaia_auth_fetcher_.reset(
-      new GaiaAuthFetcher(this, GaiaConstants::kChromeSource,
-                          signin_client_->GetURLRequestContext()));
+  gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
+      this, GaiaConstants::kChromeSource,
+      signin_client_->GetURLRequestContext()));
   gaia_auth_fetcher_->StartGetTokenResponse(kSyncListDevicesScope,
                                             kChromeDomain, login_hint_);
 }
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.cc b/components/signin/core/browser/gaia_cookie_manager_service.cc
index 0926687d..4db5fa6 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service.cc
+++ b/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -14,9 +14,9 @@
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "components/signin/core/browser/account_tracker_service.h"
 #include "components/signin/core/browser/signin_metrics.h"
 #include "google_apis/gaia/gaia_auth_fetcher.h"
-#include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/oauth2_token_service.h"
@@ -123,7 +123,8 @@
   CleanupTransientState();
   results_.clear();
   helper_->gaia_auth_fetcher_.reset(
-      new GaiaAuthFetcher(this, helper_->source_, helper_->request_context()));
+      helper_->signin_client_->CreateGaiaAuthFetcher(
+          this, helper_->source_, helper_->request_context()));
   helper_->gaia_auth_fetcher_->StartGetCheckConnectionInfo();
 
   // Some fetches may timeout.  Start a timer to decide when the result fetcher
@@ -338,7 +339,7 @@
 }
 
 bool GaiaCookieManagerService::ListAccounts(
-    std::vector<std::pair<std::string,bool> >* accounts) {
+    std::vector<gaia::ListedAccount>* accounts) {
   DCHECK(accounts);
   accounts->clear();
 
@@ -560,6 +561,11 @@
     return;
   }
 
+  for (gaia::ListedAccount account : listed_accounts_) {
+    account.id = AccountTrackerService::PickAccountIdForAccount(
+        signin_client_->GetPrefs(), account.gaia_id, account.email);
+  }
+
   list_accounts_fetched_once_ = true;
   HandleNextRequest();
   // HandleNextRequest before sending out the notification because some
@@ -628,9 +634,10 @@
 void GaiaCookieManagerService::StartFetchingUbertoken() {
   VLOG(1) << "GaiaCookieManagerService::StartFetchingUbertoken account_id="
           << requests_.front().account_id();
-  uber_token_fetcher_.reset(
-      new UbertokenFetcher(token_service_, this, source_,
-                           signin_client_->GetURLRequestContext()));
+  uber_token_fetcher_.reset(new UbertokenFetcher(
+      token_service_, this, source_, signin_client_->GetURLRequestContext(),
+      base::Bind(&SigninClient::CreateGaiaAuthFetcher,
+                 base::Unretained(signin_client_))));
   if (access_token_.empty()) {
     uber_token_fetcher_->StartFetchingToken(requests_.front().account_id());
   } else {
@@ -641,9 +648,8 @@
 
 void GaiaCookieManagerService::StartFetchingMergeSession() {
   DCHECK(!uber_token_.empty());
-  gaia_auth_fetcher_.reset(
-      new GaiaAuthFetcher(this, source_,
-                          signin_client_->GetURLRequestContext()));
+  gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
+      this, source_, signin_client_->GetURLRequestContext()));
 
   gaia_auth_fetcher_->StartMergeSession(uber_token_,
       external_cc_result_fetcher_.GetExternalCcResult());
@@ -652,16 +658,15 @@
 void GaiaCookieManagerService::StartFetchingLogOut() {
   DCHECK(requests_.front().request_type() == GaiaCookieRequestType::LOG_OUT);
   VLOG(1) << "GaiaCookieManagerService::StartFetchingLogOut";
-  gaia_auth_fetcher_.reset(new GaiaAuthFetcher(
+  gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
       this, source_, signin_client_->GetURLRequestContext()));
   gaia_auth_fetcher_->StartLogOut();
 }
 
 void GaiaCookieManagerService::StartFetchingListAccounts() {
   VLOG(1) << "GaiaCookieManagerService::ListAccounts";
-  gaia_auth_fetcher_.reset(
-      new GaiaAuthFetcher(this, source_,
-                          signin_client_->GetURLRequestContext()));
+  gaia_auth_fetcher_.reset(signin_client_->CreateGaiaAuthFetcher(
+      this, source_, signin_client_->GetURLRequestContext()));
   gaia_auth_fetcher_->StartListAccounts();
 }
 
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.h b/components/signin/core/browser/gaia_cookie_manager_service.h
index b04ebda..4844937 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service.h
+++ b/components/signin/core/browser/gaia_cookie_manager_service.h
@@ -11,6 +11,7 @@
 #include "base/timer/timer.h"
 #include "components/signin/core/browser/signin_client.h"
 #include "google_apis/gaia/gaia_auth_consumer.h"
+#include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/ubertoken_fetcher.h"
 #include "net/base/backoff_entry.h"
 #include "net/url_request/url_fetcher_delegate.h"
@@ -81,7 +82,7 @@
     // If the ListAccounts call fails and the GCMS cannot recover, the reason
     // is passed in |error|.
     virtual void OnGaiaAccountsInCookieUpdated(
-        const std::vector<std::pair<std::string, bool> >& accounts,
+        const std::vector<gaia::ListedAccount>& accounts,
         const GoogleServiceAuthError& error) {}
 
    protected:
@@ -166,7 +167,7 @@
   // parameter if return is false). The parameter will be assigned the current
   // cached accounts. If the accounts are not up to date, a ListAccounts fetch
   // is sent GAIA and Observer::OnGaiaAccountsInCookieUpdated will be called.
-  bool ListAccounts(std::vector<std::pair<std::string,bool> >* accounts);
+  bool ListAccounts(std::vector<gaia::ListedAccount>* accounts);
 
   // Add or remove observers of this helper.
   void AddObserver(Observer* observer);
@@ -275,7 +276,7 @@
   // True once the ExternalCCResultFetcher has completed once.
   bool external_cc_result_fetched_;
 
-  std::vector<std::pair<std::string, bool> > listed_accounts_;
+  std::vector<gaia::ListedAccount> listed_accounts_;
 
   bool list_accounts_fetched_once_;
 
diff --git a/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc b/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
index 3b968de..232b50327 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
+++ b/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
@@ -9,12 +9,16 @@
 #include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/testing_pref_service.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/histogram_tester.h"
 #include "base/thread_task_runner_handle.h"
 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
 #include "components/signin/core/browser/test_signin_client.h"
+#include "components/signin/core/common/signin_pref_names.h"
 #include "google_apis/gaia/fake_oauth2_token_service.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
@@ -36,7 +40,7 @@
   MOCK_METHOD2(OnAddAccountToCookieCompleted,
                void(const std::string&, const GoogleServiceAuthError&));
   MOCK_METHOD2(OnGaiaAccountsInCookieUpdated,
-               void(const std::vector<std::pair<std::string, bool> >&,
+               void(const std::vector<gaia::ListedAccount>&,
                     const GoogleServiceAuthError&));
  private:
   GaiaCookieManagerService* helper_;
@@ -79,8 +83,15 @@
         error_(GoogleServiceAuthError::SERVICE_ERROR),
         canceled_(GoogleServiceAuthError::REQUEST_CANCELED) {}
 
+  void SetUp() override {
+    pref_service_.registry()->RegisterIntegerPref(
+        prefs::kAccountIdMigrationState,
+        AccountTrackerService::MIGRATION_NOT_STARTED);
+    signin_client_.reset(new TestSigninClient(&pref_service_));
+  }
+
   OAuth2TokenService* token_service() { return &token_service_; }
-  TestSigninClient* signin_client() { return &signin_client_; }
+  TestSigninClient* signin_client() { return signin_client_.get(); }
 
   void SimulateUbertokenSuccess(UbertokenConsumer* consumer,
                                 const std::string& uber_token) {
@@ -147,7 +158,8 @@
   GoogleServiceAuthError no_error_;
   GoogleServiceAuthError error_;
   GoogleServiceAuthError canceled_;
-  TestSigninClient signin_client_;
+  TestingPrefServiceSimple pref_service_;
+  scoped_ptr<TestSigninClient> signin_client_;
 };
 
 }  // namespace
@@ -512,7 +524,7 @@
   InstrumentedGaiaCookieManagerService helper(token_service(), signin_client());
   MockObserver observer(&helper);
 
-  std::vector<std::pair<std::string, bool> > list_accounts;
+  std::vector<gaia::ListedAccount> list_accounts;
 
   EXPECT_CALL(helper, StartFetchingListAccounts());
 
@@ -524,10 +536,14 @@
   InstrumentedGaiaCookieManagerService helper(token_service(), signin_client());
   MockObserver observer(&helper);
 
-  std::vector<std::pair<std::string, bool> > list_accounts;
-  std::vector<std::pair<std::string, bool> > expected_accounts;
-  expected_accounts.push_back(std::pair<std::string, bool>(
-      "user@gmail.com", true));
+  std::vector<gaia::ListedAccount> list_accounts;
+  std::vector<gaia::ListedAccount> expected_accounts;
+  gaia::ListedAccount listed_account;
+  listed_account.email = "a@b.com";
+  listed_account.raw_email = "a@b.com";
+  listed_account.gaia_id = "8";
+  listed_account.valid = true;
+  expected_accounts.push_back(listed_account);
 
   EXPECT_CALL(helper, StartFetchingListAccounts());
   EXPECT_CALL(observer, OnGaiaAccountsInCookieUpdated(expected_accounts,
@@ -536,7 +552,7 @@
   ASSERT_FALSE(helper.ListAccounts(&list_accounts));
 
   SimulateListAccountsSuccess(&helper,
-      "[\"f\", [[\"b\", 0, \"n\", \"user@gmail.com\", \"p\", 0, 0, 0, 0, 1]]]");
+      "[\"f\", [[\"b\", 0, \"n\", \"a@b.com\", \"p\", 0, 0, 0, 0, 1, \"8\"]]]");
 }
 
 TEST_F(GaiaCookieManagerServiceTest, ExternalCcResultFetcher) {
diff --git a/components/signin/core/browser/signin_client.h b/components/signin/core/browser/signin_client.h
index ab7ea2f..934443a 100644
--- a/components/signin/core/browser/signin_client.h
+++ b/components/signin/core/browser/signin_client.h
@@ -11,6 +11,7 @@
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/signin/core/browser/account_tracker_service.h"
 #include "components/signin/core/browser/webdata/token_web_data.h"
+#include "google_apis/gaia/gaia_auth_fetcher.h"
 #include "net/cookies/cookie_store.h"
 #include "url/gurl.h"
 
@@ -127,6 +128,13 @@
 
   // Execute |callback| if and when there is a network connection.
   virtual void DelayNetworkCall(const base::Closure& callback) = 0;
+
+  // Creates and returns a new platform-specific GaiaAuthFetcher. It is the
+  // responsability of the caller to delete the returned object.
+  virtual GaiaAuthFetcher* CreateGaiaAuthFetcher(
+      GaiaAuthConsumer* consumer,
+      const std::string& source,
+      net::URLRequestContextGetter* getter) = 0;
 };
 
 #endif  // COMPONENTS_SIGNIN_CORE_BROWSER_SIGNIN_CLIENT_H_
diff --git a/components/signin/core/browser/test_signin_client.cc b/components/signin/core/browser/test_signin_client.cc
index 21cbdc2..0c3768d 100644
--- a/components/signin/core/browser/test_signin_client.cc
+++ b/components/signin/core/browser/test_signin_client.cc
@@ -132,3 +132,10 @@
 void TestSigninClient::DelayNetworkCall(const base::Closure& callback) {
   callback.Run();
 }
+
+GaiaAuthFetcher* TestSigninClient::CreateGaiaAuthFetcher(
+    GaiaAuthConsumer* consumer,
+    const std::string& source,
+    net::URLRequestContextGetter* getter) {
+  return new GaiaAuthFetcher(consumer, source, getter);
+}
diff --git a/components/signin/core/browser/test_signin_client.h b/components/signin/core/browser/test_signin_client.h
index 50353b4..80ce089 100644
--- a/components/signin/core/browser/test_signin_client.h
+++ b/components/signin/core/browser/test_signin_client.h
@@ -99,6 +99,10 @@
   void RemoveContentSettingsObserver(
       content_settings::Observer* observer) override;
   void DelayNetworkCall(const base::Closure& callback) override;
+  GaiaAuthFetcher* CreateGaiaAuthFetcher(
+      GaiaAuthConsumer* consumer,
+      const std::string& source,
+      net::URLRequestContextGetter* getter) override;
 
  private:
   // Loads the token database.
diff --git a/components/test/data/autofill/merge/input/multimerge.in b/components/test/data/autofill/merge/input/multimerge.in
deleted file mode 100644
index 5e4ef807..0000000
--- a/components/test/data/autofill/merge/input/multimerge.in
+++ /dev/null
@@ -1,26 +0,0 @@
----
-NAME_FIRST: Alice
-NAME_MIDDLE: Anne
-NAME_LAST: Akins
-EMAIL_ADDRESS: aa@a.com
-COMPANY_NAME: Acme
-ADDRESS_HOME_LINE1: 1 Main Street
-ADDRESS_HOME_LINE2: Apt 1
-ADDRESS_HOME_CITY: San Francisco
-ADDRESS_HOME_STATE: CA
-ADDRESS_HOME_ZIP: 94102
-ADDRESS_HOME_COUNTRY: United States
-PHONE_HOME_WHOLE_NUMBER: 16502101111
----
-NAME_FIRST: Billy
-NAME_MIDDLE: Bob
-NAME_LAST: Bruner
-EMAIL_ADDRESS: bb@b.com
-COMPANY_NAME: Acme
-ADDRESS_HOME_LINE1: 1 Main Street
-ADDRESS_HOME_LINE2: Apt 1
-ADDRESS_HOME_CITY: San Francisco
-ADDRESS_HOME_STATE: CA
-ADDRESS_HOME_ZIP: 94102
-ADDRESS_HOME_COUNTRY: United States
-PHONE_HOME_WHOLE_NUMBER: 6502343333
diff --git a/components/test/data/autofill/merge/output/multimerge.out b/components/test/data/autofill/merge/output/multimerge.out
deleted file mode 100644
index 9120c75..0000000
--- a/components/test/data/autofill/merge/output/multimerge.out
+++ /dev/null
@@ -1,18 +0,0 @@
----
-NAME_FIRST: Alice
-NAME_FIRST: Billy
-NAME_MIDDLE: Anne
-NAME_MIDDLE: Bob
-NAME_LAST: Akins
-NAME_LAST: Bruner
-EMAIL_ADDRESS: aa@a.com
-EMAIL_ADDRESS: bb@b.com
-COMPANY_NAME: Acme
-ADDRESS_HOME_LINE1: 1 Main Street
-ADDRESS_HOME_LINE2: Apt 1
-ADDRESS_HOME_CITY: San Francisco
-ADDRESS_HOME_STATE: CA
-ADDRESS_HOME_ZIP: 94102
-ADDRESS_HOME_COUNTRY: US
-PHONE_HOME_WHOLE_NUMBER: 1 650-210-1111
-PHONE_HOME_WHOLE_NUMBER: (650) 234-3333
diff --git a/components/test/data/autofill/merge/output/primarycase.out b/components/test/data/autofill/merge/output/primarycase.out
index 9120c75..2006203 100644
--- a/components/test/data/autofill/merge/output/primarycase.out
+++ b/components/test/data/autofill/merge/output/primarycase.out
@@ -1,12 +1,8 @@
 ---
 NAME_FIRST: Alice
-NAME_FIRST: Billy
 NAME_MIDDLE: Anne
-NAME_MIDDLE: Bob
 NAME_LAST: Akins
-NAME_LAST: Bruner
 EMAIL_ADDRESS: aa@a.com
-EMAIL_ADDRESS: bb@b.com
 COMPANY_NAME: Acme
 ADDRESS_HOME_LINE1: 1 Main Street
 ADDRESS_HOME_LINE2: Apt 1
@@ -15,4 +11,16 @@
 ADDRESS_HOME_ZIP: 94102
 ADDRESS_HOME_COUNTRY: US
 PHONE_HOME_WHOLE_NUMBER: 1 650-210-1111
+---
+NAME_FIRST: Billy
+NAME_MIDDLE: Bob
+NAME_LAST: Bruner
+EMAIL_ADDRESS: bb@b.com
+COMPANY_NAME: Acme
+ADDRESS_HOME_LINE1: 1 MAIN STREET
+ADDRESS_HOME_LINE2: Apt 1
+ADDRESS_HOME_CITY: SAN FRANCISCO
+ADDRESS_HOME_STATE: CA
+ADDRESS_HOME_ZIP: 94102
+ADDRESS_HOME_COUNTRY: US
 PHONE_HOME_WHOLE_NUMBER: (650) 234-3333
diff --git a/components/test/data/autofill/merge/output/singlemerge.out b/components/test/data/autofill/merge/output/singlemerge.out
index 17e26636..f90b61b67 100644
--- a/components/test/data/autofill/merge/output/singlemerge.out
+++ b/components/test/data/autofill/merge/output/singlemerge.out
@@ -3,6 +3,19 @@
 NAME_MIDDLE: Anne
 NAME_LAST: Akins
 EMAIL_ADDRESS: aa@a.com
+COMPANY_NAME: Acme
+ADDRESS_HOME_LINE1: 1 Main Street
+ADDRESS_HOME_LINE2: Apt 1
+ADDRESS_HOME_CITY: San Francisco
+ADDRESS_HOME_STATE: CA
+ADDRESS_HOME_ZIP: 94102
+ADDRESS_HOME_COUNTRY: US
+PHONE_HOME_WHOLE_NUMBER: 1 650-210-1111
+---
+NAME_FIRST: Alice
+NAME_MIDDLE: Anne
+NAME_LAST: Akins
+EMAIL_ADDRESS: aa@a.com
 COMPANY_NAME: Box Co
 ADDRESS_HOME_LINE1: 1 Main Street
 ADDRESS_HOME_LINE2: Apt 2
diff --git a/components/test/data/dom_distiller/markup_article.html b/components/test/data/dom_distiller/markup_article.html
index 26fe868..c1a671b36 100644
--- a/components/test/data/dom_distiller/markup_article.html
+++ b/components/test/data/dom_distiller/markup_article.html
@@ -23,14 +23,6 @@
 
 <body>
 
-<div>
-<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>
-
-<br>
-
 <!-- Schema.Org Markup Info -->
 <div itemscope itemtype="http://schema.org/Article">
   <span itemprop="description">This page tests Markup Info.</span>
@@ -45,6 +37,13 @@
   <span itemprop="copyrightYear">2000-2014</span>
   <span itemprop="copyrightHolder">Whoever Copyrighted</span>
   <span itemprop="articleSection">Whatever Section</span>
+
+  <div>
+  <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>
+
 </div>
 
 </body>
diff --git a/components/test_runner/BUILD.gn b/components/test_runner/BUILD.gn
index 0f7921f..0471b5f 100644
--- a/components/test_runner/BUILD.gn
+++ b/components/test_runner/BUILD.gn
@@ -8,8 +8,11 @@
   import("//build/config/android/config.gni")
 }
 
-static_library("test_runner") {
+component("test_runner") {
   testonly = true
+
+  defines = [ "TEST_RUNNER_IMPLEMENTATION" ]
+
   sources = [
     "accessibility_controller.cc",
     "accessibility_controller.h",
@@ -61,6 +64,7 @@
     "test_preferences.h",
     "test_runner.cc",
     "test_runner.h",
+    "test_runner_export.h",
     "text_input_controller.cc",
     "text_input_controller.h",
     "web_ax_object_proxy.cc",
@@ -84,14 +88,16 @@
   deps = [
     ":resources",
     "//base",
-    "//base:base_static",
     "//cc",
     "//gin",
+    "//gpu",
     "//skia",
     "//third_party/WebKit/public:blink",
+    "//ui/events:dom_keycode_converter",
     "//ui/events:events_base",
     "//ui/gfx",
     "//ui/gfx/geometry",
+    "//url",
     "//v8",
 
     #'copy_test_netscape_plugin',  TODO(GYP)
diff --git a/components/test_runner/app_banner_client.h b/components/test_runner/app_banner_client.h
index f304baee3..1ecd77c4 100644
--- a/components/test_runner/app_banner_client.h
+++ b/components/test_runner/app_banner_client.h
@@ -5,14 +5,17 @@
 #ifndef COMPONENTS_TEST_RUNNER_APP_BANNER_CLIENT_H_
 #define COMPONENTS_TEST_RUNNER_APP_BANNER_CLIENT_H_
 
+#include "base/compiler_specific.h"
 #include "base/id_map.h"
+#include "components/test_runner/test_runner_export.h"
 #include "third_party/WebKit/public/platform/modules/app_banner/WebAppBannerClient.h"
 
 namespace test_runner {
 
 // Test app banner client that holds on to callbacks and allows the test runner
 // to resolve them.
-class AppBannerClient : public blink::WebAppBannerClient {
+class TEST_RUNNER_EXPORT AppBannerClient
+    : public NON_EXPORTED_BASE(blink::WebAppBannerClient) {
  public:
   AppBannerClient();
   virtual ~AppBannerClient();
diff --git a/components/test_runner/gamepad_controller.h b/components/test_runner/gamepad_controller.h
index 52ddb8b..fe32cb3 100644
--- a/components/test_runner/gamepad_controller.h
+++ b/components/test_runner/gamepad_controller.h
@@ -8,6 +8,7 @@
 #include <map>
 
 #include "base/memory/weak_ptr.h"
+#include "components/test_runner/test_runner_export.h"
 #include "third_party/WebKit/public/platform/WebGamepads.h"
 
 namespace blink {
@@ -19,7 +20,8 @@
 
 class WebTestDelegate;
 
-class GamepadController : public base::SupportsWeakPtr<GamepadController> {
+class TEST_RUNNER_EXPORT GamepadController
+    : public base::SupportsWeakPtr<GamepadController> {
  public:
   static base::WeakPtr<GamepadController> Create(WebTestDelegate* delegate);
   ~GamepadController();
diff --git a/components/test_runner/mock_screen_orientation_client.h b/components/test_runner/mock_screen_orientation_client.h
index 0271f06..3985c89 100644
--- a/components/test_runner/mock_screen_orientation_client.h
+++ b/components/test_runner/mock_screen_orientation_client.h
@@ -5,7 +5,9 @@
 #ifndef COMPONENTS_TEST_RUNNER_MOCK_SCREEN_ORIENTATION_CLIENT_H_
 #define COMPONENTS_TEST_RUNNER_MOCK_SCREEN_ORIENTATION_CLIENT_H_
 
+#include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "components/test_runner/test_runner_export.h"
 #include "third_party/WebKit/public/platform/WebLockOrientationCallback.h"
 #include "third_party/WebKit/public/platform/WebScreenOrientationClient.h"
 #include "third_party/WebKit/public/platform/WebScreenOrientationLockType.h"
@@ -17,7 +19,8 @@
 
 namespace test_runner {
 
-class MockScreenOrientationClient : public blink::WebScreenOrientationClient {
+class TEST_RUNNER_EXPORT MockScreenOrientationClient
+    : public NON_EXPORTED_BASE(blink::WebScreenOrientationClient) {
  public:
   explicit MockScreenOrientationClient();
   virtual ~MockScreenOrientationClient();
diff --git a/components/test_runner/test_common.h b/components/test_runner/test_common.h
index 86d8432..973b85c 100644
--- a/components/test_runner/test_common.h
+++ b/components/test_runner/test_common.h
@@ -7,6 +7,8 @@
 
 #include <string>
 
+#include "components/test_runner/test_runner_export.h"
+
 namespace test_runner {
 
 inline bool IsASCIIAlpha(char ch) {
@@ -17,7 +19,7 @@
   return !IsASCIIAlpha(ch);
 }
 
-std::string NormalizeLayoutTestURL(const std::string& url);
+TEST_RUNNER_EXPORT std::string NormalizeLayoutTestURL(const std::string& url);
 
 }  // namespace test_runner
 
diff --git a/components/test_runner/test_preferences.h b/components/test_runner/test_preferences.h
index 342dfd1..9512b9c 100644
--- a/components/test_runner/test_preferences.h
+++ b/components/test_runner/test_preferences.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_TEST_RUNNER_TEST_PREFERENCES_H_
 #define COMPONENTS_TEST_RUNNER_TEST_PREFERENCES_H_
 
+#include "components/test_runner/test_runner_export.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebURL.h"
 #include "third_party/WebKit/public/web/WebSettings.h"
@@ -15,7 +16,7 @@
 
 namespace test_runner {
 
-struct TestPreferences {
+struct TEST_RUNNER_EXPORT TestPreferences {
     int default_font_size;
     int minimum_font_size;
     bool dom_paste_allowed;
diff --git a/components/test_runner/test_runner.cc b/components/test_runner/test_runner.cc
index ac596f0..cb84141 100644
--- a/components/test_runner/test_runner.cc
+++ b/components/test_runner/test_runner.cc
@@ -1781,6 +1781,11 @@
   return generate_pixel_results_;
 }
 
+bool TestRunner::ShouldStayOnPageAfterHandlingBeforeUnload() const {
+  return should_stay_on_page_after_handling_before_unload_;
+}
+
+
 void TestRunner::setShouldGeneratePixelResults(bool value) {
   generate_pixel_results_ = value;
 }
@@ -1885,10 +1890,6 @@
   return is_printing_;
 }
 
-bool TestRunner::shouldStayOnPageAfterHandlingBeforeUnload() const {
-  return should_stay_on_page_after_handling_before_unload_;
-}
-
 bool TestRunner::shouldWaitUntilExternalURLLoad() const {
   return wait_until_external_url_load_;
 }
diff --git a/components/test_runner/test_runner.gyp b/components/test_runner/test_runner.gyp
index 4b5694b..0a06f74 100644
--- a/components/test_runner/test_runner.gyp
+++ b/components/test_runner/test_runner.gyp
@@ -3,25 +3,33 @@
 # found in the LICENSE file.
 
 {
+  'variables': {
+    # This turns on e.g. the filename-based detection of which
+    # platforms to include source files on (e.g. files ending in
+    # _mac.h or _mac.cc are only compiled on MacOSX).
+    'chromium_code': 1,
+  },
   'targets': [
     {
       # GN version: //components/test_runner:test_runner
       'target_name': 'test_runner',
-      'type': 'static_library',
-      'variables': {
-        'chromium_code': 1,
-      },
+      'type': '<(component)',
+      'defines': [
+        'TEST_RUNNER_IMPLEMENTATION',
+      ],
       'dependencies': [
         'resources',
         '../../base/base.gyp:base',
-        '../../base/base.gyp:base_static',
         '../../cc/cc.gyp:cc',
         '../../gin/gin.gyp:gin',
+        '../../gpu/gpu.gyp:gpu',
         '../../skia/skia.gyp:skia',
         '../../third_party/WebKit/public/blink.gyp:blink',
+        '../../ui/events/events.gyp:dom_keycode_converter',
         '../../ui/events/events.gyp:events_base',
         '../../ui/gfx/gfx.gyp:gfx',
         '../../ui/gfx/gfx.gyp:gfx_geometry',
+        '../../url/url.gyp:url_lib',
         '../../v8/tools/gyp/v8.gyp:v8',
       ],
       'include_dirs': [
@@ -77,6 +85,7 @@
         'test_plugin.h',
         'test_runner.cc',
         'test_runner.h',
+        'test_runner_export.h',
         'test_preferences.cc',
         'test_preferences.h',
         'text_input_controller.cc',
@@ -173,9 +182,6 @@
           # GN version: //components/test_runner:layout_test_helper
           'target_name': 'layout_test_helper',
           'type': 'executable',
-          'variables': {
-            'chromium_code': 1,
-          },
           'sources': [
             'helper/layout_test_helper_mac.mm',
             'helper/layout_test_helper_win.cc',
diff --git a/components/test_runner/test_runner.h b/components/test_runner/test_runner.h
index 75fe1e1..5bc0f75 100644
--- a/components/test_runner/test_runner.h
+++ b/components/test_runner/test_runner.h
@@ -12,6 +12,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "components/test_runner/test_runner_export.h"
 #include "components/test_runner/web_task.h"
 #include "components/test_runner/web_test_runner.h"
 #include "v8/include/v8.h"
@@ -65,6 +66,7 @@
 
   // WebTestRunner implementation.
   bool ShouldGeneratePixelResults() override;
+  bool ShouldStayOnPageAfterHandlingBeforeUnload() const override;
   bool ShouldDumpAsAudio() const override;
   void GetAudioData(std::vector<unsigned char>* buffer_view) const override;
   bool ShouldDumpBackForwardList() const override;
@@ -105,7 +107,6 @@
   bool shouldDumpStatusCallbacks() const;
   bool shouldDumpProgressFinishedCallback() const;
   bool shouldDumpSpellCheckCallbacks() const;
-  bool shouldStayOnPageAfterHandlingBeforeUnload() const;
   bool shouldWaitUntilExternalURLLoad() const;
   const std::set<std::string>* httpHeadersToClear() const;
   void setTopLoadingFrame(blink::WebFrame*, bool);
diff --git a/components/test_runner/test_runner_export.h b/components/test_runner/test_runner_export.h
new file mode 100644
index 0000000..ea096e8
--- /dev/null
+++ b/components/test_runner/test_runner_export.h
@@ -0,0 +1,29 @@
+// 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_TEST_RUNNER_TEST_RUNNER_EXPORT_H_
+#define COMPONENTS_TEST_RUNNER_TEST_RUNNER_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(TEST_RUNNER_IMPLEMENTATION)
+#define TEST_RUNNER_EXPORT __declspec(dllexport)
+#else
+#define TEST_RUNNER_EXPORT __declspec(dllimport)
+#endif  // defined(TEST_RUNNER_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(TEST_RUNNER_IMPLEMENTATION)
+#define TEST_RUNNER_EXPORT __attribute__((visibility("default")))
+#else
+#define TEST_RUNNER_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define TEST_RUNNER_EXPORT
+#endif
+
+#endif  // COMPONENTS_TEST_RUNNER_TEST_RUNNER_EXPORT_H_
diff --git a/components/test_runner/web_frame_test_proxy.h b/components/test_runner/web_frame_test_proxy.h
index d6bd3b5..6a313f5 100644
--- a/components/test_runner/web_frame_test_proxy.h
+++ b/components/test_runner/web_frame_test_proxy.h
@@ -7,10 +7,10 @@
 
 #include "base/basictypes.h"
 #include "components/test_runner/mock_screen_orientation_client.h"
-#include "components/test_runner/test_interfaces.h"
-#include "components/test_runner/test_runner.h"
 #include "components/test_runner/web_test_delegate.h"
+#include "components/test_runner/web_test_interfaces.h"
 #include "components/test_runner/web_test_proxy.h"
+#include "components/test_runner/web_test_runner.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 
 namespace test_runner {
@@ -145,20 +145,20 @@
   }
 
   virtual void runModalAlertDialog(const blink::WebString& message) {
-    base_proxy_->delegate_->PrintMessage(std::string("ALERT: ") +
-                                         message.utf8().data() + "\n");
+    base_proxy_->GetDelegate()->PrintMessage(std::string("ALERT: ") +
+                                             message.utf8().data() + "\n");
   }
 
   virtual bool runModalConfirmDialog(const blink::WebString& message) {
-    base_proxy_->delegate_->PrintMessage(std::string("CONFIRM: ") +
-                                         message.utf8().data() + "\n");
+    base_proxy_->GetDelegate()->PrintMessage(std::string("CONFIRM: ") +
+                                             message.utf8().data() + "\n");
     return true;
   }
 
   virtual bool runModalPromptDialog(const blink::WebString& message,
                                     const blink::WebString& default_value,
                                     blink::WebString*) {
-    base_proxy_->delegate_->PrintMessage(
+    base_proxy_->GetDelegate()->PrintMessage(
         std::string("PROMPT: ") + message.utf8().data() + ", default text: " +
         default_value.utf8().data() + "\n");
     return true;
@@ -166,10 +166,11 @@
 
   virtual bool runModalBeforeUnloadDialog(bool is_reload,
                                           const blink::WebString& message) {
-    base_proxy_->delegate_->PrintMessage(std::string("CONFIRM NAVIGATION: ") +
-                                         message.utf8().data() + "\n");
-    return !base_proxy_->test_interfaces_->GetTestRunner()
-                ->shouldStayOnPageAfterHandlingBeforeUnload();
+    base_proxy_->GetDelegate()->PrintMessage(
+        std::string("CONFIRM NAVIGATION: ") + message.utf8().data() + "\n");
+    return !base_proxy_->GetInterfaces()
+                ->TestRunner()
+                ->ShouldStayOnPageAfterHandlingBeforeUnload();
   }
 
   virtual void showContextMenu(
diff --git a/components/test_runner/web_test_interfaces.cc b/components/test_runner/web_test_interfaces.cc
index e499d9a..ca8aabd 100644
--- a/components/test_runner/web_test_interfaces.cc
+++ b/components/test_runner/web_test_interfaces.cc
@@ -86,4 +86,8 @@
   return client.Pass();
 }
 
+AppBannerClient* WebTestInterfaces::GetAppBannerClient() {
+  return interfaces_->GetAppBannerClient();
+}
+
 }  // namespace test_runner
diff --git a/components/test_runner/web_test_interfaces.h b/components/test_runner/web_test_interfaces.h
index 6d46d74..4056268 100644
--- a/components/test_runner/web_test_interfaces.h
+++ b/components/test_runner/web_test_interfaces.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_TEST_RUNNER_WEB_TEST_INTERFACES_H_
 
 #include "base/memory/scoped_ptr.h"
+#include "components/test_runner/test_runner_export.h"
 
 namespace blink {
 class WebAppBannerClient;
@@ -24,12 +25,13 @@
 
 namespace test_runner {
 
+class AppBannerClient;
 class TestInterfaces;
 class WebTestDelegate;
 class WebTestProxyBase;
 class WebTestRunner;
 
-class WebTestInterfaces {
+class TEST_RUNNER_EXPORT WebTestInterfaces {
  public:
   WebTestInterfaces();
   ~WebTestInterfaces();
@@ -56,6 +58,7 @@
   blink::WebAudioDevice* CreateAudioDevice(double sample_rate);
 
   scoped_ptr<blink::WebAppBannerClient> CreateAppBannerClient();
+  AppBannerClient* GetAppBannerClient();
 
   TestInterfaces* GetTestInterfaces();
 
diff --git a/components/test_runner/web_test_proxy.cc b/components/test_runner/web_test_proxy.cc
index b021480..766459d 100644
--- a/components/test_runner/web_test_proxy.cc
+++ b/components/test_runner/web_test_proxy.cc
@@ -379,7 +379,8 @@
 }
 
 WebTestProxyBase::WebTestProxyBase()
-    : test_interfaces_(NULL),
+    : web_test_interfaces_(NULL),
+      test_interfaces_(NULL),
       delegate_(NULL),
       web_widget_(NULL),
       spellcheck_(new SpellCheckClient(this)),
@@ -392,10 +393,15 @@
 }
 
 void WebTestProxyBase::SetInterfaces(WebTestInterfaces* interfaces) {
+  web_test_interfaces_ = interfaces;
   test_interfaces_ = interfaces->GetTestInterfaces();
   test_interfaces_->WindowOpened(this);
 }
 
+WebTestInterfaces* WebTestProxyBase::GetInterfaces() {
+  return web_test_interfaces_;
+}
+
 void WebTestProxyBase::SetDelegate(WebTestDelegate* delegate) {
   delegate_ = delegate;
   spellcheck_->SetDelegate(delegate);
@@ -403,6 +409,10 @@
     speech_recognizer_->SetDelegate(delegate);
 }
 
+WebTestDelegate* WebTestProxyBase::GetDelegate() {
+  return delegate_;
+}
+
 blink::WebView* WebTestProxyBase::GetWebView() const {
   DCHECK(web_widget_);
   // TestRunner does not support popup widgets. So |web_widget|_ is always a
diff --git a/components/test_runner/web_test_proxy.h b/components/test_runner/web_test_proxy.h
index 47d350e..81d736a 100644
--- a/components/test_runner/web_test_proxy.h
+++ b/components/test_runner/web_test_proxy.h
@@ -12,6 +12,7 @@
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
+#include "components/test_runner/test_runner_export.h"
 #include "components/test_runner/web_task.h"
 #include "third_party/WebKit/public/platform/WebImage.h"
 #include "third_party/WebKit/public/platform/WebRect.h"
@@ -88,10 +89,12 @@
 // when it requires a behavior to be different from the usual, it will call
 // WebTestProxyBase that implements the expected behavior.
 // See WebTestProxy class comments for more information.
-class WebTestProxyBase {
+class TEST_RUNNER_EXPORT WebTestProxyBase {
  public:
   void SetInterfaces(WebTestInterfaces* interfaces);
+  WebTestInterfaces* GetInterfaces();
   void SetDelegate(WebTestDelegate* delegate);
+  WebTestDelegate* GetDelegate();
   void set_widget(blink::WebWidget* widget) { web_widget_ = widget; }
 
   void Reset();
@@ -247,6 +250,7 @@
 
   blink::WebWidget* web_widget() const { return web_widget_; }
 
+  WebTestInterfaces* web_test_interfaces_;
   TestInterfaces* test_interfaces_;
   WebTestDelegate* delegate_;
   blink::WebWidget* web_widget_;
diff --git a/components/test_runner/web_test_runner.h b/components/test_runner/web_test_runner.h
index c9820dc..177e2ba 100644
--- a/components/test_runner/web_test_runner.h
+++ b/components/test_runner/web_test_runner.h
@@ -35,6 +35,8 @@
   // Returns true if WebTestProxy::capturePixels should be invoked after
   // capturing text results.
   virtual bool ShouldGeneratePixelResults() = 0;
+
+  virtual bool ShouldStayOnPageAfterHandlingBeforeUnload() const = 0;
 };
 
 }  // namespace test_runner
diff --git a/components/view_manager/connection_manager.cc b/components/view_manager/connection_manager.cc
index 8555200..1022048 100644
--- a/components/view_manager/connection_manager.cc
+++ b/components/view_manager/connection_manager.cc
@@ -115,20 +115,17 @@
     : delegate_(delegate),
       window_manager_client_connection_(nullptr),
       next_connection_id_(1),
+      event_dispatcher_(this),
       display_manager_(display_manager.Pass()),
       root_(CreateServerView(RootViewId())),
       current_change_(nullptr),
       in_destructor_(false),
       animation_runner_(base::TimeTicks::Now()),
-      event_dispatcher_(this),
-      event_dispatcher_binding_(&event_dispatcher_),
       focus_controller_(new FocusController(this, root_.get())) {
   root_->SetBounds(gfx::Rect(800, 600));
   root_->SetVisible(true);
 
-  mojo::NativeViewportEventDispatcherPtr event_dispatcher_ptr;
-  event_dispatcher_binding_.Bind(GetProxy(&event_dispatcher_ptr));
-  display_manager_->Init(this, event_dispatcher_ptr.Pass());
+  display_manager_->Init(this, &event_dispatcher_);
 }
 
 ConnectionManager::~ConnectionManager() {
@@ -312,7 +309,7 @@
 }
 
 void ConnectionManager::ProcessEvent(mojo::EventPtr event) {
-  event_dispatcher_.OnEvent(event.Pass(), EventDispatcher::OnEventCallback());
+  event_dispatcher_.OnEvent(event.Pass());
 }
 
 void ConnectionManager::DispatchInputEventToView(const ServerView* view,
diff --git a/components/view_manager/connection_manager.h b/components/view_manager/connection_manager.h
index ee3cac1..d6834289 100644
--- a/components/view_manager/connection_manager.h
+++ b/components/view_manager/connection_manager.h
@@ -15,7 +15,6 @@
 #include "components/view_manager/event_dispatcher.h"
 #include "components/view_manager/focus_controller_delegate.h"
 #include "components/view_manager/ids.h"
-#include "components/view_manager/public/interfaces/native_viewport.mojom.h"
 #include "components/view_manager/public/interfaces/view_manager.mojom.h"
 #include "components/view_manager/public/interfaces/view_manager_root.mojom.h"
 #include "components/view_manager/server_view_delegate.h"
@@ -253,6 +252,10 @@
   // Set of ViewManagerServiceImpls.
   ConnectionMap connection_map_;
 
+  // DisplayManager holds a raw pointer to EventDispatcher and so it must be
+  // destroyed after DisplayManager (and thus created before).
+  EventDispatcher event_dispatcher_;
+
   scoped_ptr<DisplayManager> display_manager_;
 
   scoped_ptr<ServerView> root_;
@@ -268,10 +271,6 @@
 
   AnimationRunner animation_runner_;
 
-  EventDispatcher event_dispatcher_;
-
-  mojo::Binding<mojo::NativeViewportEventDispatcher> event_dispatcher_binding_;
-
   scoped_ptr<FocusController> focus_controller_;
 
   mojo::ViewManagerRootClientPtr view_manager_root_client_;
diff --git a/components/view_manager/display_manager.cc b/components/view_manager/display_manager.cc
index 55e881a..8e51e33f 100644
--- a/components/view_manager/display_manager.cc
+++ b/components/view_manager/display_manager.cc
@@ -6,6 +6,8 @@
 
 #include "base/numerics/safe_conversions.h"
 #include "components/view_manager/connection_manager.h"
+#include "components/view_manager/gles2/gpu_state.h"
+#include "components/view_manager/native_viewport/onscreen_context_provider.h"
 #include "components/view_manager/public/interfaces/gpu.mojom.h"
 #include "components/view_manager/public/interfaces/quads.mojom.h"
 #include "components/view_manager/public/interfaces/surfaces.mojom.h"
@@ -73,49 +75,57 @@
 }  // namespace
 
 DefaultDisplayManager::DefaultDisplayManager(
+    bool is_headless,
     mojo::ApplicationImpl* app_impl,
-    const mojo::Callback<void()>& native_viewport_closed_callback)
-    : app_impl_(app_impl),
+    const scoped_refptr<gles2::GpuState>& gpu_state,
+    const mojo::Callback<void()>& platform_viewport_closed_callback)
+    : is_headless_(is_headless),
+      app_impl_(app_impl),
+      gpu_state_(gpu_state),
       connection_manager_(nullptr),
+      event_dispatcher_(nullptr),
       draw_timer_(false, false),
       frame_pending_(false),
-      native_viewport_closed_callback_(native_viewport_closed_callback),
+      context_provider_(
+          new native_viewport::OnscreenContextProvider(gpu_state)),
+      platform_viewport_closed_callback_(platform_viewport_closed_callback),
       weak_factory_(this) {
-  metrics_.size = mojo::Size::New();
-  metrics_.size->width = 800;
-  metrics_.size->height = 600;
+  metrics_.size_in_pixels = mojo::Size::New();
+  metrics_.size_in_pixels->width = 800;
+  metrics_.size_in_pixels->height = 600;
 }
 
 void DefaultDisplayManager::Init(
     ConnectionManager* connection_manager,
-    mojo::NativeViewportEventDispatcherPtr event_dispatcher) {
+    EventDispatcher* event_dispatcher) {
   connection_manager_ = connection_manager;
-  mojo::URLRequestPtr request(mojo::URLRequest::New());
-  // TODO(beng): should not need to connect to ourselves, should just
-  //             create the appropriate platform window directly.
-  request->url = mojo::String::From("mojo:view_manager");
-  app_impl_->ConnectToService(request.Pass(),
-                              &native_viewport_);
-  native_viewport_.set_error_handler(this);
-  native_viewport_->Create(metrics_.size->Clone(),
-                           base::Bind(&DefaultDisplayManager::OnMetricsChanged,
-                                      weak_factory_.GetWeakPtr()));
-  native_viewport_->Show();
+  event_dispatcher_ = event_dispatcher;
+
+  platform_viewport_ =
+      native_viewport::PlatformViewport::Create(this, is_headless_).Pass();
+  platform_viewport_->Init(gfx::Rect(metrics_.size_in_pixels.To<gfx::Size>()));
+  platform_viewport_->Show();
 
   mojo::ContextProviderPtr context_provider;
-  native_viewport_->GetContextProvider(GetProxy(&context_provider));
+  context_provider_->Bind(GetProxy(&context_provider).Pass());
   mojo::DisplayFactoryPtr display_factory;
-  mojo::URLRequestPtr request2(mojo::URLRequest::New());
-  request2->url = mojo::String::From("mojo:surfaces_service");
-  app_impl_->ConnectToService(request2.Pass(), &display_factory);
+  mojo::URLRequestPtr request(mojo::URLRequest::New());
+  request->url = mojo::String::From("mojo:surfaces_service");
+  app_impl_->ConnectToService(request.Pass(), &display_factory);
   display_factory->Create(context_provider.Pass(),
                           nullptr,  // returner - we never submit resources.
                           GetProxy(&display_));
-
-  native_viewport_->SetEventDispatcher(event_dispatcher.Pass());
 }
 
 DefaultDisplayManager::~DefaultDisplayManager() {
+  // Destroy before |platform_viewport_| because this will destroy
+  // CommandBufferDriver objects that contain child windows. Otherwise if this
+  // class destroys its window first, X errors will occur.
+  context_provider_.reset();
+
+  // Destroy the NativeViewport early on as it may call us back during
+  // destruction and we want to be in a known state.
+  platform_viewport_.reset();
 }
 
 void DefaultDisplayManager::SchedulePaint(const ServerView* view,
@@ -131,7 +141,7 @@
 }
 
 void DefaultDisplayManager::SetViewportSize(const gfx::Size& size) {
-  native_viewport_->SetSize(Size::From(size));
+  platform_viewport_->SetBounds(gfx::Rect(size));
 }
 
 const mojo::ViewportMetrics& DefaultDisplayManager::GetViewportMetrics() {
@@ -139,7 +149,7 @@
 }
 
 void DefaultDisplayManager::Draw() {
-  gfx::Rect rect(metrics_.size->width, metrics_.size->height);
+  gfx::Rect rect(metrics_.size_in_pixels.To<gfx::Size>());
   auto pass = mojo::CreateDefaultPass(1, rect);
   pass->damage_rect = Rect::From(dirty_rect_);
 
@@ -170,20 +180,41 @@
       base::Bind(&DefaultDisplayManager::Draw, base::Unretained(this)));
 }
 
-void DefaultDisplayManager::OnMetricsChanged(mojo::ViewportMetricsPtr metrics) {
-  metrics_.size = metrics->size.Clone();
-  metrics_.device_pixel_ratio = metrics->device_pixel_ratio;
-  gfx::Rect bounds(metrics_.size.To<gfx::Size>());
-  connection_manager_->root()->SetBounds(bounds);
-  connection_manager_->ProcessViewportMetricsChanged(metrics_, *metrics);
-  native_viewport_->RequestMetrics(base::Bind(
-      &DefaultDisplayManager::OnMetricsChanged, weak_factory_.GetWeakPtr()));
+void DefaultDisplayManager::OnAcceleratedWidgetAvailable(
+    gfx::AcceleratedWidget widget,
+    float device_pixel_ratio) {
+  context_provider_->SetAcceleratedWidget(widget);
 }
 
-void DefaultDisplayManager::OnConnectionError() {
-  // This is called when the native_viewport is torn down before
-  // ~DefaultDisplayManager may be called.
-  native_viewport_closed_callback_.Run();
+void DefaultDisplayManager::OnAcceleratedWidgetDestroyed() {
+  context_provider_->SetAcceleratedWidget(gfx::kNullAcceleratedWidget);
+}
+
+void DefaultDisplayManager::OnEvent(mojo::EventPtr event) {
+  event_dispatcher_->OnEvent(event.Pass());
+}
+
+void DefaultDisplayManager::OnMetricsChanged(const gfx::Size& size,
+                                             float device_scale_factor) {
+  if ((metrics_.size_in_pixels.To<gfx::Size>() == size) &&
+      (metrics_.device_pixel_ratio == device_scale_factor)) {
+    return;
+  }
+
+  mojo::ViewportMetrics metrics;
+  metrics.size_in_pixels = mojo::Size::From(size);
+  metrics.device_pixel_ratio = device_scale_factor;
+
+  connection_manager_->root()->SetBounds(gfx::Rect(size));
+  connection_manager_->ProcessViewportMetricsChanged(metrics_, metrics);
+
+  metrics_.size_in_pixels = metrics.size_in_pixels.Clone();
+  metrics_.device_pixel_ratio = metrics.device_pixel_ratio;
+}
+
+void DefaultDisplayManager::OnDestroyed() {
+  if (!platform_viewport_closed_callback_.is_null())
+    platform_viewport_closed_callback_.Run();
 }
 
 }  // namespace view_manager
diff --git a/components/view_manager/display_manager.h b/components/view_manager/display_manager.h
index 9bbeeca2..6ba94d7 100644
--- a/components/view_manager/display_manager.h
+++ b/components/view_manager/display_manager.h
@@ -11,22 +11,31 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
+#include "components/view_manager/native_viewport/platform_viewport.h"
 #include "components/view_manager/public/interfaces/display.mojom.h"
-#include "components/view_manager/public/interfaces/native_viewport.mojom.h"
 #include "components/view_manager/public/interfaces/view_manager.mojom.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/callback.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace cc {
 class SurfaceIdAllocator;
-}
+}  // namespace cc
+
+namespace gles2 {
+class GpuState;
+}  // namespace gles2
+
+namespace native_viewport {
+class OnscreenContextProvider;
+}  // namespace native_viewport
 
 namespace mojo {
 class ApplicationImpl;
-}
+}  // namespace mojo
 
 namespace view_manager {
 
+class EventDispatcher;
 class ConnectionManager;
 class ServerView;
 
@@ -37,7 +46,7 @@
 
   virtual void Init(
       ConnectionManager* connection_manager,
-      mojo::NativeViewportEventDispatcherPtr event_dispatcher) = 0;
+      EventDispatcher* event_dispatcher) = 0;
 
   // Schedules a paint for the specified region in the coordinates of |view|.
   virtual void SchedulePaint(const ServerView* view,
@@ -50,17 +59,20 @@
 
 // DisplayManager implementation that connects to the services necessary to
 // actually display.
-class DefaultDisplayManager : public DisplayManager,
-                              public mojo::ErrorHandler {
+class DefaultDisplayManager :
+    public DisplayManager,
+    public native_viewport::PlatformViewport::Delegate {
  public:
   DefaultDisplayManager(
+      bool is_headless,
       mojo::ApplicationImpl* app_impl,
-      const mojo::Callback<void()>& native_viewport_closed_callback);
+      const scoped_refptr<gles2::GpuState>& gpu_state,
+      const mojo::Callback<void()>& platform_viewport_closed_callback);
   ~DefaultDisplayManager() override;
 
   // DisplayManager:
   void Init(ConnectionManager* connection_manager,
-            mojo::NativeViewportEventDispatcherPtr event_dispatcher) override;
+            EventDispatcher* event_dispatcher) override;
   void SchedulePaint(const ServerView* view, const gfx::Rect& bounds) override;
   void SetViewportSize(const gfx::Size& size) override;
   const mojo::ViewportMetrics& GetViewportMetrics() override;
@@ -70,13 +82,20 @@
   void Draw();
   void DidDraw();
 
-  void OnMetricsChanged(mojo::ViewportMetricsPtr metrics);
+  // PlatformViewport::Delegate implementation:
+  void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget,
+                                    float device_pixel_ratio) override;
+  void OnAcceleratedWidgetDestroyed() override;
+  void OnEvent(mojo::EventPtr event) override;
+  void OnMetricsChanged(const gfx::Size& size,
+                        float device_scale_factor) override;
+  void OnDestroyed() override;
 
-  // ErrorHandler:
-  void OnConnectionError() override;
-
+  bool is_headless_;
   mojo::ApplicationImpl* app_impl_;
+  scoped_refptr<gles2::GpuState> gpu_state_;
   ConnectionManager* connection_manager_;
+  EventDispatcher* event_dispatcher_;
 
   mojo::ViewportMetrics metrics_;
   gfx::Rect dirty_rect_;
@@ -84,8 +103,10 @@
   bool frame_pending_;
 
   mojo::DisplayPtr display_;
-  mojo::NativeViewportPtr native_viewport_;
-  mojo::Callback<void()> native_viewport_closed_callback_;
+  scoped_ptr<native_viewport::OnscreenContextProvider> context_provider_;
+  scoped_ptr<native_viewport::PlatformViewport> platform_viewport_;
+  mojo::Callback<void()> platform_viewport_closed_callback_;
+
   base::WeakPtrFactory<DefaultDisplayManager> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(DefaultDisplayManager);
diff --git a/components/view_manager/event_dispatcher.cc b/components/view_manager/event_dispatcher.cc
index a06e7c2..edc2bc5 100644
--- a/components/view_manager/event_dispatcher.cc
+++ b/components/view_manager/event_dispatcher.cc
@@ -30,15 +30,11 @@
   accelerators_.erase(Accelerator(keyboard_code, flags));
 }
 
-void EventDispatcher::OnEvent(mojo::EventPtr event,
-                              const OnEventCallback& callback) {
-  callback.Run();
-
+void EventDispatcher::OnEvent(mojo::EventPtr event) {
   if (event->pointer_data) {
     const gfx::Point root_point(static_cast<int>(event->pointer_data->x),
                                 static_cast<int>(event->pointer_data->y));
     ServerView* target = connection_manager_->GetFocusedView();
-    ;
     if (event->action == mojo::EVENT_TYPE_POINTER_DOWN || !target) {
       target = FindDeepestVisibleView(connection_manager_->root(), root_point);
       CHECK(target);
diff --git a/components/view_manager/event_dispatcher.h b/components/view_manager/event_dispatcher.h
index 9716f06..a2d4514 100644
--- a/components/view_manager/event_dispatcher.h
+++ b/components/view_manager/event_dispatcher.h
@@ -8,24 +8,25 @@
 #include <set>
 
 #include "base/basictypes.h"
-#include "components/view_manager/public/interfaces/native_viewport.mojom.h"
+#include "ui/mojo/events/input_event_constants.mojom.h"
+#include "ui/mojo/events/input_events.mojom.h"
+#include "ui/mojo/events/input_key_codes.mojom.h"
 
 namespace view_manager {
 
 class ConnectionManager;
 
 // Handles dispatching events to the right location as well as updating focus.
-class EventDispatcher : public mojo::NativeViewportEventDispatcher {
+class EventDispatcher {
  public:
   explicit EventDispatcher(ConnectionManager* connection_manager);
-  ~EventDispatcher() override;
+  ~EventDispatcher();
 
   void AddAccelerator(mojo::KeyboardCode keyboard_code, mojo::EventFlags flags);
   void RemoveAccelerator(mojo::KeyboardCode keyboard_code,
                          mojo::EventFlags flags);
 
-  // NativeViewportEventDispatcher:
-  void OnEvent(mojo::EventPtr event, const OnEventCallback& callback) override;
+  void OnEvent(mojo::EventPtr event);
 
  private:
   struct Accelerator {
diff --git a/components/view_manager/native_viewport/BUILD.gn b/components/view_manager/native_viewport/BUILD.gn
index 1201bd4..123e40e 100644
--- a/components/view_manager/native_viewport/BUILD.gn
+++ b/components/view_manager/native_viewport/BUILD.gn
@@ -7,8 +7,6 @@
 
 source_set("native_viewport") {
   sources = [
-    "native_viewport_impl.cc",
-    "native_viewport_impl.h",
     "onscreen_context_provider.cc",
     "onscreen_context_provider.h",
     "platform_viewport.h",
diff --git a/components/view_manager/native_viewport/native_viewport_impl.cc b/components/view_manager/native_viewport/native_viewport_impl.cc
deleted file mode 100644
index e990cbdc..0000000
--- a/components/view_manager/native_viewport/native_viewport_impl.cc
+++ /dev/null
@@ -1,166 +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 "components/view_manager/native_viewport/native_viewport_impl.h"
-
-#include "base/auto_reset.h"
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/time/time.h"
-#include "components/view_manager/gles2/gpu_state.h"
-#include "components/view_manager/native_viewport/platform_viewport_headless.h"
-#include "mojo/application/public/cpp/interface_factory.h"
-#include "mojo/converters/geometry/geometry_type_converters.h"
-#include "ui/events/event.h"
-
-namespace native_viewport {
-
-NativeViewportImpl::NativeViewportImpl(
-    bool is_headless,
-    const scoped_refptr<gles2::GpuState>& gpu_state,
-    mojo::InterfaceRequest<mojo::NativeViewport> request,
-    scoped_ptr<mojo::AppRefCount> app_refcount)
-    : is_headless_(is_headless),
-      app_refcount_(app_refcount.Pass()),
-      context_provider_(new OnscreenContextProvider(gpu_state)),
-      sent_metrics_(false),
-      metrics_(mojo::ViewportMetrics::New()),
-      binding_(this, request.Pass()),
-      weak_factory_(this) {
-}
-
-NativeViewportImpl::~NativeViewportImpl() {
-  // Destroy before |platform_viewport_| because this will destroy
-  // CommandBufferDriver objects that contain child windows. Otherwise if this
-  // class destroys its window first, X errors will occur.
-  context_provider_.reset();
-
-  // Destroy the NativeViewport early on as it may call us back during
-  // destruction and we want to be in a known state.
-  platform_viewport_.reset();
-}
-
-void NativeViewportImpl::Create(mojo::SizePtr size,
-                                const CreateCallback& callback) {
-  create_callback_ = callback;
-  metrics_->size = size.Clone();
-  if (is_headless_)
-    platform_viewport_ = PlatformViewportHeadless::Create(this);
-  else
-    platform_viewport_ = PlatformViewport::Create(this);
-  platform_viewport_->Init(gfx::Rect(size.To<gfx::Size>()));
-}
-
-void NativeViewportImpl::RequestMetrics(
-    const RequestMetricsCallback& callback) {
-  if (!sent_metrics_) {
-    callback.Run(metrics_.Clone());
-    sent_metrics_ = true;
-    return;
-  }
-  metrics_callback_ = callback;
-}
-
-void NativeViewportImpl::Show() {
-  platform_viewport_->Show();
-}
-
-void NativeViewportImpl::Hide() {
-  platform_viewport_->Hide();
-}
-
-void NativeViewportImpl::Close() {
-  DCHECK(platform_viewport_);
-  platform_viewport_->Close();
-}
-
-void NativeViewportImpl::SetSize(mojo::SizePtr size) {
-  platform_viewport_->SetBounds(gfx::Rect(size.To<gfx::Size>()));
-}
-
-void NativeViewportImpl::GetContextProvider(
-    mojo::InterfaceRequest<mojo::ContextProvider> request) {
-  context_provider_->Bind(request.Pass());
-}
-
-void NativeViewportImpl::SetEventDispatcher(
-    mojo::NativeViewportEventDispatcherPtr dispatcher) {
-  event_dispatcher_ = dispatcher.Pass();
-}
-
-void NativeViewportImpl::OnMetricsChanged(mojo::ViewportMetricsPtr metrics) {
-  if (metrics_->Equals(*metrics))
-    return;
-
-  metrics_ = metrics.Pass();
-  sent_metrics_ = false;
-
-  if (!metrics_callback_.is_null()) {
-    metrics_callback_.Run(metrics_.Clone());
-    metrics_callback_.reset();
-    sent_metrics_ = true;
-  }
-}
-
-void NativeViewportImpl::OnAcceleratedWidgetAvailable(
-    gfx::AcceleratedWidget widget,
-    float device_pixel_ratio) {
-  metrics_->device_pixel_ratio = device_pixel_ratio;
-  context_provider_->SetAcceleratedWidget(widget);
-  // TODO: The metrics here might not match the actual window size on android
-  // where we don't know the actual size until the first OnMetricsChanged call.
-  create_callback_.Run(metrics_.Clone());
-  sent_metrics_ = true;
-  create_callback_.reset();
-}
-
-void NativeViewportImpl::OnAcceleratedWidgetDestroyed() {
-  context_provider_->SetAcceleratedWidget(gfx::kNullAcceleratedWidget);
-}
-
-bool NativeViewportImpl::OnEvent(mojo::EventPtr event) {
-  if (event.is_null() || !event_dispatcher_.get())
-    return false;
-
-  mojo::NativeViewportEventDispatcher::OnEventCallback callback;
-  switch (event->action) {
-    case mojo::EVENT_TYPE_POINTER_MOVE: {
-      // TODO(sky): add logic to remember last event location and not send if
-      // the same.
-      if (pointers_waiting_on_ack_.count(event->pointer_data->pointer_id))
-        return false;
-
-      pointers_waiting_on_ack_.insert(event->pointer_data->pointer_id);
-      callback =
-          base::Bind(&NativeViewportImpl::AckEvent, weak_factory_.GetWeakPtr(),
-                     event->pointer_data->pointer_id);
-      break;
-    }
-
-    case mojo::EVENT_TYPE_POINTER_CANCEL:
-      pointers_waiting_on_ack_.clear();
-      break;
-
-    case mojo::EVENT_TYPE_POINTER_UP:
-      pointers_waiting_on_ack_.erase(event->pointer_data->pointer_id);
-      break;
-
-    default:
-      break;
-  }
-
-  event_dispatcher_->OnEvent(event.Pass(), callback);
-  return false;
-}
-
-void NativeViewportImpl::OnDestroyed() {
-  delete this;
-}
-
-void NativeViewportImpl::AckEvent(int32 pointer_id) {
-  pointers_waiting_on_ack_.erase(pointer_id);
-}
-
-}  // namespace native_viewport
diff --git a/components/view_manager/native_viewport/native_viewport_impl.h b/components/view_manager/native_viewport/native_viewport_impl.h
deleted file mode 100644
index 2c21b14..0000000
--- a/components/view_manager/native_viewport/native_viewport_impl.h
+++ /dev/null
@@ -1,90 +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 COMPONENTS_VIEW_MANAGER_NATIVE_VIEWPORT_NATIVE_VIEWPORT_IMPL_H_
-#define COMPONENTS_VIEW_MANAGER_NATIVE_VIEWPORT_NATIVE_VIEWPORT_IMPL_H_
-
-#include <set>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/view_manager/native_viewport/onscreen_context_provider.h"
-#include "components/view_manager/native_viewport/platform_viewport.h"
-#include "components/view_manager/public/interfaces/gpu.mojom.h"
-#include "components/view_manager/public/interfaces/native_viewport.mojom.h"
-#include "mojo/application/public/cpp/app_lifetime_helper.h"
-#include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace gles2 {
-class GpuState;
-}
-
-namespace ui {
-class Event;
-}
-
-namespace native_viewport {
-
-// A NativeViewportImpl is bound to a message pipe and to a PlatformViewport.
-// The NativeViewportImpl's lifetime ends when either the message pipe is closed
-// or the PlatformViewport informs the NativeViewportImpl that it has been
-// destroyed.
-class NativeViewportImpl : public mojo::NativeViewport,
-                           public PlatformViewport::Delegate {
- public:
-  NativeViewportImpl(bool is_headless,
-                     const scoped_refptr<gles2::GpuState>& gpu_state,
-                     mojo::InterfaceRequest<mojo::NativeViewport> request,
-                     scoped_ptr<mojo::AppRefCount> app_refcount);
-  ~NativeViewportImpl() override;
-
-  // NativeViewport implementation.
-  void Create(mojo::SizePtr size, const CreateCallback& callback) override;
-  void RequestMetrics(const RequestMetricsCallback& callback) override;
-  void Show() override;
-  void Hide() override;
-  void Close() override;
-  void SetSize(mojo::SizePtr size) override;
-  void GetContextProvider(
-      mojo::InterfaceRequest<mojo::ContextProvider> request) override;
-  void SetEventDispatcher(
-      mojo::NativeViewportEventDispatcherPtr dispatcher) override;
-
-  // PlatformViewport::Delegate implementation.
-  void OnMetricsChanged(mojo::ViewportMetricsPtr metrics) override;
-  void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget,
-                                    float device_pixel_ratio) override;
-  void OnAcceleratedWidgetDestroyed() override;
-  bool OnEvent(mojo::EventPtr event) override;
-  void OnDestroyed() override;
-
- private:
-  // Callback when the dispatcher has processed a message we're waiting on
-  // an ack from. |pointer_id| identifies the pointer the message was associated
-  // with.
-  void AckEvent(int32 pointer_id);
-
-  bool is_headless_;
-  scoped_ptr<mojo::AppRefCount> app_refcount_;
-  scoped_ptr<PlatformViewport> platform_viewport_;
-  scoped_ptr<OnscreenContextProvider> context_provider_;
-  bool sent_metrics_;
-  mojo::ViewportMetricsPtr metrics_;
-  CreateCallback create_callback_;
-  RequestMetricsCallback metrics_callback_;
-  mojo::NativeViewportEventDispatcherPtr event_dispatcher_;
-  mojo::StrongBinding<mojo::NativeViewport> binding_;
-
-  // Set of pointer_ids we've sent a move to and are waiting on an ack.
-  std::set<int32> pointers_waiting_on_ack_;
-
-  base::WeakPtrFactory<NativeViewportImpl> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(NativeViewportImpl);
-};
-
-}  // namespace native_viewport
-
-#endif  // COMPONENTS_VIEW_MANAGER_NATIVE_VIEWPORT_NATIVE_VIEWPORT_IMPL_H_
diff --git a/components/view_manager/native_viewport/platform_viewport.h b/components/view_manager/native_viewport/platform_viewport.h
index 6bc62ca..f57adb9 100644
--- a/components/view_manager/native_viewport/platform_viewport.h
+++ b/components/view_manager/native_viewport/platform_viewport.h
@@ -6,7 +6,6 @@
 #define COMPONENTS_VIEW_MANAGER_NATIVE_VIEWPORT_PLATFORM_VIEWPORT_H_
 
 #include "base/memory/scoped_ptr.h"
-#include "components/view_manager/public/interfaces/native_viewport.mojom.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/mojo/events/input_events.mojom.h"
@@ -24,12 +23,13 @@
    public:
     virtual ~Delegate() {}
 
-    virtual void OnMetricsChanged(mojo::ViewportMetricsPtr metrics) = 0;
     virtual void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget,
                                               float device_pixel_ratio) = 0;
     virtual void OnAcceleratedWidgetDestroyed() = 0;
-    virtual bool OnEvent(mojo::EventPtr event) = 0;
     virtual void OnDestroyed() = 0;
+    virtual void OnEvent(mojo::EventPtr event) = 0;
+    virtual void OnMetricsChanged(const gfx::Size& size,
+                                  float device_scale_factor) = 0;
   };
 
   virtual ~PlatformViewport() {}
@@ -41,7 +41,7 @@
   virtual gfx::Size GetSize() = 0;
   virtual void SetBounds(const gfx::Rect& bounds) = 0;
 
-  static scoped_ptr<PlatformViewport> Create(Delegate* delegate);
+  static scoped_ptr<PlatformViewport> Create(Delegate* delegate, bool headless);
 };
 
 }  // namespace native_viewport
diff --git a/components/view_manager/native_viewport/platform_viewport_android.cc b/components/view_manager/native_viewport/platform_viewport_android.cc
index ccca113..f5d47be 100644
--- a/components/view_manager/native_viewport/platform_viewport_android.cc
+++ b/components/view_manager/native_viewport/platform_viewport_android.cc
@@ -8,6 +8,7 @@
 #include <android/native_window_jni.h>
 
 #include "base/android/jni_android.h"
+#include "components/view_manager/native_viewport/platform_viewport_headless.h"
 #include "jni/PlatformViewportAndroid_jni.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
 #include "mojo/converters/input_events/input_events_type_converters.h"
@@ -98,12 +99,8 @@
                                              jint width,
                                              jint height,
                                              jfloat density) {
-  metrics_ = mojo::ViewportMetrics::New();
-  metrics_->size = mojo::Size::New();
-  metrics_->size->width = static_cast<int>(width);
-  metrics_->size->height = static_cast<int>(height);
-  metrics_->device_pixel_ratio = density;
-  delegate_->OnMetricsChanged(metrics_.Clone());
+  size_ = gfx::Size(static_cast<int>(width), static_cast<int>(height));
+  delegate_->OnMetricsChanged(size_, density);
 }
 
 bool PlatformViewportAndroid::TouchEvent(JNIEnv* env,
@@ -189,7 +186,7 @@
 }
 
 gfx::Size PlatformViewportAndroid::GetSize() {
-  return metrics_->size.To<gfx::Size>();
+  return size_;
 }
 
 void PlatformViewportAndroid::SetBounds(const gfx::Rect& bounds) {
@@ -208,7 +205,11 @@
 // PlatformViewport, public:
 
 // static
-scoped_ptr<PlatformViewport> PlatformViewport::Create(Delegate* delegate) {
+scoped_ptr<PlatformViewport> PlatformViewport::Create(Delegate* delegate,
+                                                      bool headless) {
+  if (headless)
+    return PlatformViewportHeadless::Create(delegate);
+
   return scoped_ptr<PlatformViewport>(
       new PlatformViewportAndroid(delegate)).Pass();
 }
diff --git a/components/view_manager/native_viewport/platform_viewport_android.h b/components/view_manager/native_viewport/platform_viewport_android.h
index 467614b7..3eba7cc 100644
--- a/components/view_manager/native_viewport/platform_viewport_android.h
+++ b/components/view_manager/native_viewport/platform_viewport_android.h
@@ -73,9 +73,10 @@
   Delegate* const delegate_;
   JavaObjectWeakGlobalRef java_platform_viewport_android_;
   ANativeWindow* window_;
-  mojo::ViewportMetricsPtr metrics_;
   ui::SequentialIDGenerator id_generator_;
 
+  gfx::Size size_;
+
   base::WeakPtrFactory<PlatformViewportAndroid> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(PlatformViewportAndroid);
diff --git a/components/view_manager/native_viewport/platform_viewport_headless.cc b/components/view_manager/native_viewport/platform_viewport_headless.cc
index 3918b18..a758a5070 100644
--- a/components/view_manager/native_viewport/platform_viewport_headless.cc
+++ b/components/view_manager/native_viewport/platform_viewport_headless.cc
@@ -18,7 +18,7 @@
 void PlatformViewportHeadless::Init(const gfx::Rect& bounds) {
   metrics_ = mojo::ViewportMetrics::New();
   metrics_->device_pixel_ratio = 1.f;
-  metrics_->size = mojo::Size::From(bounds.size());
+  metrics_->size_in_pixels = mojo::Size::From(bounds.size());
 }
 
 void PlatformViewportHeadless::Show() {
@@ -32,12 +32,11 @@
 }
 
 gfx::Size PlatformViewportHeadless::GetSize() {
-  return metrics_->size.To<gfx::Size>();
+  return metrics_->size_in_pixels.To<gfx::Size>();
 }
 
 void PlatformViewportHeadless::SetBounds(const gfx::Rect& bounds) {
-  metrics_->size = mojo::Size::From(bounds.size());
-  delegate_->OnMetricsChanged(metrics_->Clone());
+  delegate_->OnMetricsChanged(bounds.size(), 1.f /* device_scale_factor */);
 }
 
 // static
diff --git a/components/view_manager/native_viewport/platform_viewport_headless.h b/components/view_manager/native_viewport/platform_viewport_headless.h
index 949bc316..924f3a5 100644
--- a/components/view_manager/native_viewport/platform_viewport_headless.h
+++ b/components/view_manager/native_viewport/platform_viewport_headless.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "components/view_manager/native_viewport/platform_viewport.h"
+#include "components/view_manager/public/interfaces/view_manager.mojom.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace native_viewport {
diff --git a/components/view_manager/native_viewport/platform_viewport_win.cc b/components/view_manager/native_viewport/platform_viewport_win.cc
index 6a48302..a5beb9c 100644
--- a/components/view_manager/native_viewport/platform_viewport_win.cc
+++ b/components/view_manager/native_viewport/platform_viewport_win.cc
@@ -5,6 +5,8 @@
 #include "components/view_manager/native_viewport/platform_viewport.h"
 
 #include "base/memory/scoped_ptr.h"
+#include "components/view_manager/native_viewport/platform_viewport_headless.h"
+#include "components/view_manager/public/interfaces/view_manager.mojom.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
 #include "mojo/converters/input_events/input_events_type_converters.h"
 #include "ui/events/event.h"
@@ -31,7 +33,7 @@
       : delegate_(delegate) {
   }
 
-  ~PlatformViewportWin() {
+  ~PlatformViewportWin() override {
     // Destroy the platform-window while |this| is still alive.
     platform_window_.reset();
   }
@@ -42,7 +44,7 @@
     metrics_ = mojo::ViewportMetrics::New();
     // TODO(sky): make density real.
     metrics_->device_pixel_ratio = 1.f;
-    metrics_->size = mojo::Size::From(bounds.size());
+    metrics_->size_in_pixels = mojo::Size::From(bounds.size());
     platform_window_.reset(new ui::WinWindow(this, bounds));
   }
 
@@ -58,7 +60,9 @@
     platform_window_->Close();
   }
 
-  gfx::Size GetSize() override { return metrics_->size.To<gfx::Size>(); }
+  gfx::Size GetSize() override {
+    return metrics_->size_in_pixels.To<gfx::Size>();
+  }
 
   void SetBounds(const gfx::Rect& bounds) override {
     platform_window_->SetBounds(bounds);
@@ -66,8 +70,9 @@
 
   // ui::PlatformWindowDelegate:
   void OnBoundsChanged(const gfx::Rect& new_bounds) override {
-    metrics_->size = mojo::Size::From(new_bounds.size());
-    delegate_->OnMetricsChanged(metrics_.Clone());
+    // TODO(fsamuel): Use the real device_scale_factor.
+    delegate_->OnMetricsChanged(new_bounds.size(),
+                                1.f /* device_scale_factor */);
   }
 
   void OnDamageRect(const gfx::Rect& damaged_region) override {
@@ -133,8 +138,11 @@
 };
 
 // static
-scoped_ptr<PlatformViewport> PlatformViewport::Create(Delegate* delegate) {
-  return scoped_ptr<PlatformViewport>(new PlatformViewportWin(delegate)).Pass();
+scoped_ptr<PlatformViewport> PlatformViewport::Create(Delegate* delegate,
+                                                      bool headless) {
+  if (headless)
+    return PlatformViewportHeadless::Create(delegate);
+  return make_scoped_ptr(new PlatformViewportWin(delegate));
 }
 
 }  // namespace native_viewport
diff --git a/components/view_manager/native_viewport/platform_viewport_x11.cc b/components/view_manager/native_viewport/platform_viewport_x11.cc
index d0f69767..c661fb5c 100644
--- a/components/view_manager/native_viewport/platform_viewport_x11.cc
+++ b/components/view_manager/native_viewport/platform_viewport_x11.cc
@@ -6,6 +6,8 @@
 
 #include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
+#include "components/view_manager/native_viewport/platform_viewport_headless.h"
+#include "components/view_manager/public/interfaces/view_manager.mojom.h"
 #include "mojo/converters/geometry/geometry_type_converters.h"
 #include "mojo/converters/input_events/input_events_type_converters.h"
 #include "mojo/converters/input_events/mojo_extended_key_event_data.h"
@@ -49,7 +51,7 @@
     metrics_ = mojo::ViewportMetrics::New();
     // TODO(sky): make density real.
     metrics_->device_pixel_ratio = 1.f;
-    metrics_->size = mojo::Size::From(bounds.size());
+    metrics_->size_in_pixels = mojo::Size::From(bounds.size());
 
     platform_window_.reset(new ui::X11Window(this));
     platform_window_->SetBounds(bounds);
@@ -61,7 +63,9 @@
 
   void Close() override { platform_window_->Close(); }
 
-  gfx::Size GetSize() override { return metrics_->size.To<gfx::Size>(); }
+  gfx::Size GetSize() override {
+    return metrics_->size_in_pixels.To<gfx::Size>();
+  }
 
   void SetBounds(const gfx::Rect& bounds) override {
     platform_window_->SetBounds(bounds);
@@ -69,8 +73,9 @@
 
   // ui::PlatformWindowDelegate:
   void OnBoundsChanged(const gfx::Rect& new_bounds) override {
-    metrics_->size = mojo::Size::From(new_bounds.size());
-    delegate_->OnMetricsChanged(metrics_.Clone());
+    // TODO(fsamuel): Use the real device_scale_factor.
+    delegate_->OnMetricsChanged(new_bounds.size(),
+                                1.f /* device_scale_factor */);
   }
 
   void OnDamageRect(const gfx::Rect& damaged_region) override {}
@@ -158,7 +163,10 @@
 };
 
 // static
-scoped_ptr<PlatformViewport> PlatformViewport::Create(Delegate* delegate) {
+scoped_ptr<PlatformViewport> PlatformViewport::Create(Delegate* delegate,
+                                                      bool headless) {
+  if (headless)
+    return PlatformViewportHeadless::Create(delegate);
   return make_scoped_ptr(new PlatformViewportX11(delegate));
 }
 
diff --git a/components/view_manager/public/cpp/lib/view.cc b/components/view_manager/public/cpp/lib/view.cc
index cc78b6cf..3497dfa 100644
--- a/components/view_manager/public/cpp/lib/view.cc
+++ b/components/view_manager/public/cpp/lib/view.cc
@@ -399,7 +399,7 @@
 
 ViewportMetricsPtr CreateEmptyViewportMetrics() {
   ViewportMetricsPtr metrics = ViewportMetrics::New();
-  metrics->size = Size::New();
+  metrics->size_in_pixels = Size::New();
   // TODO(vtl): The |.Pass()| below is only needed due to an MSVS bug; remove it
   // once that's fixed.
   return metrics.Pass();
diff --git a/components/view_manager/public/interfaces/BUILD.gn b/components/view_manager/public/interfaces/BUILD.gn
index 88330c4..09afdb9 100644
--- a/components/view_manager/public/interfaces/BUILD.gn
+++ b/components/view_manager/public/interfaces/BUILD.gn
@@ -13,7 +13,6 @@
     "display.mojom",
     "gpu.mojom",
     "gpu_capabilities.mojom",
-    "native_viewport.mojom",
     "quads.mojom",
     "surface_id.mojom",
     "surfaces.mojom",
diff --git a/components/view_manager/public/interfaces/native_viewport.mojom b/components/view_manager/public/interfaces/native_viewport.mojom
deleted file mode 100644
index 220fc535..0000000
--- a/components/view_manager/public/interfaces/native_viewport.mojom
+++ /dev/null
@@ -1,42 +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.
-
-module mojo;
-
-import "components/view_manager/public/interfaces/context_provider.mojom";
-import "ui/mojo/geometry/geometry.mojom";
-import "ui/mojo/events/input_events.mojom";
-
-struct ViewportMetrics {
-  Size size;
-  // A value of 0 indicates the real value is not yet available.
-  float device_pixel_ratio = 0.0;
-};
-
-interface NativeViewport {
-  // TODO(sky): having a create function is awkward. Should there be a factory
-  // to create the NativeViewport that takes the size?
-  Create(Size size) => (ViewportMetrics metrics);
-
-  Show();
-  Hide();
-  Close();
-  SetSize(Size size);
-  SetEventDispatcher(NativeViewportEventDispatcher dispatcher);
-
-  // Requests a ContextProvider capable of producing contexts that draw to
-  // this native viewport.
-  GetContextProvider(ContextProvider& provider);
-
-  // The initial viewport metrics will be sent in the reply to the Create
-  // method. Call RequestMetrics() to receive updates when the viewport metrics
-  // change. The reply will be sent when the viewport metrics are different from
-  // the values last sent, so to receive continuous updates call this method
-  // again after receiving the callback.
-  RequestMetrics() => (ViewportMetrics metrics);
-};
-
-interface NativeViewportEventDispatcher {
-  OnEvent(Event event) => ();
-};
diff --git a/components/view_manager/public/interfaces/view_manager.mojom b/components/view_manager/public/interfaces/view_manager.mojom
index a20533fd..70afc08 100644
--- a/components/view_manager/public/interfaces/view_manager.mojom
+++ b/components/view_manager/public/interfaces/view_manager.mojom
@@ -5,13 +5,18 @@
 module mojo;
 
 import "components/view_manager/public/interfaces/surface_id.mojom";
-import "components/view_manager/public/interfaces/native_viewport.mojom";
 import "components/view_manager/public/interfaces/view_manager_constants.mojom";
 import "mojo/application/public/interfaces/service_provider.mojom";
 import "network/public/interfaces/url_loader.mojom";
 import "ui/mojo/events/input_events.mojom";
 import "ui/mojo/geometry/geometry.mojom";
 
+struct ViewportMetrics {
+  Size size_in_pixels;
+  // A value of 0 indicates the real value is not yet available.
+  float device_pixel_ratio = 0.0;
+};
+
 struct ViewData {
   uint32 parent_id;
   uint32 view_id;
diff --git a/components/view_manager/view_manager_app.cc b/components/view_manager/view_manager_app.cc
index 4a3949a..0dac932b 100644
--- a/components/view_manager/view_manager_app.cc
+++ b/components/view_manager/view_manager_app.cc
@@ -8,7 +8,6 @@
 #include "components/view_manager/client_connection.h"
 #include "components/view_manager/connection_manager.h"
 #include "components/view_manager/display_manager.h"
-#include "components/view_manager/native_viewport/native_viewport_impl.h"
 #include "components/view_manager/public/cpp/args.h"
 #include "components/view_manager/view_manager_service_impl.h"
 #include "mojo/application/public/cpp/application_connection.h"
@@ -24,13 +23,12 @@
 using mojo::ApplicationImpl;
 using mojo::Gpu;
 using mojo::InterfaceRequest;
-using mojo::NativeViewport;
 using mojo::ViewManagerRoot;
 using mojo::ViewManagerService;
 
 namespace view_manager {
 
-ViewManagerApp::ViewManagerApp() : app_impl_(nullptr) {
+ViewManagerApp::ViewManagerApp() : app_impl_(nullptr), is_headless_(false) {
 }
 
 ViewManagerApp::~ViewManagerApp() {}
@@ -39,12 +37,6 @@
   app_impl_ = app;
   tracing_.Initialize(app);
 
-  scoped_ptr<DefaultDisplayManager> display_manager(new DefaultDisplayManager(
-      app_impl_, base::Bind(&ViewManagerApp::OnLostConnectionToWindowManager,
-                            base::Unretained(this))));
-  connection_manager_.reset(
-      new ConnectionManager(this, display_manager.Pass()));
-
 #if !defined(OS_ANDROID)
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   is_headless_ = command_line->HasSwitch(mojo::kUseHeadlessConfig);
@@ -56,6 +48,17 @@
       gfx::GLSurface::InitializeOneOff();
   }
 #endif
+
+  if (!gpu_state_.get())
+    gpu_state_ = new gles2::GpuState;
+  scoped_ptr<DefaultDisplayManager> display_manager(new DefaultDisplayManager(
+      is_headless_,
+      app_impl_,
+      gpu_state_,
+      base::Bind(&ViewManagerApp::OnLostConnectionToWindowManager,
+                 base::Unretained(this))));
+  connection_manager_.reset(
+      new ConnectionManager(this, display_manager.Pass()));
 }
 
 bool ViewManagerApp::ConfigureIncomingConnection(
@@ -65,7 +68,6 @@
   // to the ViewManager.
   connection->AddService<ViewManagerService>(this);
   connection->AddService<ViewManagerRoot>(this);
-  connection->AddService<NativeViewport>(this);
   connection->AddService<Gpu>(this);
 
   return true;
@@ -141,18 +143,6 @@
 
 void ViewManagerApp::Create(
     mojo::ApplicationConnection* connection,
-    mojo::InterfaceRequest<NativeViewport> request) {
-  if (!gpu_state_.get())
-    gpu_state_ = new gles2::GpuState;
-  new native_viewport::NativeViewportImpl(
-      is_headless_,
-      gpu_state_,
-      request.Pass(),
-      app_impl_->app_lifetime_helper()->CreateAppRefCount());
-}
-
-void ViewManagerApp::Create(
-    mojo::ApplicationConnection* connection,
     mojo::InterfaceRequest<Gpu> request) {
   if (!gpu_state_.get())
     gpu_state_ = new gles2::GpuState;
diff --git a/components/view_manager/view_manager_app.h b/components/view_manager/view_manager_app.h
index 1a39c28..a2fa9dd6 100644
--- a/components/view_manager/view_manager_app.h
+++ b/components/view_manager/view_manager_app.h
@@ -8,7 +8,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "components/view_manager/connection_manager_delegate.h"
 #include "components/view_manager/gles2/gpu_impl.h"
-#include "components/view_manager/public/interfaces/native_viewport.mojom.h"
 #include "components/view_manager/public/interfaces/view_manager.mojom.h"
 #include "components/view_manager/public/interfaces/view_manager_root.mojom.h"
 #include "mojo/application/public/cpp/app_lifetime_helper.h"
@@ -33,7 +32,6 @@
                        public mojo::ErrorHandler,
                        public mojo::InterfaceFactory<mojo::ViewManagerRoot>,
                        public mojo::InterfaceFactory<mojo::ViewManagerService>,
-                       public mojo::InterfaceFactory<mojo::NativeViewport>,
                        public mojo::InterfaceFactory<mojo::Gpu> {
  public:
   ViewManagerApp();
@@ -71,10 +69,6 @@
   void Create(mojo::ApplicationConnection* connection,
               mojo::InterfaceRequest<mojo::ViewManagerRoot> request) override;
 
-  // mojo::InterfaceFactory<mojo::NativeViewport> implementation.
-  void Create(mojo::ApplicationConnection* connection,
-              mojo::InterfaceRequest<mojo::NativeViewport> request) override;
-
   // mojo::InterfaceFactory<mojo::Gpu> implementation.
   void Create(mojo::ApplicationConnection* connection,
               mojo::InterfaceRequest<mojo::Gpu> request) override;
diff --git a/components/view_manager/view_manager_service_unittest.cc b/components/view_manager/view_manager_service_unittest.cc
index 970b47e..6166449 100644
--- a/components/view_manager/view_manager_service_unittest.cc
+++ b/components/view_manager/view_manager_service_unittest.cc
@@ -184,7 +184,7 @@
 
   // DisplayManager:
   void Init(ConnectionManager* connection_manager,
-            mojo::NativeViewportEventDispatcherPtr event_dispatcher) override {}
+            EventDispatcher* event_dispatcher) override {}
   void SchedulePaint(const ServerView* view, const gfx::Rect& bounds) override {
   }
   void SetViewportSize(const gfx::Size& size) override {}
diff --git a/components/visitedlink/test/visitedlink_unittest.cc b/components/visitedlink/test/visitedlink_unittest.cc
index 1b0454d..f663f83 100644
--- a/components/visitedlink/test/visitedlink_unittest.cc
+++ b/components/visitedlink/test/visitedlink_unittest.cc
@@ -680,7 +680,7 @@
 }
 
 TEST_F(VisitedLinkEventsTest, Basics) {
-  RenderViewHostTester::For(rvh())->CreateRenderView(
+  RenderViewHostTester::For(rvh())->CreateTestRenderView(
       base::string16(), MSG_ROUTING_NONE, MSG_ROUTING_NONE, -1, false);
 
   // Add a few URLs.
@@ -704,7 +704,7 @@
 }
 
 TEST_F(VisitedLinkEventsTest, TabVisibility) {
-  RenderViewHostTester::For(rvh())->CreateRenderView(
+  RenderViewHostTester::For(rvh())->CreateTestRenderView(
       base::string16(), MSG_ROUTING_NONE, MSG_ROUTING_NONE, -1, false);
 
   // Simulate tab becoming inactive.
diff --git a/components/webdata_services/web_data_service_wrapper.cc b/components/webdata_services/web_data_service_wrapper.cc
index 73d48e7..d1aeea8 100644
--- a/components/webdata_services/web_data_service_wrapper.cc
+++ b/components/webdata_services/web_data_service_wrapper.cc
@@ -11,6 +11,7 @@
 #include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/password_manager/core/browser/webdata/logins_table.h"
@@ -47,6 +48,9 @@
       autofill_web_data.get(), autofill_backend, app_locale);
   autofill::AutofillWalletSyncableService::CreateForWebDataServiceAndBackend(
       autofill_web_data.get(), autofill_backend, app_locale);
+  autofill::AutofillWalletMetadataSyncableService::
+      CreateForWebDataServiceAndBackend(autofill_web_data.get(),
+                                        autofill_backend, app_locale);
 
   autofill::AutofillProfileSyncableService::FromWebDataService(
       autofill_web_data.get())->InjectStartSyncFlare(sync_flare);
diff --git a/components/webui_generator/generator/wug.gni b/components/webui_generator/generator/wug.gni
index 28009a0..e088e5d9 100644
--- a/components/webui_generator/generator/wug.gni
+++ b/components/webui_generator/generator/wug.gni
@@ -8,7 +8,11 @@
 # Parameters:
 #
 #   source (required)
-#      declaration file.
+#      Declaration file.
+#
+#   deps (optional)
+#   visibility (optional)
+#      Normal meanings.
 #
 # Example:
 # wug("some_type_wug_generated") {
@@ -36,6 +40,7 @@
   helper_path = "$generator_dir/build_helper.py"
   target_name = "${target_name}"
   action_name = target_name + "_gen"
+  group_name = target_name
   out_dir = "$root_gen_dir/wug"
 
   helper_args = [
@@ -55,6 +60,8 @@
              "', got '" + target_name + "'.")
 
   action(action_name) {
+    visibility = [ ":$group_name" ]
+
     script = generator_path
     sources = [
       "$generator_dir/declaration.py",
@@ -87,14 +94,26 @@
       "--destination",
       rebase_path(out_dir, root_build_dir),
     ]
+
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+    if (defined(invoker.public_deps)) {
+      public_deps = invoker.public_deps
+    }
   }
 
-  component(target_name) {
+  source_set(target_name) {
+    if (defined(invoker.visibility)) {
+      visibility = invoker.visibility
+    }
+
     sources = get_target_outputs(":$action_name")
     defines = [ exec_script(helper_path,
                             helper_args + [ "impl_macro" ],
                             "trim string") ]
     deps = [
+      ":$action_name",
       "//base",
       "//components/login",
       "//components/strings",
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc
index e4f8812d..1a39863 100644
--- a/content/app/content_main_runner.cc
+++ b/content/app/content_main_runner.cc
@@ -741,17 +741,23 @@
 #endif  // !OS_ANDROID
     int v8_natives_fd = g_fds->MaybeGet(kV8NativesDataDescriptor);
     int v8_snapshot_fd = g_fds->MaybeGet(kV8SnapshotDataDescriptor);
-    if (v8_natives_fd != -1 && v8_snapshot_fd != -1) {
-      auto v8_natives_region = g_fds->GetRegion(kV8NativesDataDescriptor);
+    if (v8_snapshot_fd != -1) {
       auto v8_snapshot_region = g_fds->GetRegion(kV8SnapshotDataDescriptor);
-      CHECK(gin::V8Initializer::LoadV8SnapshotFromFD(
-          v8_natives_fd, v8_natives_region.offset, v8_natives_region.size,
-          v8_snapshot_fd, v8_snapshot_region.offset, v8_snapshot_region.size));
+      gin::V8Initializer::LoadV8SnapshotFromFD(
+          v8_snapshot_fd, v8_snapshot_region.offset, v8_snapshot_region.size);
     } else {
-      CHECK(gin::V8Initializer::LoadV8Snapshot());
+      gin::V8Initializer::LoadV8Snapshot();
+    }
+    if (v8_natives_fd != -1) {
+      auto v8_natives_region = g_fds->GetRegion(kV8NativesDataDescriptor);
+      gin::V8Initializer::LoadV8NativesFromFD(
+          v8_natives_fd, v8_natives_region.offset, v8_natives_region.size);
+    } else {
+      gin::V8Initializer::LoadV8Natives();
     }
 #else
-    CHECK(gin::V8Initializer::LoadV8Snapshot());
+    gin::V8Initializer::LoadV8Snapshot();
+    gin::V8Initializer::LoadV8Natives();
 #endif  // OS_POSIX && !OS_MACOSX
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
 
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 71083b9..a8bcd7a 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -29,14 +29,20 @@
     "//content/browser/service_worker:service_worker_proto",
     "//content/browser/speech/proto",
     "//content/public/common:common_sources",
+    "//content/public/common:mojo_bindings",
     "//crypto",
     "//device/battery",
     "//device/vibration",
     "//google_apis",
+    "//mojo/application/public/cpp:cpp_for_chromium",
+    "//mojo/application/public/interfaces",
+    "//mojo/common",
+    "//mojo/shell",
     "//net",
     "//net:extras",
     "//skia",
     "//sql",
+    "//third_party/mojo/src/mojo/public/cpp/bindings",
     "//third_party/npapi",
     "//third_party/re2",
     "//third_party/WebKit/public:blink_headers",
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index ec252f5e..6a9c041 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -111,6 +111,8 @@
     return [](BrowserAccessibility* start, BrowserAccessibility* current) {
       if (current->IsWebAreaForPresentationalIframe())
         return false;
+      if (!current->GetParent())
+        return false;
       return (current->GetRole() == ui::AX_ROLE_WEB_AREA ||
               current->GetRole() == ui::AX_ROLE_ROOT_WEB_AREA);
     };
@@ -1890,12 +1892,8 @@
     [self delegate]->AccessibilityDoDefaultAction(
         browserAccessibility_->GetId());
   } else if ([action isEqualToString:NSAccessibilityShowMenuAction]) {
-    NSPoint objOrigin = [self origin];
-    NSSize size = [[self size] sizeValue];
-    gfx::Point origin = [self delegate]->AccessibilityOriginInScreen(
-        gfx::Rect(objOrigin.x, objOrigin.y, size.width, size.height));
-    origin.Offset(size.width / 2, size.height / 2);
-    [self delegate]->AccessibilityShowMenu(origin);
+    [self delegate]->AccessibilityShowContextMenu(
+        browserAccessibility_->GetId());
   }
 }
 
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
index b7a74d9..48c9b1e 100644
--- a/content/browser/accessibility/browser_accessibility_manager.h
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -54,7 +54,7 @@
   virtual ~BrowserAccessibilityDelegate() {}
   virtual void AccessibilitySetFocus(int acc_obj_id) = 0;
   virtual void AccessibilityDoDefaultAction(int acc_obj_id) = 0;
-  virtual void AccessibilityShowMenu(const gfx::Point& global_point) = 0;
+  virtual void AccessibilityShowContextMenu(int acc_obj_id) = 0;
   virtual void AccessibilityScrollToMakeVisible(
       int acc_obj_id, const gfx::Rect& subfocus) = 0;
   virtual void AccessibilityScrollToPoint(
diff --git a/content/browser/accessibility/browser_accessibility_manager_unittest.cc b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
index 544d42d5..2027c12 100644
--- a/content/browser/accessibility/browser_accessibility_manager_unittest.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_unittest.cc
@@ -65,7 +65,7 @@
 
   void AccessibilitySetFocus(int acc_obj_id) override {}
   void AccessibilityDoDefaultAction(int acc_obj_id) override {}
-  void AccessibilityShowMenu(const gfx::Point& point) override {}
+  void AccessibilityShowContextMenu(int acc_obj_id) override {}
   void AccessibilityScrollToMakeVisible(int acc_obj_id,
                                         const gfx::Rect& subfocus) override {}
   void AccessibilityScrollToPoint(int acc_obj_id,
diff --git a/content/browser/android/browser_jni_registrar.cc b/content/browser/android/browser_jni_registrar.cc
index eaf9b46..808e3f3e 100644
--- a/content/browser/android/browser_jni_registrar.cc
+++ b/content/browser/android/browser_jni_registrar.cc
@@ -79,6 +79,8 @@
     {"MediaSession", content::MediaSession::RegisterMediaSession},
     {"MotionEventAndroid",
      content::MotionEventAndroid::RegisterMotionEventAndroid},
+    {"MotionEventSynthesizer",
+     content::SyntheticGestureTargetAndroid::RegisterMotionEventSynthesizer},
     {"NavigationControllerAndroid",
      content::NavigationControllerAndroid::Register},
     {"PopupTouchHandleDrawable",
@@ -93,8 +95,6 @@
     {"SpeechRecognizerImplAndroid",
      content::SpeechRecognizerImplAndroid::RegisterSpeechRecognizer},
     {"TimeZoneMonitorAndroid", content::TimeZoneMonitorAndroid::Register},
-    {"TouchEventSynthesizer",
-     content::SyntheticGestureTargetAndroid::RegisterTouchEventSynthesizer},
     {"TracingControllerAndroid", content::RegisterTracingControllerAndroid},
     {"WebContentsAndroid", content::WebContentsAndroid::Register},
     {"WebContentsObserver", content::RegisterWebContentsObserverProxy},
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index ead8407..a47ded2 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -695,13 +695,14 @@
                                                java_bitmap.obj());
 }
 
-ScopedJavaLocalRef<jobject> ContentViewCoreImpl::CreateTouchEventSynthesizer() {
+ScopedJavaLocalRef<jobject>
+ContentViewCoreImpl::CreateMotionEventSynthesizer() {
   JNIEnv* env = AttachCurrentThread();
 
   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
   if (obj.is_null())
     return ScopedJavaLocalRef<jobject>();
-  return Java_ContentViewCore_createTouchEventSynthesizer(env, obj.obj());
+  return Java_ContentViewCore_createMotionEventSynthesizer(env, obj.obj());
 }
 
 bool ContentViewCoreImpl::ShouldBlockMediaRequest(const GURL& url) {
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h
index 0ca7c64..a4e1bddc 100644
--- a/content/browser/android/content_view_core_impl.h
+++ b/content/browser/android/content_view_core_impl.h
@@ -257,9 +257,9 @@
   void ShowDisambiguationPopup(
       const gfx::Rect& rect_pixels, const SkBitmap& zoomed_bitmap);
 
-  // Creates a java-side touch event, used for injecting touch event for
-  // testing/benchmarking purposes
-  base::android::ScopedJavaLocalRef<jobject> CreateTouchEventSynthesizer();
+  // Creates a java-side touch event, used for injecting motion events for
+  // testing/benchmarking purposes.
+  base::android::ScopedJavaLocalRef<jobject> CreateMotionEventSynthesizer();
 
   // Returns True if the given media should be blocked to load.
   bool ShouldBlockMediaRequest(const GURL& url);
diff --git a/content/browser/android/in_process/synchronous_compositor_factory_impl.cc b/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
index a57f8d4..f4df3bc7 100644
--- a/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
+++ b/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/observer_list.h"
+#include "base/sys_info.h"
 #include "base/thread_task_runner_handle.h"
 #include "content/browser/android/in_process/context_provider_in_process.h"
 #include "content/browser/android/in_process/synchronous_compositor_external_begin_frame_source.h"
@@ -180,7 +181,12 @@
   gpu::GLInProcessContextSharedMemoryLimits mem_limits;
   // This is half of what RenderWidget uses because synchronous compositor
   // pipeline is only one frame deep.
-  mem_limits.mapped_memory_reclaim_limit = 6 * 1024 * 1024;
+  if (base::SysInfo::IsLowEndDevice()) {
+    // But twice of half here because 16bit texture is not supported.
+    mem_limits.mapped_memory_reclaim_limit = 2 * 1024 * 1024;
+  } else {
+    mem_limits.mapped_memory_reclaim_limit = 6 * 1024 * 1024;
+  }
   ContextHolder holder =
       CreateContextHolder(attributes, nullptr, mem_limits, true);
   return ContextProviderInProcess::Create(holder.command_buffer.Pass(),
diff --git a/content/browser/android/in_process/synchronous_compositor_impl.cc b/content/browser/android/in_process/synchronous_compositor_impl.cc
index 5963ac5..4329ce5 100644
--- a/content/browser/android/in_process/synchronous_compositor_impl.cc
+++ b/content/browser/android/in_process/synchronous_compositor_impl.cc
@@ -274,7 +274,9 @@
 }
 
 void SynchronousCompositorImpl::BeginFrame(const cc::BeginFrameArgs& args) {
-  if (!registered_with_client_) {
+  if (!registered_with_client_ && is_active_ && renderer_needs_begin_frames_) {
+    // Make sure this is a BeginFrame that renderer side explicitly requested.
+    // Otherwise it is possible renderer objects not initialized.
     RegisterWithClient();
     DCHECK(registered_with_client_);
   }
diff --git a/content/browser/android/in_process/synchronous_compositor_output_surface.cc b/content/browser/android/in_process/synchronous_compositor_output_surface.cc
index 1e61994..95d82804 100644
--- a/content/browser/android/in_process/synchronous_compositor_output_surface.cc
+++ b/content/browser/android/in_process/synchronous_compositor_output_surface.cc
@@ -16,6 +16,7 @@
 #include "content/browser/gpu/compositor_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/renderer/gpu/frame_swap_message_queue.h"
+#include "gpu/command_buffer/client/context_support.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "third_party/skia/include/core/SkCanvas.h"
@@ -243,11 +244,22 @@
 
 void SynchronousCompositorOutputSurface::SetMemoryPolicy(size_t bytes_limit) {
   DCHECK(CalledOnValidThread());
+  bool became_zero = memory_policy_.bytes_limit_when_visible && !bytes_limit;
+  bool became_non_zero =
+      !memory_policy_.bytes_limit_when_visible && bytes_limit;
   memory_policy_.bytes_limit_when_visible = bytes_limit;
   memory_policy_.num_resources_limit = kNumResourcesLimit;
 
   if (client_)
     client_->SetMemoryPolicy(memory_policy_);
+
+  if (became_zero) {
+    // This is small hack to drop context resources without destroying it
+    // when this compositor is put into the background.
+    context_provider()->ContextSupport()->SetSurfaceVisible(false);
+  } else if (became_non_zero) {
+    context_provider()->ContextSupport()->SetSurfaceVisible(true);
+  }
 }
 
 void SynchronousCompositorOutputSurface::SetTreeActivationCallback(
diff --git a/content/browser/appcache/appcache_group.cc b/content/browser/appcache/appcache_group.cc
index 4e16e7f..dbd089c 100644
--- a/content/browser/appcache/appcache_group.cc
+++ b/content/browser/appcache/appcache_group.cc
@@ -7,8 +7,10 @@
 #include <algorithm>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_host.h"
 #include "content/browser/appcache/appcache_service_impl.h"
@@ -230,9 +232,8 @@
   DCHECK(restart_update_task_.IsCancelled());
   restart_update_task_.Reset(
       base::Bind(&AppCacheGroup::RunQueuedUpdates, this));
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      restart_update_task_.callback(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, restart_update_task_.callback(),
       base::TimeDelta::FromMilliseconds(delay_ms));
 }
 
diff --git a/content/browser/appcache/appcache_quota_client_unittest.cc b/content/browser/appcache/appcache_quota_client_unittest.cc
index a453ee1c..de173240 100644
--- a/content/browser/appcache/appcache_quota_client_unittest.cc
+++ b/content/browser/appcache/appcache_quota_client_unittest.cc
@@ -6,7 +6,6 @@
 #include <set>
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
 #include "content/browser/appcache/appcache_quota_client.h"
 #include "content/browser/appcache/mock_appcache_service.h"
diff --git a/content/browser/appcache/appcache_request_handler_unittest.cc b/content/browser/appcache/appcache_request_handler_unittest.cc
index f05fed29..3dbaf85 100644
--- a/content/browser/appcache/appcache_request_handler_unittest.cc
+++ b/content/browser/appcache/appcache_request_handler_unittest.cc
@@ -9,8 +9,10 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_backend_impl.h"
@@ -180,7 +182,7 @@
   template <class Method>
   void RunTestOnIOThread(Method method) {
     test_finished_event_ .reset(new base::WaitableEvent(false, false));
-    io_thread_->message_loop()->PostTask(
+    io_thread_->task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&AppCacheRequestHandlerTest::MethodWrapper<Method>,
                    base::Unretained(this), method));
@@ -221,10 +223,9 @@
     // We unwind the stack prior to finishing up to let stack
     // based objects get deleted.
     DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&AppCacheRequestHandlerTest::TestFinishedUnwound,
-                   base::Unretained(this)));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&AppCacheRequestHandlerTest::TestFinishedUnwound,
+                              base::Unretained(this)));
   }
 
   void TestFinishedUnwound() {
@@ -242,7 +243,7 @@
       TestFinished();
       return;
     }
-    base::MessageLoop::current()->PostTask(FROM_HERE, task_stack_.top());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task_stack_.top());
     task_stack_.pop();
   }
 
diff --git a/content/browser/appcache/appcache_response.cc b/content/browser/appcache/appcache_response.cc
index 66ec22e..f113adf9 100644
--- a/content/browser/appcache/appcache_response.cc
+++ b/content/browser/appcache/appcache_response.cc
@@ -7,12 +7,14 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
 #include "base/numerics/safe_math.h"
 #include "base/pickle.h"
 #include "base/profiler/scoped_tracker.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/appcache/appcache_storage.h"
 #include "net/base/completion_callback.h"
 #include "net/base/io_buffer.h"
@@ -90,7 +92,7 @@
 }
 
 void AppCacheResponseIO::ScheduleIOCompletionCallback(int result) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&AppCacheResponseIO::OnIOComplete,
                             weak_factory_.GetWeakPtr(), result));
 }
diff --git a/content/browser/appcache/appcache_response_unittest.cc b/content/browser/appcache/appcache_response_unittest.cc
index f5eb417d..743a6245 100644
--- a/content/browser/appcache/appcache_response_unittest.cc
+++ b/content/browser/appcache/appcache_response_unittest.cc
@@ -10,8 +10,11 @@
 #include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/pickle.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "content/browser/appcache/appcache_response.h"
 #include "content/browser/appcache/mock_appcache_service.h"
@@ -75,7 +78,7 @@
   template <class Method>
   void RunTestOnIOThread(Method method) {
     test_finished_event_ .reset(new base::WaitableEvent(false, false));
-    io_thread_->message_loop()->PostTask(
+    io_thread_->task_runner()->PostTask(
         FROM_HERE, base::Bind(&AppCacheResponseTest::MethodWrapper<Method>,
                               base::Unretained(this), method));
     test_finished_event_->Wait();
@@ -116,7 +119,7 @@
     // We unwind the stack prior to finishing up to let stack
     // based objects get deleted.
     DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&AppCacheResponseTest::TestFinishedUnwound,
                               base::Unretained(this)));
   }
@@ -146,7 +149,7 @@
     if (immediate)
       task.Run();
     else
-      base::MessageLoop::current()->PostTask(FROM_HERE, task);
+      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task);
   }
 
   // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
@@ -736,7 +739,7 @@
     reader_.reset();
 
     // Wait a moment to verify no callbacks.
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, base::Bind(&AppCacheResponseTest::VerifyNoCallbacks,
                               base::Unretained(this)),
         base::TimeDelta::FromMilliseconds(10));
diff --git a/content/browser/appcache/appcache_service_impl.cc b/content/browser/appcache/appcache_service_impl.cc
index 0c784df..47e81a4 100644
--- a/content/browser/appcache/appcache_service_impl.cc
+++ b/content/browser/appcache/appcache_service_impl.cc
@@ -8,10 +8,11 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_backend_impl.h"
 #include "content/browser/appcache/appcache_entry.h"
@@ -63,7 +64,7 @@
   void CallCallback(int rv) {
     if (!callback_.is_null()) {
       // Defer to guarantee async completion.
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, base::Bind(&DeferredCallback, callback_, rv));
     }
     callback_.Reset();
diff --git a/content/browser/appcache/appcache_service_unittest.cc b/content/browser/appcache/appcache_service_unittest.cc
index 41592457..62e6a4d 100644
--- a/content/browser/appcache/appcache_service_unittest.cc
+++ b/content/browser/appcache/appcache_service_unittest.cc
@@ -6,8 +6,11 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/pickle.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/appcache/appcache_response.h"
 #include "content/browser/appcache/appcache_service_impl.h"
 #include "content/browser/appcache/mock_appcache_storage.h"
@@ -67,9 +70,9 @@
 
  private:
   void ScheduleUserCallback(int result) {
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-        base::Bind(&MockResponseReader::InvokeUserCompletionCallback,
-                   weak_factory_.GetWeakPtr(), result));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&MockResponseReader::InvokeUserCompletionCallback,
+                              weak_factory_.GetWeakPtr(), result));
   }
 
   scoped_ptr<net::HttpResponseInfo> info_;
diff --git a/content/browser/appcache/appcache_storage_impl.cc b/content/browser/appcache/appcache_storage_impl.cc
index 3653488..7494f5a 100644
--- a/content/browser/appcache/appcache_storage_impl.cc
+++ b/content/browser/appcache/appcache_storage_impl.cc
@@ -12,12 +12,13 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_database.h"
 #include "content/browser/appcache/appcache_entry.h"
@@ -136,8 +137,9 @@
     : public base::RefCountedThreadSafe<DatabaseTask> {
  public:
   explicit DatabaseTask(AppCacheStorageImpl* storage)
-      : storage_(storage), database_(storage->database_),
-        io_thread_(base::MessageLoopProxy::current()) {
+      : storage_(storage),
+        database_(storage->database_),
+        io_thread_(base::ThreadTaskRunnerHandle::Get()) {
     DCHECK(io_thread_.get());
   }
 
@@ -178,7 +180,7 @@
   void CallRunCompleted(base::TimeTicks schedule_time);
   void OnFatalError();
 
-  scoped_refptr<base::MessageLoopProxy> io_thread_;
+  scoped_refptr<base::SingleThreadTaskRunner> io_thread_;
 };
 
 void AppCacheStorageImpl::DatabaseTask::Schedule() {
@@ -314,7 +316,7 @@
   if (!storage_->is_disabled()) {
     storage_->usage_map_.swap(usage_map_);
     const base::TimeDelta kDelay = base::TimeDelta::FromMinutes(5);
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&AppCacheStorageImpl::DelayedStartDeletingUnusedResponses,
                    storage_->weak_factory_.GetWeakPtr()),
@@ -1738,10 +1740,9 @@
 void AppCacheStorageImpl::ScheduleDeleteOneResponse() {
   DCHECK(!is_response_deletion_scheduled_);
   const base::TimeDelta kBriefDelay = base::TimeDelta::FromMilliseconds(10);
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&AppCacheStorageImpl::DeleteOneResponse,
-                 weak_factory_.GetWeakPtr()),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&AppCacheStorageImpl::DeleteOneResponse,
+                            weak_factory_.GetWeakPtr()),
       kBriefDelay);
   is_response_deletion_scheduled_ = true;
 }
@@ -1824,10 +1825,9 @@
 
 void AppCacheStorageImpl::ScheduleSimpleTask(const base::Closure& task) {
   pending_simple_tasks_.push_back(task);
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&AppCacheStorageImpl::RunOnePendingSimpleTask,
-                 weak_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&AppCacheStorageImpl::RunOnePendingSimpleTask,
+                            weak_factory_.GetWeakPtr()));
 }
 
 void AppCacheStorageImpl::RunOnePendingSimpleTask() {
diff --git a/content/browser/appcache/appcache_storage_impl_unittest.cc b/content/browser/appcache/appcache_storage_impl_unittest.cc
index 37c295d..9c980da 100644
--- a/content/browser/appcache/appcache_storage_impl_unittest.cc
+++ b/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -9,9 +9,11 @@
 #include "base/callback.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_backend_impl.h"
@@ -269,8 +271,8 @@
     MockQuotaManager()
         : QuotaManager(true /* is_incognito */,
                        base::FilePath(),
-                       io_thread->message_loop_proxy().get(),
-                       db_thread->message_loop_proxy().get(),
+                       io_thread->task_runner().get(),
+                       db_thread->task_runner().get(),
                        NULL),
           async_(false) {}
 
@@ -279,11 +281,9 @@
                           const GetUsageAndQuotaCallback& callback) override {
       EXPECT_EQ(storage::kStorageTypeTemporary, type);
       if (async_) {
-        base::MessageLoop::current()->PostTask(
-            FROM_HERE,
-            base::Bind(&MockQuotaManager::CallCallback,
-                       base::Unretained(this),
-                       callback));
+        base::ThreadTaskRunnerHandle::Get()->PostTask(
+            FROM_HERE, base::Bind(&MockQuotaManager::CallCallback,
+                                  base::Unretained(this), callback));
         return;
       }
       CallCallback(callback);
@@ -370,11 +370,9 @@
     // We also have to wait for InitTask completion call to be performed
     // on the IO thread prior to running the test. Its guaranteed to be
     // queued by this time.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&AppCacheStorageImplTest::RunMethod<Method>,
-                   base::Unretained(this),
-                   method));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&AppCacheStorageImplTest::RunMethod<Method>,
+                              base::Unretained(this), method));
   }
 
   static void SetUpTestCase() {
@@ -400,7 +398,7 @@
   template <class Method>
   void RunTestOnIOThread(Method method) {
     test_finished_event_ .reset(new base::WaitableEvent(false, false));
-    io_thread->message_loop()->PostTask(
+    io_thread->task_runner()->PostTask(
         FROM_HERE, base::Bind(&AppCacheStorageImplTest::MethodWrapper<Method>,
                               base::Unretained(this), method));
     test_finished_event_->Wait();
@@ -431,10 +429,9 @@
     // We unwind the stack prior to finishing up to let stack
     // based objects get deleted.
     DCHECK(base::MessageLoop::current() == io_thread->message_loop());
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&AppCacheStorageImplTest::TestFinishedUnwound,
-                   base::Unretained(this)));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&AppCacheStorageImplTest::TestFinishedUnwound,
+                              base::Unretained(this)));
   }
 
   void TestFinishedUnwound() {
@@ -451,7 +448,7 @@
     if (task_stack_.empty()) {
       return;
     }
-    base::MessageLoop::current()->PostTask(FROM_HERE, task_stack_.top());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task_stack_.top());
     task_stack_.pop();
   }
 
@@ -463,7 +460,7 @@
     // We pump a task thru the db thread to ensure any tasks previously
     // scheduled on that thread have been performed prior to return.
     base::WaitableEvent event(false, false);
-    db_thread->message_loop()->PostTask(
+    db_thread->task_runner()->PostTask(
         FROM_HERE, base::Bind(&AppCacheStorageImplTest::SignalEvent, &event));
     event.Wait();
   }
@@ -1732,11 +1729,9 @@
     // We continue after the init task is complete including the callback
     // on the current thread.
     FlushDbThreadTasks();
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&AppCacheStorageImplTest::Continue_Reinitialize,
-                   base::Unretained(this),
-                   test_case));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&AppCacheStorageImplTest::Continue_Reinitialize,
+                              base::Unretained(this), test_case));
   }
 
   void Continue_Reinitialize(ReinitTestCase test_case) {
diff --git a/content/browser/appcache/appcache_update_job_unittest.cc b/content/browser/appcache/appcache_update_job_unittest.cc
index b69af526..c5ddf4f 100644
--- a/content/browser/appcache/appcache_update_job_unittest.cc
+++ b/content/browser/appcache/appcache_update_job_unittest.cc
@@ -4,8 +4,11 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "content/browser/appcache/appcache_group.h"
 #include "content/browser/appcache/appcache_host.h"
@@ -603,7 +606,7 @@
   template <class Method>
   void RunTestOnIOThread(Method method) {
     event_.reset(new base::WaitableEvent(false, false));
-    io_thread_->message_loop()->PostTask(
+    io_thread_->task_runner()->PostTask(
         FROM_HERE, base::Bind(method, base::Unretained(this)));
 
     // Wait until task is done before exiting the test.
@@ -2983,10 +2986,9 @@
   void UpdateFinished() {
     // We unwind the stack prior to finishing up to let stack-based objects
     // get deleted.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&AppCacheUpdateJobTest::UpdateFinishedUnwound,
-                   base::Unretained(this)));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&AppCacheUpdateJobTest::UpdateFinishedUnwound,
+                              base::Unretained(this)));
   }
 
   void UpdateFinishedUnwound() {
diff --git a/content/browser/appcache/appcache_url_request_job.cc b/content/browser/appcache/appcache_url_request_job.cc
index 9bf70e7..d66c795c 100644
--- a/content/browser/appcache/appcache_url_request_job.cc
+++ b/content/browser/appcache/appcache_url_request_job.cc
@@ -10,9 +10,11 @@
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_group.h"
 #include "content/browser/appcache/appcache_histograms.h"
@@ -79,10 +81,9 @@
   if (has_been_started() && has_delivery_orders()) {
     // Start asynchronously so that all error reporting and data
     // callbacks happen as they would for network requests.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&AppCacheURLRequestJob::BeginDelivery,
-                   weak_factory_.GetWeakPtr()));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&AppCacheURLRequestJob::BeginDelivery,
+                              weak_factory_.GetWeakPtr()));
   }
 }
 
diff --git a/content/browser/appcache/appcache_url_request_job_unittest.cc b/content/browser/appcache/appcache_url_request_job_unittest.cc
index fdd1c9b..0e27295 100644
--- a/content/browser/appcache/appcache_url_request_job_unittest.cc
+++ b/content/browser/appcache/appcache_url_request_job_unittest.cc
@@ -9,10 +9,13 @@
 #include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/pickle.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "content/browser/appcache/appcache_response.h"
 #include "content/browser/appcache/appcache_url_request_job.h"
@@ -217,7 +220,7 @@
   template <class Method>
   void RunTestOnIOThread(Method method) {
     test_finished_event_ .reset(new base::WaitableEvent(false, false));
-    io_thread_->message_loop()->PostTask(
+    io_thread_->task_runner()->PostTask(
         FROM_HERE, base::Bind(&AppCacheURLRequestJobTest::MethodWrapper<Method>,
                               base::Unretained(this), method));
     test_finished_event_->Wait();
@@ -267,10 +270,9 @@
     // We unwind the stack prior to finishing up to let stack
     // based objects get deleted.
     DCHECK(base::MessageLoop::current() == io_thread_->message_loop());
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&AppCacheURLRequestJobTest::TestFinishedUnwound,
-                   base::Unretained(this)));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&AppCacheURLRequestJobTest::TestFinishedUnwound,
+                              base::Unretained(this)));
   }
 
   void TestFinishedUnwound() {
@@ -298,7 +300,7 @@
     if (immediate)
       task.Run();
     else
-      base::MessageLoop::current()->PostTask(FROM_HERE, task);
+      base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task);
   }
 
   // Wrappers to call AppCacheResponseReader/Writer Read and Write methods
diff --git a/content/browser/appcache/chrome_appcache_service_unittest.cc b/content/browser/appcache/chrome_appcache_service_unittest.cc
index 450bfe2..0eca5fe 100644
--- a/content/browser/appcache/chrome_appcache_service_unittest.cc
+++ b/content/browser/appcache/chrome_appcache_service_unittest.cc
@@ -5,8 +5,9 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "content/browser/appcache/appcache_database.h"
 #include "content/browser/appcache/appcache_storage_impl.h"
 #include "content/browser/appcache/chrome_appcache_service.h"
@@ -33,17 +34,15 @@
 
 class MockURLRequestContextGetter : public net::URLRequestContextGetter {
  public:
-  MockURLRequestContextGetter(
-      net::URLRequestContext* context,
-      base::MessageLoopProxy* message_loop_proxy)
-      : context_(context), message_loop_proxy_(message_loop_proxy) {
-  }
+  MockURLRequestContextGetter(net::URLRequestContext* context,
+                              base::SingleThreadTaskRunner* task_runner)
+      : context_(context), task_runner_(task_runner) {}
 
   net::URLRequestContext* GetURLRequestContext() override { return context_; }
 
   scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
       const override {
-    return message_loop_proxy_;
+    return task_runner_;
   }
 
  protected:
@@ -51,7 +50,7 @@
 
  private:
   net::URLRequestContext* context_;
-  scoped_refptr<base::SingleThreadTaskRunner> message_loop_proxy_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 };
 
 }  // namespace
@@ -101,7 +100,7 @@
   scoped_refptr<MockURLRequestContextGetter> mock_request_context_getter =
       new MockURLRequestContextGetter(
           browser_context_.GetResourceContext()->GetRequestContext(),
-          message_loop_.message_loop_proxy().get());
+          message_loop_.task_runner().get());
   BrowserThread::PostTask(
       BrowserThread::IO,
       FROM_HERE,
diff --git a/content/browser/appcache/mock_appcache_service.cc b/content/browser/appcache/mock_appcache_service.cc
index 549d20b..4f3e2234 100644
--- a/content/browser/appcache/mock_appcache_service.cc
+++ b/content/browser/appcache/mock_appcache_service.cc
@@ -5,7 +5,9 @@
 #include "content/browser/appcache/mock_appcache_service.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 
 namespace content {
 
@@ -17,11 +19,9 @@
 void MockAppCacheService::DeleteAppCachesForOrigin(
     const GURL& origin, const net::CompletionCallback& callback) {
   ++delete_called_count_;
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&DeferredCallCallback,
-                 callback,
-                 mock_delete_appcaches_for_origin_result_));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&DeferredCallCallback, callback,
+                            mock_delete_appcaches_for_origin_result_));
 }
 
 }  // namespace content
diff --git a/content/browser/appcache/mock_appcache_storage.cc b/content/browser/appcache/mock_appcache_storage.cc
index 2a337a0e..efac9ba 100644
--- a/content/browser/appcache/mock_appcache_storage.cc
+++ b/content/browser/appcache/mock_appcache_storage.cc
@@ -5,10 +5,12 @@
 #include "content/browser/appcache/mock_appcache_storage.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/appcache/appcache.h"
 #include "content/browser/appcache/appcache_entry.h"
 #include "content/browser/appcache/appcache_group.h"
@@ -458,10 +460,9 @@
 
 void MockAppCacheStorage::ScheduleTask(const base::Closure& task) {
   pending_tasks_.push_back(task);
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&MockAppCacheStorage::RunOnePendingTask,
-                 weak_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&MockAppCacheStorage::RunOnePendingTask,
+                            weak_factory_.GetWeakPtr()));
 }
 
 void MockAppCacheStorage::RunOnePendingTask() {
diff --git a/content/browser/background_sync/background_sync_manager.cc b/content/browser/background_sync/background_sync_manager.cc
index c7c78cb..b82103d5 100644
--- a/content/browser/background_sync/background_sync_manager.cc
+++ b/content/browser/background_sync/background_sync_manager.cc
@@ -6,6 +6,9 @@
 
 #include "base/barrier_closure.h"
 #include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/background_sync/background_sync_network_observer.h"
 #include "content/browser/background_sync/background_sync_power_observer.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
@@ -75,7 +78,7 @@
             sync_registration.id);
 
   if (disabled_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
     return;
@@ -96,7 +99,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (disabled_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
     return;
   }
@@ -117,7 +120,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (disabled_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
     return;
@@ -138,7 +141,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (disabled_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE,
                               std::vector<BackgroundSyncRegistration>()));
     return;
@@ -203,7 +206,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (disabled_) {
-    base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(callback));
     return;
   }
 
@@ -276,7 +280,8 @@
 
   FireReadyEvents();
 
-  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback));
 }
 
 void BackgroundSyncManager::RegisterImpl(
@@ -286,7 +291,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (disabled_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
     return;
@@ -296,7 +301,7 @@
       sw_registration_id, RegistrationKey(sync_registration));
   if (existing_registration &&
       existing_registration->Equals(sync_registration)) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, *existing_registration));
     return;
   }
@@ -309,7 +314,7 @@
   ServiceWorkerRegistration* sw_registration =
       service_worker_context_->GetLiveRegistration(sw_registration_id);
   if (!sw_registration || !sw_registration->active_version()) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, ERROR_TYPE_NO_SERVICE_WORKER,
                               BackgroundSyncRegistration()));
     return;
@@ -331,7 +336,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (disabled_) {
-    base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(callback));
     return;
   }
 
@@ -354,7 +360,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (status != SERVICE_WORKER_OK || user_data.empty()) {
-    base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(callback));
     return;
   }
 
@@ -375,8 +382,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   // The status doesn't matter at this point, there is nothing else to be done.
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(barrier_closure));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(barrier_closure));
 }
 
 BackgroundSyncManager::BackgroundSyncRegistration*
@@ -445,7 +452,7 @@
   if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
     // The registration is gone.
     sw_to_registrations_map_.erase(sw_registration_id);
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
     return;
@@ -460,7 +467,7 @@
   }
 
   FireReadyEvents();
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, new_registration));
 }
 
@@ -530,7 +537,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (disabled_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
     return;
   }
@@ -539,7 +546,7 @@
       LookupRegistration(sw_registration_id, registration_key);
   if (!existing_registration ||
       existing_registration->id != sync_registration_id) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND));
     return;
   }
@@ -561,7 +568,7 @@
   if (status == SERVICE_WORKER_ERROR_NOT_FOUND) {
     // ServiceWorker was unregistered.
     sw_to_registrations_map_.erase(sw_registration_id);
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE));
     return;
   }
@@ -572,8 +579,8 @@
     return;
   }
 
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::Bind(callback, ERROR_TYPE_OK));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, ERROR_TYPE_OK));
 }
 
 void BackgroundSyncManager::GetRegistrationImpl(
@@ -583,7 +590,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (disabled_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(callback, ERROR_TYPE_STORAGE, BackgroundSyncRegistration()));
     return;
@@ -592,13 +599,13 @@
   const BackgroundSyncRegistration* out_registration =
       LookupRegistration(sw_registration_id, registration_key);
   if (!out_registration) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, ERROR_TYPE_NOT_FOUND,
                               BackgroundSyncRegistration()));
     return;
   }
 
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, *out_registration));
 }
 
@@ -611,7 +618,7 @@
   std::vector<BackgroundSyncRegistration> out_registrations;
 
   if (disabled_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, ERROR_TYPE_STORAGE, out_registrations));
     return;
   }
@@ -629,7 +636,7 @@
     }
   }
 
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, ERROR_TYPE_OK, out_registrations));
 }
 
@@ -696,7 +703,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (disabled_) {
-    base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(callback));
     return;
   }
 
@@ -749,7 +757,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (service_worker_status != SERVICE_WORKER_OK) {
-    base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(callback));
     return;
   }
 
@@ -760,7 +769,8 @@
                  service_worker_registration->id(), registration_key,
                  registration_id));
 
-  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback));
 }
 
 // |service_worker_registration| is just to keep the registration alive
@@ -791,14 +801,16 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (disabled_) {
-    base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(callback));
     return;
   }
 
   BackgroundSyncRegistration* registration =
       LookupRegistration(service_worker_id, key);
   if (!registration || registration->id != sync_registration_id) {
-    base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(callback));
     return;
   }
 
@@ -831,7 +843,8 @@
   if (status_code == SERVICE_WORKER_ERROR_NOT_FOUND) {
     // The registration is gone.
     sw_to_registrations_map_.erase(service_worker_id);
-    base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(callback));
     return;
   }
 
@@ -842,7 +855,8 @@
     return;
   }
 
-  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback));
 }
 
 void BackgroundSyncManager::OnRegistrationDeletedImpl(
@@ -853,7 +867,8 @@
   // The backend (ServiceWorkerStorage) will delete the data, so just delete the
   // memory representation here.
   sw_to_registrations_map_.erase(registration_id);
-  base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback));
 }
 
 void BackgroundSyncManager::OnStorageWipedImpl(const base::Closure& callback) {
diff --git a/content/browser/background_sync/background_sync_manager_unittest.cc b/content/browser/background_sync/background_sync_manager_unittest.cc
index 426f56f37..f49db2d1 100644
--- a/content/browser/background_sync/background_sync_manager_unittest.cc
+++ b/content/browser/background_sync/background_sync_manager_unittest.cc
@@ -5,10 +5,12 @@
 #include "content/browser/background_sync/background_sync_manager.h"
 
 #include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/power_monitor/power_monitor.h"
 #include "base/power_monitor/power_monitor_source.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/service_worker/embedded_worker_test_helper.h"
@@ -145,7 +147,7 @@
       const ServiceWorkerStorage::StatusCallback& callback) override {
     EXPECT_TRUE(continuation_.is_null());
     if (corrupt_backend_) {
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_FAILED));
       return;
     }
@@ -165,7 +167,7 @@
           callback) override {
     EXPECT_TRUE(continuation_.is_null());
     if (corrupt_backend_) {
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
           base::Bind(callback, std::vector<std::pair<int64, std::string>>(),
                      SERVICE_WORKER_ERROR_FAILED));
@@ -315,6 +317,11 @@
     background_sync_manager_.reset(test_background_sync_manager_);
   }
 
+  void DeleteBackgroundSyncManager() {
+    background_sync_manager_.reset();
+    test_background_sync_manager_ = nullptr;
+  }
+
   bool Register(const BackgroundSyncManager::BackgroundSyncRegistration&
                     sync_registration) {
     return RegisterWithServiceWorkerId(sw_registration_id_1_,
@@ -729,11 +736,12 @@
 }
 
 TEST_F(BackgroundSyncManagerTest, InitWithBadBackend) {
-  TestBackgroundSyncManager* manager =
+  DeleteBackgroundSyncManager();
+  test_background_sync_manager_ =
       new TestBackgroundSyncManager(helper_->context_wrapper());
-  background_sync_manager_.reset(manager);
-  manager->set_corrupt_backend(true);
-  manager->DoInit();
+  background_sync_manager_.reset(test_background_sync_manager_);
+  test_background_sync_manager_->set_corrupt_backend(true);
+  test_background_sync_manager_->DoInit();
 
   EXPECT_FALSE(Register(sync_reg_1_));
   EXPECT_FALSE(GetRegistration(sync_reg_1_));
@@ -742,11 +750,14 @@
 TEST_F(BackgroundSyncManagerTest, SequentialOperations) {
   // Schedule Init and all of the operations on a delayed backend. Verify that
   // the operations complete sequentially.
-  TestBackgroundSyncManager* manager =
+  DeleteBackgroundSyncManager();
+
+  test_background_sync_manager_ =
       new TestBackgroundSyncManager(helper_->context_wrapper());
-  background_sync_manager_.reset(manager);
-  manager->set_delay_backend(true);
-  manager->DoInit();
+  background_sync_manager_.reset(test_background_sync_manager_);
+
+  test_background_sync_manager_->set_delay_backend(true);
+  test_background_sync_manager_->DoInit();
 
   const int64 kExpectedInitialId =
       BackgroundSyncManager::BackgroundSyncRegistration::kInitialId;
@@ -754,15 +765,16 @@
   bool register_called = false;
   bool unregister_called = false;
   bool get_registration_called = false;
-  manager->Register(
+  test_background_sync_manager_->Register(
       sw_registration_id_1_, sync_reg_1_,
       base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
                  base::Unretained(this), &register_called));
-  manager->Unregister(sw_registration_id_1_, sync_reg_1_.tag,
-                      sync_reg_1_.periodicity, kExpectedInitialId,
-                      base::Bind(&BackgroundSyncManagerTest::StatusCallback,
-                                 base::Unretained(this), &unregister_called));
-  manager->GetRegistration(
+  test_background_sync_manager_->Unregister(
+      sw_registration_id_1_, sync_reg_1_.tag, sync_reg_1_.periodicity,
+      kExpectedInitialId,
+      base::Bind(&BackgroundSyncManagerTest::StatusCallback,
+                 base::Unretained(this), &unregister_called));
+  test_background_sync_manager_->GetRegistration(
       sw_registration_id_1_, sync_reg_1_.tag, sync_reg_1_.periodicity,
       base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
                  base::Unretained(this), &get_registration_called));
@@ -773,14 +785,14 @@
   EXPECT_FALSE(unregister_called);
   EXPECT_FALSE(get_registration_called);
 
-  manager->Continue();
+  test_background_sync_manager_->Continue();
   base::RunLoop().RunUntilIdle();
   // Register should be blocked while storing to the backend.
   EXPECT_FALSE(register_called);
   EXPECT_FALSE(unregister_called);
   EXPECT_FALSE(get_registration_called);
 
-  manager->Continue();
+  test_background_sync_manager_->Continue();
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(register_called);
   EXPECT_EQ(kExpectedInitialId, callback_registration_.id);
@@ -789,7 +801,7 @@
   EXPECT_FALSE(unregister_called);
   EXPECT_FALSE(get_registration_called);
 
-  manager->Continue();
+  test_background_sync_manager_->Continue();
   base::RunLoop().RunUntilIdle();
   // Unregister should be done and since GetRegistration doesn't require the
   // backend it should be done too.
@@ -806,16 +818,13 @@
 
 TEST_F(BackgroundSyncManagerTest,
        UnregisterServiceWorkerDuringSyncRegistration) {
-  TestBackgroundSyncManager* manager =
-      new TestBackgroundSyncManager(helper_->context_wrapper());
-  background_sync_manager_.reset(manager);
-  manager->DoInit();
+  UseTestBackgroundSyncManager();
 
   EXPECT_TRUE(Register(sync_reg_1_));
 
-  manager->set_delay_backend(true);
+  test_background_sync_manager_->set_delay_backend(true);
   bool callback_called = false;
-  manager->Register(
+  test_background_sync_manager_->Register(
       sw_registration_id_1_, sync_reg_2_,
       base::Bind(&BackgroundSyncManagerTest::StatusAndRegistrationCallback,
                  base::Unretained(this), &callback_called));
@@ -824,12 +833,12 @@
   EXPECT_FALSE(callback_called);
   UnregisterServiceWorker(sw_registration_id_1_);
 
-  manager->Continue();
+  test_background_sync_manager_->Continue();
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(callback_called);
   EXPECT_EQ(BackgroundSyncManager::ERROR_TYPE_STORAGE, callback_error_);
 
-  manager->set_delay_backend(false);
+  test_background_sync_manager_->set_delay_backend(false);
   EXPECT_FALSE(GetRegistration(sync_reg_1_));
 }
 
@@ -841,39 +850,32 @@
 }
 
 TEST_F(BackgroundSyncManagerTest, DisabledManagerWorksAfterBrowserRestart) {
-  TestBackgroundSyncManager* manager =
-      new TestBackgroundSyncManager(helper_->context_wrapper());
-  background_sync_manager_.reset(manager);
-  manager->DoInit();
+  UseTestBackgroundSyncManager();
   EXPECT_TRUE(Register(sync_reg_1_));
-  manager->set_corrupt_backend(true);
+  test_background_sync_manager_->set_corrupt_backend(true);
   EXPECT_FALSE(Register(sync_reg_2_));
 
   // The manager is now disabled and not accepting new requests until browser
   // restart or notification that the storage has been wiped.
-  manager->set_corrupt_backend(false);
+  test_background_sync_manager_->set_corrupt_backend(false);
   EXPECT_FALSE(GetRegistration(sync_reg_1_));
   EXPECT_FALSE(Register(sync_reg_2_));
 
   // Simulate restarting the browser by creating a new BackgroundSyncManager.
-  background_sync_manager_.reset(
-      new TestBackgroundSyncManager(helper_->context_wrapper()));
-  EXPECT_FALSE(GetRegistration(sync_reg_1_));
-  EXPECT_TRUE(Register(sync_reg_1_));
+  UseTestBackgroundSyncManager();
+  EXPECT_TRUE(GetRegistration(sync_reg_1_));
+  EXPECT_TRUE(Register(sync_reg_2_));
 }
 
 TEST_F(BackgroundSyncManagerTest, DisabledManagerWorksAfterDeleteAndStartOver) {
-  TestBackgroundSyncManager* manager =
-      new TestBackgroundSyncManager(helper_->context_wrapper());
-  background_sync_manager_.reset(manager);
-  manager->DoInit();
+  UseTestBackgroundSyncManager();
   EXPECT_TRUE(Register(sync_reg_1_));
-  manager->set_corrupt_backend(true);
+  test_background_sync_manager_->set_corrupt_backend(true);
   EXPECT_FALSE(Register(sync_reg_2_));
 
   // The manager is now disabled and not accepting new requests until browser
   // restart or notification that the storage has been wiped.
-  manager->set_corrupt_backend(false);
+  test_background_sync_manager_->set_corrupt_backend(false);
   helper_->context()->ScheduleDeleteAndStartOver();
   base::RunLoop().RunUntilIdle();
 
@@ -1063,7 +1065,7 @@
   EXPECT_TRUE(GetRegistration(sync_reg_2_));
 
   SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
-  base::RunLoop().RunUntilIdle();
+
   EXPECT_EQ(2, sync_events_called_);
   EXPECT_FALSE(GetRegistration(sync_reg_1_));
   EXPECT_FALSE(GetRegistration(sync_reg_2_));
@@ -1079,7 +1081,7 @@
   EXPECT_TRUE(GetRegistration(sync_reg_1_));
 
   // Simulate closing the browser.
-  background_sync_manager_.reset();
+  DeleteBackgroundSyncManager();
 
   // The next time the manager is started, the network is good.
   SetNetwork(net::NetworkChangeNotifier::CONNECTION_WIFI);
diff --git a/content/browser/background_sync/background_sync_network_observer.cc b/content/browser/background_sync/background_sync_network_observer.cc
index fafb1e6..1c6f2bd9 100644
--- a/content/browser/background_sync/background_sync_network_observer.cc
+++ b/content/browser/background_sync/background_sync_network_observer.cc
@@ -4,6 +4,9 @@
 
 #include "content/browser/background_sync/background_sync_network_observer.h"
 
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace content {
@@ -47,7 +50,8 @@
 void BackgroundSyncNetworkObserver::NotifyNetworkChanged() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  base::MessageLoop::current()->PostTask(FROM_HERE, network_changed_callback_);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                network_changed_callback_);
 }
 
 void BackgroundSyncNetworkObserver::OnNetworkChanged(
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index 746f4fe..56ca3e06 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -306,6 +306,9 @@
                                   PROCESS_TYPE_MAX);
         break;
       }
+#if defined(OS_CHROMEOS)
+      case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
+#endif
       case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: {
         delegate_->OnProcessCrashed(exit_code);
         // Report that this child process was killed.
@@ -325,6 +328,13 @@
     UMA_HISTOGRAM_ENUMERATION("ChildProcess.Disconnected2",
                               data_.process_type,
                               PROCESS_TYPE_MAX);
+#if defined(OS_CHROMEOS)
+    if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM) {
+      UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed2.OOM",
+                                data_.process_type,
+                                PROCESS_TYPE_MAX);
+    }
+#endif
   }
   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                           base::Bind(&NotifyProcessHostDisconnected, data_));
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index c1932ef..9ed607ac 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -6,9 +6,9 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/memory_pressure_monitor.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/pending_task.h"
@@ -17,6 +17,7 @@
 #include "base/process/process_metrics.h"
 #include "base/profiler/scoped_profile.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/system_monitor/system_monitor.h"
@@ -39,6 +40,7 @@
 #include "content/browser/histogram_synchronizer.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/media/media_internals.h"
+#include "content/browser/mojo/mojo_shell_context.h"
 #include "content/browser/net/browser_online_state_observer.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/browser/speech/speech_recognition_manager_impl.h"
@@ -628,7 +630,7 @@
 
 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
   trace_memory_controller_.reset(new base::trace_event::TraceMemoryController(
-      base::MessageLoop::current()->message_loop_proxy(),
+      base::MessageLoop::current()->task_runner(),
       ::HeapProfilerWithPseudoStackStart, ::HeapProfilerStop,
       ::GetHeapProfile));
 #endif
@@ -713,13 +715,13 @@
   // First time through, we really want to create all the tasks
   if (!startup_task_runner_.get()) {
 #if defined(OS_ANDROID)
-    startup_task_runner_ = make_scoped_ptr(new StartupTaskRunner(
-        base::Bind(&BrowserStartupComplete),
-        base::MessageLoop::current()->message_loop_proxy()));
+    startup_task_runner_ = make_scoped_ptr(
+        new StartupTaskRunner(base::Bind(&BrowserStartupComplete),
+                              base::ThreadTaskRunnerHandle::Get()));
 #else
-    startup_task_runner_ = make_scoped_ptr(new StartupTaskRunner(
-        base::Callback<void(int)>(),
-        base::MessageLoop::current()->message_loop_proxy()));
+    startup_task_runner_ = make_scoped_ptr(
+        new StartupTaskRunner(base::Callback<void(int)>(),
+                              base::ThreadTaskRunnerHandle::Get()));
 #endif
     StartupTask pre_create_threads =
         base::Bind(&BrowserMainLoop::PreCreateThreads, base::Unretained(this));
@@ -897,6 +899,8 @@
       base::Bind(base::IgnoreResult(&base::ThreadRestrictions::SetIOAllowed),
                  true));
 
+  mojo_shell_context_.reset();
+
 #if !defined(OS_IOS)
   if (RenderProcessHost::run_renderer_in_process())
     RenderProcessHostImpl::ShutDownInProcessRenderer();
@@ -1204,7 +1208,7 @@
         "startup",
         "BrowserMainLoop::BrowserThreadsStarted::InitUserInputMonitor");
     user_input_monitor_ = media::UserInputMonitor::Create(
-        io_thread_->message_loop_proxy(), main_thread_->message_loop_proxy());
+        io_thread_->task_runner(), main_thread_->task_runner());
   }
 
   {
@@ -1253,6 +1257,8 @@
 
 #endif  // !defined(OS_IOS)
 
+  mojo_shell_context_.reset(new MojoShellContext);
+
   return result_code_;
 }
 
@@ -1306,8 +1312,8 @@
 #else
   DCHECK(base::MessageLoopForUI::IsCurrent());
   if (parameters_.ui_task) {
-    base::MessageLoopForUI::current()->PostTask(FROM_HERE,
-                                                *parameters_.ui_task);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  *parameters_.ui_task);
   }
 
   base::RunLoop run_loop;
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h
index 9eba81d..14478ec5 100644
--- a/content/browser/browser_main_loop.h
+++ b/content/browser/browser_main_loop.h
@@ -45,6 +45,7 @@
 class BrowserShutdownImpl;
 class BrowserThreadImpl;
 class MediaStreamManager;
+class MojoShellContext;
 class ResourceDispatcherHostImpl;
 class SpeechRecognitionManagerImpl;
 class StartupTaskRunner;
@@ -231,6 +232,7 @@
 
   // Members initialized in |BrowserThreadsStarted()| --------------------------
   scoped_ptr<base::Thread> indexed_db_thread_;
+  scoped_ptr<MojoShellContext> mojo_shell_context_;
 
   // |user_input_monitor_| has to outlive |audio_manager_|, so declared first.
   scoped_ptr<media::UserInputMonitor> user_input_monitor_;
diff --git a/content/browser/browser_plugin/browser_plugin_guest.cc b/content/browser/browser_plugin/browser_plugin_guest.cc
index 3f6173a..f438805 100644
--- a/content/browser/browser_plugin/browser_plugin_guest.cc
+++ b/content/browser/browser_plugin/browser_plugin_guest.cc
@@ -542,6 +542,9 @@
   SendMessageToEmbedder(
       new BrowserPluginMsg_GuestGone(browser_plugin_instance_id()));
   switch (status) {
+#if defined(OS_CHROMEOS)
+    case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
+#endif
     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
       RecordAction(base::UserMetricsAction("BrowserPlugin.Guest.Killed"));
       break;
diff --git a/content/browser/browser_shutdown_profile_dumper.cc b/content/browser/browser_shutdown_profile_dumper.cc
index 6c4d8c8..c23d8d1 100644
--- a/content/browser/browser_shutdown_profile_dumper.cc
+++ b/content/browser/browser_shutdown_profile_dumper.cc
@@ -8,7 +8,9 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/logging.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
@@ -59,11 +61,10 @@
   base::WaitableEvent flush_complete_event(false, false);
   base::Thread flush_thread("browser_shutdown_trace_event_flush");
   flush_thread.Start();
-  flush_thread.message_loop()->PostTask(
-      FROM_HERE,
-      base::Bind(&BrowserShutdownProfileDumper::EndTraceAndFlush,
-                 base::Unretained(this),
-                 base::Unretained(&flush_complete_event)));
+  flush_thread.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&BrowserShutdownProfileDumper::EndTraceAndFlush,
+                            base::Unretained(this),
+                            base::Unretained(&flush_complete_event)));
 
   bool original_wait_allowed = base::ThreadRestrictions::SetWaitAllowed(true);
   flush_complete_event.Wait();
diff --git a/content/browser/browser_thread_impl.cc b/content/browser/browser_thread_impl.cc
index 1aac305..b0a24ae 100644
--- a/content/browser/browser_thread_impl.cc
+++ b/content/browser/browser_thread_impl.cc
@@ -10,8 +10,7 @@
 #include "base/bind.h"
 #include "base/compiler_specific.h"
 #include "base/lazy_instance.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_restrictions.h"
 #include "content/public/browser/browser_thread_delegate.h"
@@ -37,15 +36,14 @@
   "Chrome_IOThread",  // IO
 };
 
-// An implementation of MessageLoopProxy to be used in conjunction
+// An implementation of SingleThreadTaskRunner to be used in conjunction
 // with BrowserThread.
-class BrowserThreadMessageLoopProxy : public base::MessageLoopProxy {
+class BrowserThreadTaskRunner : public base::SingleThreadTaskRunner {
  public:
-  explicit BrowserThreadMessageLoopProxy(BrowserThread::ID identifier)
-      : id_(identifier) {
-  }
+  explicit BrowserThreadTaskRunner(BrowserThread::ID identifier)
+      : id_(identifier) {}
 
-  // MessageLoopProxy implementation.
+  // SingleThreadTaskRunner implementation.
   bool PostDelayedTask(const tracked_objects::Location& from_here,
                        const base::Closure& task,
                        base::TimeDelta delay) override {
@@ -64,28 +62,28 @@
   }
 
  protected:
-  ~BrowserThreadMessageLoopProxy() override {}
+  ~BrowserThreadTaskRunner() override {}
 
  private:
   BrowserThread::ID id_;
-  DISALLOW_COPY_AND_ASSIGN(BrowserThreadMessageLoopProxy);
+  DISALLOW_COPY_AND_ASSIGN(BrowserThreadTaskRunner);
 };
 
-// A separate helper is used just for the proxies, in order to avoid needing
-// to initialize the globals to create a proxy.
-struct BrowserThreadProxies {
-  BrowserThreadProxies() {
+// A separate helper is used just for the task runners, in order to avoid
+// needing to initialize the globals to create a task runner.
+struct BrowserThreadTaskRunners {
+  BrowserThreadTaskRunners() {
     for (int i = 0; i < BrowserThread::ID_COUNT; ++i) {
       proxies[i] =
-          new BrowserThreadMessageLoopProxy(static_cast<BrowserThread::ID>(i));
+          new BrowserThreadTaskRunner(static_cast<BrowserThread::ID>(i));
     }
   }
 
-  scoped_refptr<base::MessageLoopProxy> proxies[BrowserThread::ID_COUNT];
+  scoped_refptr<base::SingleThreadTaskRunner> proxies[BrowserThread::ID_COUNT];
 };
 
-base::LazyInstance<BrowserThreadProxies>::Leaky
-    g_proxies = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<BrowserThreadTaskRunners>::Leaky g_task_runners =
+    LAZY_INSTANCE_INITIALIZER;
 
 struct BrowserThreadGlobals {
   BrowserThreadGlobals()
@@ -331,9 +329,10 @@
                                   : NULL;
   if (message_loop) {
     if (nestable) {
-      message_loop->PostDelayedTask(from_here, task, delay);
+      message_loop->task_runner()->PostDelayedTask(from_here, task, delay);
     } else {
-      message_loop->PostNonNestableDelayedTask(from_here, task, delay);
+      message_loop->task_runner()->PostNonNestableDelayedTask(from_here, task,
+                                                              delay);
     }
   }
 
@@ -517,9 +516,9 @@
 }
 
 // static
-scoped_refptr<base::MessageLoopProxy>
+scoped_refptr<base::SingleThreadTaskRunner>
 BrowserThread::GetMessageLoopProxyForThread(ID identifier) {
-  return g_proxies.Get().proxies[identifier];
+  return g_task_runners.Get().proxies[identifier];
 }
 
 // static
diff --git a/content/browser/browser_thread_unittest.cc b/content/browser/browser_thread_unittest.cc
index 3f1f8cd..9b23057f 100644
--- a/content/browser/browser_thread_unittest.cc
+++ b/content/browser/browser_thread_unittest.cc
@@ -4,10 +4,10 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/sequenced_task_runner_helpers.h"
+#include "base/single_thread_task_runner.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/public/test/test_browser_thread.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -19,7 +19,7 @@
  public:
   void Release() const {
     CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-    loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
+    loop_.task_runner()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
   }
 
  protected:
@@ -37,7 +37,8 @@
 
   static void BasicFunction(base::MessageLoop* message_loop) {
     CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-    message_loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
+    message_loop->task_runner()->PostTask(FROM_HERE,
+                                          base::MessageLoop::QuitClosure());
   }
 
   class DeletedOnFile
@@ -53,7 +54,8 @@
 
     ~DeletedOnFile() {
       CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-      message_loop_->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
+      message_loop_->task_runner()->PostTask(FROM_HERE,
+                                             base::MessageLoop::QuitClosure());
     }
 
     base::MessageLoop* message_loop_;
@@ -88,24 +90,24 @@
   base::MessageLoop::current()->Run();
 }
 
-TEST_F(BrowserThreadTest, PostTaskViaMessageLoopProxy) {
-  scoped_refptr<base::MessageLoopProxy> message_loop_proxy =
+TEST_F(BrowserThreadTest, PostTaskViaTaskRunner) {
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE);
-  message_loop_proxy->PostTask(
+  task_runner->PostTask(
       FROM_HERE, base::Bind(&BasicFunction, base::MessageLoop::current()));
   base::MessageLoop::current()->Run();
 }
 
-TEST_F(BrowserThreadTest, ReleaseViaMessageLoopProxy) {
-  scoped_refptr<base::MessageLoopProxy> message_loop_proxy =
+TEST_F(BrowserThreadTest, ReleaseViaTaskRunner) {
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
-  message_loop_proxy->ReleaseSoon(FROM_HERE, this);
+  task_runner->ReleaseSoon(FROM_HERE, this);
   base::MessageLoop::current()->Run();
 }
 
 TEST_F(BrowserThreadTest, PostTaskAndReply) {
   // Most of the heavy testing for PostTaskAndReply() is done inside the
-  // MessageLoopProxy test.  This just makes sure we get piped through at all.
+  // task runner test.  This just makes sure we get piped through at all.
   ASSERT_TRUE(BrowserThread::PostTaskAndReply(
       BrowserThread::FILE,
       FROM_HERE,
diff --git a/content/browser/byte_stream_unittest.cc b/content/browser/byte_stream_unittest.cc
index f814e2f5..f750cf2 100644
--- a/content/browser/byte_stream_unittest.cc
+++ b/content/browser/byte_stream_unittest.cc
@@ -10,7 +10,6 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
 #include "base/test/test_simple_task_runner.h"
 #include "net/base/io_buffer.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -104,9 +103,8 @@
 TEST_F(ByteStreamTest, ByteStream_PushBack) {
   scoped_ptr<ByteStreamWriter> byte_stream_input;
   scoped_ptr<ByteStreamReader> byte_stream_output;
-  CreateByteStream(
-      message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
-      3 * 1024, &byte_stream_input, &byte_stream_output);
+  CreateByteStream(message_loop_.task_runner(), message_loop_.task_runner(),
+                   3 * 1024, &byte_stream_input, &byte_stream_output);
 
   // Push a series of IO buffers on; test pushback happening and
   // that it's advisory.
@@ -159,9 +157,8 @@
 TEST_F(ByteStreamTest, ByteStream_Flush) {
   scoped_ptr<ByteStreamWriter> byte_stream_input;
   scoped_ptr<ByteStreamReader> byte_stream_output;
-  CreateByteStream(
-      message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
-      1024, &byte_stream_input, &byte_stream_output);
+  CreateByteStream(message_loop_.task_runner(), message_loop_.task_runner(),
+                   1024, &byte_stream_input, &byte_stream_output);
 
   EXPECT_TRUE(Write(byte_stream_input.get(), 1));
   message_loop_.RunUntilIdle();
@@ -199,9 +196,8 @@
 TEST_F(ByteStreamTest, ByteStream_PushBackSplit) {
   scoped_ptr<ByteStreamWriter> byte_stream_input;
   scoped_ptr<ByteStreamReader> byte_stream_output;
-  CreateByteStream(
-      message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
-      9 * 1024, &byte_stream_input, &byte_stream_output);
+  CreateByteStream(message_loop_.task_runner(), message_loop_.task_runner(),
+                   9 * 1024, &byte_stream_input, &byte_stream_output);
 
   // Push a series of IO buffers on; test pushback happening and
   // that it's advisory.
@@ -254,9 +250,8 @@
   size_t output_length;
 
   // Empty stream, non-error case.
-  CreateByteStream(
-      message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
-      3 * 1024, &byte_stream_input, &byte_stream_output);
+  CreateByteStream(message_loop_.task_runner(), message_loop_.task_runner(),
+                   3 * 1024, &byte_stream_input, &byte_stream_output);
   EXPECT_EQ(ByteStreamReader::STREAM_EMPTY,
             byte_stream_output->Read(&output_io_buffer, &output_length));
   byte_stream_input->Close(0);
@@ -266,9 +261,8 @@
   EXPECT_EQ(0, byte_stream_output->GetStatus());
 
   // Non-empty stream, non-error case.
-  CreateByteStream(
-      message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
-      3 * 1024, &byte_stream_input, &byte_stream_output);
+  CreateByteStream(message_loop_.task_runner(), message_loop_.task_runner(),
+                   3 * 1024, &byte_stream_input, &byte_stream_output);
   EXPECT_EQ(ByteStreamReader::STREAM_EMPTY,
             byte_stream_output->Read(&output_io_buffer, &output_length));
   EXPECT_TRUE(Write(byte_stream_input.get(), 1024));
@@ -284,9 +278,8 @@
   const int kFakeErrorCode = 22;
 
   // Empty stream, error case.
-  CreateByteStream(
-      message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
-      3 * 1024, &byte_stream_input, &byte_stream_output);
+  CreateByteStream(message_loop_.task_runner(), message_loop_.task_runner(),
+                   3 * 1024, &byte_stream_input, &byte_stream_output);
   EXPECT_EQ(ByteStreamReader::STREAM_EMPTY,
             byte_stream_output->Read(&output_io_buffer, &output_length));
   byte_stream_input->Close(kFakeErrorCode);
@@ -296,9 +289,8 @@
   EXPECT_EQ(kFakeErrorCode, byte_stream_output->GetStatus());
 
   // Non-empty stream, error case.
-  CreateByteStream(
-      message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
-      3 * 1024, &byte_stream_input, &byte_stream_output);
+  CreateByteStream(message_loop_.task_runner(), message_loop_.task_runner(),
+                   3 * 1024, &byte_stream_input, &byte_stream_output);
   EXPECT_EQ(ByteStreamReader::STREAM_EMPTY,
             byte_stream_output->Read(&output_io_buffer, &output_length));
   EXPECT_TRUE(Write(byte_stream_input.get(), 1024));
@@ -319,9 +311,8 @@
 
   scoped_ptr<ByteStreamWriter> byte_stream_input;
   scoped_ptr<ByteStreamReader> byte_stream_output;
-  CreateByteStream(
-      message_loop_.message_loop_proxy(), task_runner,
-      10000, &byte_stream_input, &byte_stream_output);
+  CreateByteStream(message_loop_.task_runner(), task_runner, 10000,
+                   &byte_stream_input, &byte_stream_output);
 
   scoped_refptr<net::IOBuffer> output_io_buffer;
   size_t output_length;
@@ -371,9 +362,8 @@
 
   scoped_ptr<ByteStreamWriter> byte_stream_input;
   scoped_ptr<ByteStreamReader> byte_stream_output;
-  CreateByteStream(
-      task_runner, message_loop_.message_loop_proxy(),
-      10000, &byte_stream_input, &byte_stream_output);
+  CreateByteStream(task_runner, message_loop_.task_runner(), 10000,
+                   &byte_stream_input, &byte_stream_output);
 
   scoped_refptr<net::IOBuffer> output_io_buffer;
   size_t output_length;
@@ -433,9 +423,8 @@
 
   scoped_ptr<ByteStreamWriter> byte_stream_input;
   scoped_ptr<ByteStreamReader> byte_stream_output;
-  CreateByteStream(
-      message_loop_.message_loop_proxy(), task_runner,
-      10000, &byte_stream_input, &byte_stream_output);
+  CreateByteStream(message_loop_.task_runner(), task_runner, 10000,
+                   &byte_stream_input, &byte_stream_output);
 
   scoped_refptr<net::IOBuffer> output_io_buffer;
   size_t output_length;
@@ -480,9 +469,8 @@
 
   scoped_ptr<ByteStreamWriter> byte_stream_input;
   scoped_ptr<ByteStreamReader> byte_stream_output;
-  CreateByteStream(
-      task_runner, message_loop_.message_loop_proxy(),
-      10000, &byte_stream_input, &byte_stream_output);
+  CreateByteStream(task_runner, message_loop_.task_runner(), 10000,
+                   &byte_stream_input, &byte_stream_output);
 
   scoped_refptr<net::IOBuffer> output_io_buffer;
   size_t output_length;
@@ -532,9 +520,8 @@
 
   scoped_ptr<ByteStreamWriter> byte_stream_input;
   scoped_ptr<ByteStreamReader> byte_stream_output;
-  CreateByteStream(
-      message_loop_.message_loop_proxy(), task_runner,
-      10000, &byte_stream_input, &byte_stream_output);
+  CreateByteStream(message_loop_.task_runner(), task_runner, 10000,
+                   &byte_stream_input, &byte_stream_output);
 
   base::Closure intermediate_callback;
 
@@ -552,9 +539,8 @@
 TEST_F(ByteStreamTest, ByteStream_CloseWithoutAnyWrite) {
   scoped_ptr<ByteStreamWriter> byte_stream_input;
   scoped_ptr<ByteStreamReader> byte_stream_output;
-  CreateByteStream(
-      message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
-      3 * 1024, &byte_stream_input, &byte_stream_output);
+  CreateByteStream(message_loop_.task_runner(), message_loop_.task_runner(),
+                   3 * 1024, &byte_stream_input, &byte_stream_output);
 
   byte_stream_input->Close(0);
   message_loop_.RunUntilIdle();
@@ -568,9 +554,8 @@
 TEST_F(ByteStreamTest, ByteStream_FlushWithoutAnyWrite) {
   scoped_ptr<ByteStreamWriter> byte_stream_input;
   scoped_ptr<ByteStreamReader> byte_stream_output;
-  CreateByteStream(
-      message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
-      3 * 1024, &byte_stream_input, &byte_stream_output);
+  CreateByteStream(message_loop_.task_runner(), message_loop_.task_runner(),
+                   3 * 1024, &byte_stream_input, &byte_stream_output);
 
   byte_stream_input->Flush();
   message_loop_.RunUntilIdle();
@@ -590,10 +575,9 @@
 TEST_F(ByteStreamTest, ByteStream_WriteOverflow) {
   scoped_ptr<ByteStreamWriter> byte_stream_input;
   scoped_ptr<ByteStreamReader> byte_stream_output;
-  CreateByteStream(
-      message_loop_.message_loop_proxy(), message_loop_.message_loop_proxy(),
-      std::numeric_limits<size_t>::max(),
-      &byte_stream_input, &byte_stream_output);
+  CreateByteStream(message_loop_.task_runner(), message_loop_.task_runner(),
+                   std::numeric_limits<size_t>::max(), &byte_stream_input,
+                   &byte_stream_output);
 
   EXPECT_TRUE(Write(byte_stream_input.get(), 1));
   // 1 + size_t max -> Overflow.
diff --git a/content/browser/cache_storage/cache_storage.cc b/content/browser/cache_storage/cache_storage.cc
index a6a32b9..24cc38b 100644
--- a/content/browser/cache_storage/cache_storage.cc
+++ b/content/browser/cache_storage/cache_storage.cc
@@ -9,12 +9,15 @@
 #include "base/barrier_closure.h"
 #include "base/files/file_util.h"
 #include "base/files/memory_mapped_file.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/sha1.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/cache_storage/cache_storage.pb.h"
 #include "content/browser/cache_storage/cache_storage_cache.h"
 #include "content/browser/cache_storage/cache_storage_scheduler.h"
@@ -225,15 +228,15 @@
     cache_task_runner_->PostTask(
         FROM_HERE,
         base::Bind(&SimpleCacheLoader::CleanUpDeleteCacheDirInPool, cache_path,
-                   callback, base::MessageLoopProxy::current()));
+                   callback, base::ThreadTaskRunnerHandle::Get()));
   }
 
   static void CleanUpDeleteCacheDirInPool(
       const base::FilePath& cache_path,
       const BoolCallback& callback,
-      const scoped_refptr<base::MessageLoopProxy>& original_loop) {
+      const scoped_refptr<base::SingleThreadTaskRunner>& original_task_runner) {
     bool rv = base::DeleteFile(cache_path, true);
-    original_loop->PostTask(FROM_HERE, base::Bind(callback, rv));
+    original_task_runner->PostTask(FROM_HERE, base::Bind(callback, rv));
   }
 
   void WriteIndex(const StringVector& cache_names,
@@ -262,7 +265,7 @@
     cache_task_runner_->PostTask(
         FROM_HERE, base::Bind(&SimpleCacheLoader::WriteIndexWriteToFileInPool,
                               tmp_path, index_path, serialized, callback,
-                              base::MessageLoopProxy::current()));
+                              base::ThreadTaskRunnerHandle::Get()));
   }
 
   static void WriteIndexWriteToFileInPool(
@@ -270,16 +273,16 @@
       const base::FilePath& index_path,
       const std::string& data,
       const BoolCallback& callback,
-      const scoped_refptr<base::MessageLoopProxy>& original_loop) {
+      const scoped_refptr<base::SingleThreadTaskRunner>& original_task_runner) {
     int bytes_written = base::WriteFile(tmp_path, data.c_str(), data.size());
     if (bytes_written != implicit_cast<int>(data.size())) {
       base::DeleteFile(tmp_path, /* recursive */ false);
-      original_loop->PostTask(FROM_HERE, base::Bind(callback, false));
+      original_task_runner->PostTask(FROM_HERE, base::Bind(callback, false));
     }
 
     // Atomically rename the temporary index file to become the real one.
     bool rv = base::ReplaceFile(tmp_path, index_path, NULL);
-    original_loop->PostTask(FROM_HERE, base::Bind(callback, rv));
+    original_task_runner->PostTask(FROM_HERE, base::Bind(callback, rv));
   }
 
   void LoadIndex(scoped_ptr<std::vector<std::string>> names,
@@ -295,18 +298,18 @@
     cache_task_runner_->PostTask(
         FROM_HERE, base::Bind(&SimpleCacheLoader::LoadIndexReadFileInPool,
                               index_path, base::Passed(names.Pass()), callback,
-                              base::MessageLoopProxy::current()));
+                              base::ThreadTaskRunnerHandle::Get()));
   }
 
   static void LoadIndexReadFileInPool(
       const base::FilePath& index_path,
       scoped_ptr<std::vector<std::string>> names,
       const StringVectorCallback& callback,
-      const scoped_refptr<base::MessageLoopProxy>& original_loop) {
+      const scoped_refptr<base::SingleThreadTaskRunner>& original_task_runner) {
     std::string body;
     base::ReadFileToString(index_path, &body);
 
-    original_loop->PostTask(
+    original_task_runner->PostTask(
         FROM_HERE, base::Bind(&SimpleCacheLoader::LoadIndexDidReadFile,
                               base::Passed(names.Pass()), callback, body));
   }
diff --git a/content/browser/cache_storage/cache_storage_cache.cc b/content/browser/cache_storage/cache_storage_cache.cc
index 4373759..ab57e30 100644
--- a/content/browser/cache_storage/cache_storage_cache.cc
+++ b/content/browser/cache_storage/cache_storage_cache.cc
@@ -9,7 +9,6 @@
 #include "base/barrier_closure.h"
 #include "base/files/file_path.h"
 #include "base/guid.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_util.h"
 #include "content/browser/cache_storage/cache_storage.pb.h"
@@ -512,8 +511,8 @@
 }
 
 void CacheStorageCache::Close(const base::Closure& callback) {
-  DCHECK(backend_state_ != BACKEND_CLOSED)
-      << "Don't call CacheStorageCache::Close() twice.";
+  DCHECK_NE(BACKEND_CLOSED, backend_state_)
+      << "Was CacheStorageCache::Close() called twice?";
 
   base::Closure pending_callback =
       base::Bind(&CacheStorageCache::PendingClosure,
@@ -540,8 +539,8 @@
               &entry, base::Bind(NotReachedCompletionCallback))) == net::OK) {
     entries.push_back(entry);  // Open the entries without mutating them.
   }
-  DCHECK(rv !=
-         net::ERR_IO_PENDING);  // Expect all memory ops to be synchronous.
+  DCHECK_NE(net::ERR_IO_PENDING, rv)
+      << "Memory cache operations should be synchronous.";
 
   for (disk_cache::Entry* entry : entries) {
     sum += entry->GetDataSize(INDEX_HEADERS) +
@@ -572,7 +571,7 @@
 
 void CacheStorageCache::MatchImpl(scoped_ptr<ServiceWorkerFetchRequest> request,
                                   const ResponseCallback& callback) {
-  DCHECK(backend_state_ != BACKEND_UNINITIALIZED);
+  DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_);
   if (backend_state_ != BACKEND_OPEN) {
     callback.Run(CACHE_STORAGE_ERROR_STORAGE,
                  scoped_ptr<ServiceWorkerResponse>(),
@@ -640,16 +639,16 @@
 
   for (int i = 0; i < metadata->response().headers_size(); ++i) {
     const CacheHeaderMap header = metadata->response().headers(i);
-    DCHECK(header.name().find('\0') == std::string::npos);
-    DCHECK(header.value().find('\0') == std::string::npos);
+    DCHECK_EQ(std::string::npos, header.name().find('\0'));
+    DCHECK_EQ(std::string::npos, header.value().find('\0'));
     response->headers.insert(std::make_pair(header.name(), header.value()));
   }
 
   ServiceWorkerHeaderMap cached_request_headers;
   for (int i = 0; i < metadata->request().headers_size(); ++i) {
     const CacheHeaderMap header = metadata->request().headers(i);
-    DCHECK(header.name().find('\0') == std::string::npos);
-    DCHECK(header.value().find('\0') == std::string::npos);
+    DCHECK_EQ(std::string::npos, header.name().find('\0'));
+    DCHECK_EQ(std::string::npos, header.value().find('\0'));
     cached_request_headers[header.name()] = header.value();
   }
 
@@ -803,7 +802,7 @@
 }
 
 void CacheStorageCache::PutImpl(scoped_ptr<PutContext> put_context) {
-  DCHECK(backend_state_ != BACKEND_UNINITIALIZED);
+  DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_);
   if (backend_state_ != BACKEND_OPEN) {
     put_context->callback.Run(CACHE_STORAGE_ERROR_STORAGE);
     return;
@@ -854,8 +853,8 @@
   for (ServiceWorkerHeaderMap::const_iterator it =
            put_context->request->headers.begin();
        it != put_context->request->headers.end(); ++it) {
-    DCHECK(it->first.find('\0') == std::string::npos);
-    DCHECK(it->second.find('\0') == std::string::npos);
+    DCHECK_EQ(std::string::npos, it->first.find('\0'));
+    DCHECK_EQ(std::string::npos, it->second.find('\0'));
     CacheHeaderMap* header_map = request_metadata->add_headers();
     header_map->set_name(it->first);
     header_map->set_value(it->second);
@@ -870,8 +869,8 @@
   for (ServiceWorkerHeaderMap::const_iterator it =
            put_context->response->headers.begin();
        it != put_context->response->headers.end(); ++it) {
-    DCHECK(it->first.find('\0') == std::string::npos);
-    DCHECK(it->second.find('\0') == std::string::npos);
+    DCHECK_EQ(std::string::npos, it->first.find('\0'));
+    DCHECK_EQ(std::string::npos, it->second.find('\0'));
     CacheHeaderMap* header_map = response_metadata->add_headers();
     header_map->set_name(it->first);
     header_map->set_value(it->second);
@@ -992,7 +991,7 @@
 void CacheStorageCache::DeleteImpl(
     scoped_ptr<ServiceWorkerFetchRequest> request,
     const ErrorCallback& callback) {
-  DCHECK(backend_state_ != BACKEND_UNINITIALIZED);
+  DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_);
   if (backend_state_ != BACKEND_OPEN) {
     callback.Run(CACHE_STORAGE_ERROR_STORAGE);
     return;
@@ -1042,7 +1041,7 @@
 }
 
 void CacheStorageCache::KeysImpl(const RequestsCallback& callback) {
-  DCHECK(backend_state_ != BACKEND_UNINITIALIZED);
+  DCHECK_NE(BACKEND_UNINITIALIZED, backend_state_);
   if (backend_state_ != BACKEND_OPEN) {
     callback.Run(CACHE_STORAGE_ERROR_STORAGE, scoped_ptr<Requests>());
     return;
@@ -1145,8 +1144,8 @@
 
     for (int i = 0; i < metadata->request().headers_size(); ++i) {
       const CacheHeaderMap header = metadata->request().headers(i);
-      DCHECK(header.name().find('\0') == std::string::npos);
-      DCHECK(header.value().find('\0') == std::string::npos);
+      DCHECK_EQ(std::string::npos, header.name().find('\0'));
+      DCHECK_EQ(std::string::npos, header.value().find('\0'));
       req_headers.insert(std::make_pair(header.name(), header.value()));
     }
   } else {
@@ -1157,7 +1156,7 @@
 }
 
 void CacheStorageCache::CloseImpl(const base::Closure& callback) {
-  DCHECK(backend_state_ != BACKEND_CLOSED);
+  DCHECK_NE(BACKEND_CLOSED, backend_state_);
 
   backend_state_ = BACKEND_CLOSED;
   backend_.reset();
@@ -1180,7 +1179,7 @@
                  weak_ptr_factory_.GetWeakPtr(), callback,
                  base::Passed(backend_ptr.Pass()));
 
-  // TODO(jkarlin): Use the cache MessageLoopProxy that ServiceWorkerCacheCore
+  // TODO(jkarlin): Use the cache task runner that ServiceWorkerCacheCore
   // has for disk caches.
   int rv = disk_cache::CreateCacheBackend(
       cache_type, net::CACHE_BACKEND_SIMPLE, path_, kMaxCacheBytes,
@@ -1205,7 +1204,7 @@
 }
 
 void CacheStorageCache::InitBackend() {
-  DCHECK(backend_state_ == BACKEND_UNINITIALIZED);
+  DCHECK_EQ(BACKEND_UNINITIALIZED, backend_state_);
 
   if (initializing_)
     return;
diff --git a/content/browser/cache_storage/cache_storage_cache_unittest.cc b/content/browser/cache_storage/cache_storage_cache_unittest.cc
index 57350d2..2f11ab7 100644
--- a/content/browser/cache_storage/cache_storage_cache_unittest.cc
+++ b/content/browser/cache_storage/cache_storage_cache_unittest.cc
@@ -6,9 +6,9 @@
 
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
 #include "base/strings/string_split.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/fileapi/chrome_blob_storage_context.h"
 #include "content/browser/fileapi/mock_url_request_delegate.h"
 #include "content/browser/quota/mock_quota_manager_proxy.h"
@@ -38,10 +38,10 @@
 // the memory.
 storage::BlobProtocolHandler* CreateMockBlobProtocolHandler(
     storage::BlobStorageContext* blob_storage_context) {
-  // The FileSystemContext and MessageLoopProxy are not actually used but a
-  // MessageLoopProxy is needed to avoid a DCHECK in BlobURLRequestJob ctor.
+  // The FileSystemContext and thread task runner are not actually used but a
+  // task runner is needed to avoid a DCHECK in BlobURLRequestJob ctor.
   return new storage::BlobProtocolHandler(
-      blob_storage_context, NULL, base::MessageLoopProxy::current().get());
+      blob_storage_context, NULL, base::ThreadTaskRunnerHandle::Get().get());
 }
 
 // A disk_cache::Backend wrapper that can delay operations.
@@ -186,7 +186,7 @@
     blob_storage_context_ = blob_storage_context->context();
 
     quota_manager_proxy_ = new MockQuotaManagerProxy(
-        nullptr, base::MessageLoopProxy::current().get());
+        nullptr, base::ThreadTaskRunnerHandle::Get().get());
 
     url_request_job_factory_.reset(new net::URLRequestJobFactoryImpl);
     url_request_job_factory_->SetProtocolHandler(
@@ -261,8 +261,7 @@
         base::Bind(&CacheStorageCacheTest::ErrorTypeCallback,
                    base::Unretained(this), base::Unretained(loop.get())));
     // TODO(jkarlin): These functions should use base::RunLoop().RunUntilIdle()
-    // once the cache uses a passed in MessageLoopProxy instead of the CACHE
-    // thread.
+    // once the cache uses a passed in task runner instead of the CACHE thread.
     loop->Run();
 
     return callback_error_;
diff --git a/content/browser/cache_storage/cache_storage_manager_unittest.cc b/content/browser/cache_storage/cache_storage_manager_unittest.cc
index 4fb7e7f..61963b1 100644
--- a/content/browser/cache_storage/cache_storage_manager_unittest.cc
+++ b/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -7,9 +7,9 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/cache_storage/cache_storage_quota_client.h"
 #include "content/browser/fileapi/chrome_blob_storage_context.h"
 #include "content/browser/quota/mock_quota_manager_proxy.h"
@@ -39,18 +39,18 @@
     base::RunLoop().RunUntilIdle();
 
     quota_manager_proxy_ = new MockQuotaManagerProxy(
-        nullptr, base::MessageLoopProxy::current().get());
+        nullptr, base::ThreadTaskRunnerHandle::Get().get());
 
     net::URLRequestContext* url_request_context =
         browser_context_.GetRequestContext()->GetURLRequestContext();
     if (MemoryOnly()) {
       cache_manager_ = CacheStorageManager::Create(
-          base::FilePath(), base::MessageLoopProxy::current(),
+          base::FilePath(), base::ThreadTaskRunnerHandle::Get(),
           quota_manager_proxy_);
     } else {
       ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
       cache_manager_ = CacheStorageManager::Create(
-          temp_dir_.path(), base::MessageLoopProxy::current(),
+          temp_dir_.path(), base::ThreadTaskRunnerHandle::Get(),
           quota_manager_proxy_);
     }
 
diff --git a/content/browser/cache_storage/cache_storage_scheduler.cc b/content/browser/cache_storage/cache_storage_scheduler.cc
index 33447b93..86db5f2 100644
--- a/content/browser/cache_storage/cache_storage_scheduler.cc
+++ b/content/browser/cache_storage/cache_storage_scheduler.cc
@@ -9,7 +9,8 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 
 namespace content {
 
@@ -40,7 +41,8 @@
     // TODO(jkarlin): Run multiple operations in parallel where allowed.
     base::Closure closure = pending_operations_.front();
     pending_operations_.pop_front();
-    base::MessageLoopProxy::current()->PostTask(FROM_HERE, base::Bind(closure));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(closure));
   }
 }
 
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc
index 0c461f42..48c5e94 100644
--- a/content/browser/child_process_launcher.cc
+++ b/content/browser/child_process_launcher.cc
@@ -149,6 +149,8 @@
   GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
       *cmd_line, child_process_id, files_to_register.get());
 
+  GetContentClient()->browser()->AppendMappedFileCommandLineSwitches(cmd_line);
+
   StartChildProcess(
       cmd_line->argv(), child_process_id, files_to_register.Pass(), regions,
       base::Bind(&OnChildProcessStartedAndroid, callback, client_thread_id,
@@ -161,6 +163,9 @@
 #if !defined(OS_MACOSX)
   GetContentClient()->browser()->GetAdditionalMappedFilesForChildProcess(
       *cmd_line, child_process_id, files_to_register.get());
+
+  GetContentClient()->browser()->AppendMappedFileCommandLineSwitches(cmd_line);
+
   if (use_zygote) {
     base::ProcessHandle handle = ZygoteHostImpl::GetInstance()->ForkRequest(
         cmd_line->argv(), files_to_register.Pass(), process_type);
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index 68ee72c1..e1b4cfa 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -9,9 +9,10 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/profiler/scoped_tracker.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/simple_thread.h"
 #include "base/threading/thread.h"
 #include "cc/output/compositor_frame.h"
@@ -594,7 +595,7 @@
 }
 
 void GpuProcessTransportFactory::OnLostMainThreadSharedContextInsideCallback() {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&GpuProcessTransportFactory::OnLostMainThreadSharedContext,
                  callback_factory_.GetWeakPtr()));
diff --git a/content/browser/compositor/reflector_impl.h b/content/browser/compositor/reflector_impl.h
index 957dfc305..ca1a89f 100644
--- a/content/browser/compositor/reflector_impl.h
+++ b/content/browser/compositor/reflector_impl.h
@@ -18,8 +18,6 @@
 #include "ui/compositor/reflector.h"
 #include "ui/gfx/geometry/size.h"
 
-namespace base { class MessageLoopProxy; }
-
 namespace gfx { class Rect; }
 
 namespace ui {
diff --git a/content/browser/compositor/reflector_impl_unittest.cc b/content/browser/compositor/reflector_impl_unittest.cc
index a80b4fb..ce9fbb9 100644
--- a/content/browser/compositor/reflector_impl_unittest.cc
+++ b/content/browser/compositor/reflector_impl_unittest.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "cc/test/fake_output_surface_client.h"
@@ -119,7 +118,7 @@
         scoped_ptr<ImageTransportFactory>(
             new NoTransportImageTransportFactory));
     message_loop_.reset(new base::MessageLoop());
-    proxy_ = message_loop_->message_loop_proxy();
+    task_runner_ = message_loop_->task_runner();
     compositor_task_runner_ = new FakeTaskRunner();
     compositor_.reset(new ui::Compositor(gfx::kNullAcceleratedWidget,
                                          context_factory,
@@ -166,7 +165,7 @@
   scoped_refptr<cc::ContextProvider> context_provider_;
   cc::FakeOutputSurfaceClient output_surface_client_;
   scoped_ptr<base::MessageLoop> message_loop_;
-  scoped_refptr<base::MessageLoopProxy> proxy_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   scoped_ptr<ui::Compositor> compositor_;
   scoped_ptr<ui::Layer> root_layer_;
   scoped_ptr<ui::Layer> mirroring_layer_;
diff --git a/content/browser/compositor/software_browser_compositor_output_surface.cc b/content/browser/compositor/software_browser_compositor_output_surface.cc
index c2b70d4..866853c 100644
--- a/content/browser/compositor/software_browser_compositor_output_surface.cc
+++ b/content/browser/compositor/software_browser_compositor_output_surface.cc
@@ -4,8 +4,10 @@
 
 #include "content/browser/compositor/software_browser_compositor_output_surface.h"
 
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "cc/output/compositor_frame.h"
 #include "cc/output/output_surface_client.h"
@@ -38,11 +40,9 @@
         ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0,
         swap_time, 1);
   }
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(
-          &RenderWidgetHostImpl::CompositorFrameDrawn,
-          frame->metadata.latency_info));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&RenderWidgetHostImpl::CompositorFrameDrawn,
+                            frame->metadata.latency_info));
 
   gfx::VSyncProvider* vsync_provider = software_device()->GetVSyncProvider();
   if (vsync_provider) {
diff --git a/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc b/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc
index 68534f0c..ae4962e 100644
--- a/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc
+++ b/content/browser/compositor/software_browser_compositor_output_surface_unittest.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 "base/message_loop/message_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "cc/output/compositor_frame.h"
 #include "cc/test/fake_output_surface_client.h"
 #include "content/browser/compositor/software_browser_compositor_output_surface.h"
@@ -91,7 +91,7 @@
 
   compositor_.reset(new ui::Compositor(gfx::kNullAcceleratedWidget,
                                        context_factory,
-                                       base::MessageLoopProxy::current()));
+                                       base::ThreadTaskRunnerHandle::Get()));
 }
 
 void SoftwareBrowserCompositorOutputSurfaceTest::TearDown() {
diff --git a/content/browser/compositor/software_output_device_ozone.cc b/content/browser/compositor/software_output_device_ozone.cc
index 98c111d..0d1edd0 100644
--- a/content/browser/compositor/software_output_device_ozone.cc
+++ b/content/browser/compositor/software_output_device_ozone.cc
@@ -7,6 +7,7 @@
 #include "ui/compositor/compositor.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/gfx/vsync_provider.h"
+#include "ui/ozone/public/ozone_platform.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
 #include "ui/ozone/public/surface_ozone_canvas.h"
 
@@ -14,7 +15,8 @@
 
 SoftwareOutputDeviceOzone::SoftwareOutputDeviceOzone(ui::Compositor* compositor)
     : compositor_(compositor) {
-  ui::SurfaceFactoryOzone* factory = ui::SurfaceFactoryOzone::GetInstance();
+  ui::SurfaceFactoryOzone* factory =
+      ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone();
 
   surface_ozone_ = factory->CreateCanvasForWidget(compositor_->widget());
 
diff --git a/content/browser/compositor/software_output_device_ozone_unittest.cc b/content/browser/compositor/software_output_device_ozone_unittest.cc
index a19465b35..99c55bd 100644
--- a/content/browser/compositor/software_output_device_ozone_unittest.cc
+++ b/content/browser/compositor/software_output_device_ozone_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "cc/output/software_frame_data.h"
 #include "content/browser/compositor/software_output_device_ozone.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -88,7 +89,7 @@
       &window_delegate_, gfx::Rect(size));
   compositor_.reset(new ui::Compositor(window_delegate_.GetAcceleratedWidget(),
                                        context_factory,
-                                       base::MessageLoopProxy::current()));
+                                       base::ThreadTaskRunnerHandle::Get()));
   compositor_->SetScaleAndSize(1.0f, size);
 
   output_device_.reset(new content::SoftwareOutputDeviceOzone(
diff --git a/content/browser/database_quota_client_unittest.cc b/content/browser/database_quota_client_unittest.cc
index a439b51..3c2c6f3 100644
--- a/content/browser/database_quota_client_unittest.cc
+++ b/content/browser/database_quota_client_unittest.cc
@@ -6,9 +6,11 @@
 
 #include "base/bind.h"
 #include "base/files/file_path.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_errors.h"
 #include "storage/browser/database/database_quota_client.h"
@@ -72,10 +74,9 @@
                           const net::CompletionCallback& callback) override {
     ++delete_called_count_;
     if (async_delete()) {
-      base::MessageLoopProxy::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&MockDatabaseTracker::AsyncDeleteDataForOrigin, this,
-                     callback));
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&MockDatabaseTracker::AsyncDeleteDataForOrigin,
+                                this, callback));
       return net::ERR_IO_PENDING;
     }
     return net::OK;
@@ -207,7 +208,7 @@
 
 
 TEST_F(DatabaseQuotaClientTest, GetOriginUsage) {
-  DatabaseQuotaClient client(base::MessageLoopProxy::current().get(),
+  DatabaseQuotaClient client(base::ThreadTaskRunnerHandle::Get().get(),
                              mock_tracker());
 
   EXPECT_EQ(0, GetOriginUsage(&client, kOriginA, kTemp));
@@ -222,7 +223,7 @@
 }
 
 TEST_F(DatabaseQuotaClientTest, GetOriginsForHost) {
-  DatabaseQuotaClient client(base::MessageLoopProxy::current().get(),
+  DatabaseQuotaClient client(base::ThreadTaskRunnerHandle::Get().get(),
                              mock_tracker());
 
   EXPECT_EQ(kOriginA.host(), kOriginB.host());
@@ -247,7 +248,7 @@
 }
 
 TEST_F(DatabaseQuotaClientTest, GetOriginsForType) {
-  DatabaseQuotaClient client(base::MessageLoopProxy::current().get(),
+  DatabaseQuotaClient client(base::ThreadTaskRunnerHandle::Get().get(),
                              mock_tracker());
 
   EXPECT_TRUE(GetOriginsForType(&client, kTemp).empty());
@@ -262,7 +263,7 @@
 }
 
 TEST_F(DatabaseQuotaClientTest, DeleteOriginData) {
-  DatabaseQuotaClient client(base::MessageLoopProxy::current().get(),
+  DatabaseQuotaClient client(base::ThreadTaskRunnerHandle::Get().get(),
                              mock_tracker());
 
   // Perm deletions are short circuited in the Client and
diff --git a/content/browser/database_tracker_unittest.cc b/content/browser/database_tracker_unittest.cc
index 14557de..a068b4d 100644
--- a/content/browser/database_tracker_unittest.cc
+++ b/content/browser/database_tracker_unittest.cc
@@ -8,8 +8,8 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "content/public/test/mock_special_storage_policy.h"
 #include "net/base/net_errors.h"
@@ -564,12 +564,9 @@
       scoped_refptr<MockSpecialStoragePolicy> special_storage_policy =
           new MockSpecialStoragePolicy;
       special_storage_policy->AddSessionOnly(GURL(kOrigin2Url));
-      scoped_refptr<DatabaseTracker> tracker(
-          new DatabaseTracker(temp_dir.path(),
-                              false,
-                              special_storage_policy.get(),
-                              NULL,
-                              base::MessageLoopProxy::current().get()));
+      scoped_refptr<DatabaseTracker> tracker(new DatabaseTracker(
+          temp_dir.path(), false, special_storage_policy.get(), NULL,
+          base::ThreadTaskRunnerHandle::Get().get()));
 
       // Open two new databases.
       tracker->DatabaseOpened(kOrigin1, kDB1, kDescription, 0,
@@ -644,12 +641,9 @@
       scoped_refptr<MockSpecialStoragePolicy> special_storage_policy =
           new MockSpecialStoragePolicy;
       special_storage_policy->AddSessionOnly(GURL(kOrigin2Url));
-      scoped_refptr<DatabaseTracker> tracker(
-          new DatabaseTracker(temp_dir.path(),
-                              false,
-                              special_storage_policy.get(),
-                              NULL,
-                              base::MessageLoopProxy::current().get()));
+      scoped_refptr<DatabaseTracker> tracker(new DatabaseTracker(
+          temp_dir.path(), false, special_storage_policy.get(), NULL,
+          base::ThreadTaskRunnerHandle::Get().get()));
       tracker->SetForceKeepSessionState();
 
       // Open two new databases.
diff --git a/content/browser/device_sensors/data_fetcher_shared_memory_base.cc b/content/browser/device_sensors/data_fetcher_shared_memory_base.cc
index f2b2d40..ac86c6f8 100644
--- a/content/browser/device_sensors/data_fetcher_shared_memory_base.cc
+++ b/content/browser/device_sensors/data_fetcher_shared_memory_base.cc
@@ -5,7 +5,9 @@
 #include "content/browser/device_sensors/data_fetcher_shared_memory_base.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/threading/thread.h"
 #include "base/timer/timer.h"
@@ -129,11 +131,10 @@
   if (GetType() != FETCHER_TYPE_DEFAULT) {
     if (!InitAndStartPollingThreadIfNecessary())
       return false;
-    polling_thread_->message_loop()->PostTask(
-        FROM_HERE,
-        base::Bind(&PollingThread::AddConsumer,
-                   base::Unretained(polling_thread_.get()),
-                   consumer_type, buffer));
+    polling_thread_->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&PollingThread::AddConsumer,
+                              base::Unretained(polling_thread_.get()),
+                              consumer_type, buffer));
   } else {
     if (!Start(consumer_type, buffer))
       return false;
@@ -150,11 +151,10 @@
     return true;
 
   if (GetType() != FETCHER_TYPE_DEFAULT) {
-    polling_thread_->message_loop()->PostTask(
+    polling_thread_->task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&PollingThread::RemoveConsumer,
-                   base::Unretained(polling_thread_.get()),
-                   consumer_type));
+                   base::Unretained(polling_thread_.get()), consumer_type));
   } else {
     if (!Stop(consumer_type))
       return false;
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc
index bab5b0c..cff2fe8e 100644
--- a/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -77,8 +77,7 @@
 
 DevToolsAgentHostImpl::DevToolsAgentHostImpl()
     : id_(base::GenerateGUID()),
-      client_(NULL),
-      message_buffer_size_(0) {
+      client_(NULL) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   g_instances.Get()[id_] = this;
 }
@@ -166,35 +165,6 @@
   client_->DispatchProtocolMessage(this, message);
 }
 
-void DevToolsAgentHostImpl::ProcessChunkedMessageFromAgent(
-    const DevToolsMessageChunk& chunk) {
-  if (chunk.is_last && !chunk.post_state.empty())
-    state_cookie_ = chunk.post_state;
-
-  if (chunk.is_first && chunk.is_last) {
-    CHECK(message_buffer_size_ == 0);
-    SendMessageToClient(chunk.data);
-    return;
-  }
-
-  if (chunk.is_first) {
-    message_buffer_ = std::string();
-    message_buffer_.reserve(chunk.message_size);
-    message_buffer_size_ = chunk.message_size;
-  }
-
-  CHECK(message_buffer_.size() + chunk.data.size() <=
-      message_buffer_size_);
-  message_buffer_.append(chunk.data);
-
-  if (chunk.is_last) {
-    CHECK(message_buffer_.size() == message_buffer_size_);
-    SendMessageToClient(message_buffer_);
-    message_buffer_ = std::string();
-    message_buffer_size_ = 0;
-  }
-}
-
 // static
 void DevToolsAgentHost::DetachAllClients() {
   if (g_instances == NULL)
@@ -253,4 +223,47 @@
     manager->delegate()->Inspect(browser_context, this);
 }
 
+// DevToolsMessageChunkProcessor -----------------------------------------------
+
+DevToolsMessageChunkProcessor::DevToolsMessageChunkProcessor(
+    const SendMessageCallback& callback)
+    : callback_(callback),
+      message_buffer_size_(0),
+      last_call_id_(0) {
+}
+
+DevToolsMessageChunkProcessor::~DevToolsMessageChunkProcessor() {
+}
+
+void DevToolsMessageChunkProcessor::ProcessChunkedMessageFromAgent(
+    const DevToolsMessageChunk& chunk) {
+  if (chunk.is_last && !chunk.post_state.empty())
+    state_cookie_ = chunk.post_state;
+  if (chunk.is_last)
+    last_call_id_ = chunk.call_id;
+
+  if (chunk.is_first && chunk.is_last) {
+    CHECK(message_buffer_size_ == 0);
+    callback_.Run(chunk.data);
+    return;
+  }
+
+  if (chunk.is_first) {
+    message_buffer_ = std::string();
+    message_buffer_.reserve(chunk.message_size);
+    message_buffer_size_ = chunk.message_size;
+  }
+
+  CHECK(message_buffer_.size() + chunk.data.size() <=
+      message_buffer_size_);
+  message_buffer_.append(chunk.data);
+
+  if (chunk.is_last) {
+    CHECK(message_buffer_.size() == message_buffer_size_);
+    callback_.Run(message_buffer_);
+    message_buffer_ = std::string();
+    message_buffer_size_ = 0;
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/devtools/devtools_agent_host_impl.h b/content/browser/devtools/devtools_agent_host_impl.h
index 62f1463..81ce06b 100644
--- a/content/browser/devtools/devtools_agent_host_impl.h
+++ b/content/browser/devtools/devtools_agent_host_impl.h
@@ -47,11 +47,8 @@
   DevToolsAgentHostImpl();
   ~DevToolsAgentHostImpl() override;
 
-  std::string state_cookie_;
-
   void HostClosed();
   void SendMessageToClient(const std::string& message);
-  void ProcessChunkedMessageFromAgent(const DevToolsMessageChunk& chunk);
   static void NotifyCallbacks(DevToolsAgentHostImpl* agent_host, bool attached);
 
  private:
@@ -59,8 +56,25 @@
 
   const std::string id_;
   DevToolsAgentHostClient* client_;
+};
+
+class DevToolsMessageChunkProcessor {
+ public:
+  using SendMessageCallback = base::Callback<void(const std::string&)>;
+  explicit DevToolsMessageChunkProcessor(const SendMessageCallback& callback);
+  ~DevToolsMessageChunkProcessor();
+
+  std::string state_cookie() const { return state_cookie_; }
+  void set_state_cookie(const std::string& cookie) { state_cookie_ = cookie; }
+  int last_call_id() const { return last_call_id_; }
+  void ProcessChunkedMessageFromAgent(const DevToolsMessageChunk& chunk);
+
+ private:
+  SendMessageCallback callback_;
   std::string message_buffer_;
   uint32 message_buffer_size_;
+  std::string state_cookie_;
+  int last_call_id_;
 };
 
 }  // namespace content
diff --git a/content/browser/devtools/devtools_manager_unittest.cc b/content/browser/devtools/devtools_manager_unittest.cc
index cd632c1..9ace6fa 100644
--- a/content/browser/devtools/devtools_manager_unittest.cc
+++ b/content/browser/devtools/devtools_manager_unittest.cc
@@ -3,7 +3,10 @@
 // found in the LICENSE file.
 
 #include "base/basictypes.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "content/browser/devtools/devtools_manager.h"
 #include "content/browser/devtools/shared_worker_devtools_manager.h"
@@ -140,9 +143,8 @@
   // Start with a short timeout.
   inspected_rvh->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(10));
   // Wait long enough for first timeout and see if it fired.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
       TimeDelta::FromMilliseconds(10));
   base::MessageLoop::current()->Run();
   EXPECT_FALSE(delegate.renderer_unresponsive_received());
@@ -152,9 +154,8 @@
   // Start with a short timeout.
   inspected_rvh->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(10));
   // Wait long enough for first timeout and see if it fired.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
       TimeDelta::FromMilliseconds(10));
   base::MessageLoop::current()->Run();
   EXPECT_TRUE(delegate.renderer_unresponsive_received());
diff --git a/content/browser/devtools/devtools_protocol_handler.cc b/content/browser/devtools/devtools_protocol_handler.cc
index c079519..86ccd8e 100644
--- a/content/browser/devtools/devtools_protocol_handler.cc
+++ b/content/browser/devtools/devtools_protocol_handler.cc
@@ -55,13 +55,13 @@
 }
 
 bool DevToolsProtocolHandler::HandleOptionalMessage(
-    const std::string& message) {
+    const std::string& message, int* call_id) {
   scoped_ptr<base::DictionaryValue> command = ParseCommand(message);
   if (!command)
     return true;
   if (PassCommandToDelegate(command.get()))
     return true;
-  return HandleOptionalCommand(command.Pass());
+  return HandleOptionalCommand(command.Pass(), call_id);
 }
 
 bool DevToolsProtocolHandler::PassCommandToDelegate(
@@ -134,15 +134,17 @@
 }
 
 bool DevToolsProtocolHandler::HandleOptionalCommand(
-    scoped_ptr<base::DictionaryValue> command) {
-  int id = DevToolsProtocolClient::kNoId;
+    scoped_ptr<base::DictionaryValue> command, int* call_id) {
+  *call_id = DevToolsProtocolClient::kNoId;
   std::string method;
-  command->GetInteger(kIdParam, &id);
+  command->GetInteger(kIdParam, call_id);
   command->GetString(kMethodParam, &method);
   DevToolsProtocolDispatcher::CommandHandler command_handler(
       dispatcher_.FindCommandHandler(method));
-  if (!command_handler.is_null())
-    return command_handler.Run(id, TakeDictionary(command.get(), kParamsParam));
+  if (!command_handler.is_null()) {
+    return command_handler.Run(
+        *call_id, TakeDictionary(command.get(), kParamsParam));
+  }
   return false;
 }
 
diff --git a/content/browser/devtools/devtools_protocol_handler.h b/content/browser/devtools/devtools_protocol_handler.h
index cf60cb50..299b342 100644
--- a/content/browser/devtools/devtools_protocol_handler.h
+++ b/content/browser/devtools/devtools_protocol_handler.h
@@ -21,7 +21,7 @@
   virtual ~DevToolsProtocolHandler();
 
   void HandleMessage(const std::string& message);
-  bool HandleOptionalMessage(const std::string& message);
+  bool HandleOptionalMessage(const std::string& message, int* call_id);
 
   DevToolsProtocolDispatcher* dispatcher() { return &dispatcher_; }
 
@@ -29,7 +29,8 @@
   scoped_ptr<base::DictionaryValue> ParseCommand(const std::string& message);
   bool PassCommandToDelegate(base::DictionaryValue* command);
   void HandleCommand(scoped_ptr<base::DictionaryValue> command);
-  bool HandleOptionalCommand(scoped_ptr<base::DictionaryValue> command);
+  bool HandleOptionalCommand(scoped_ptr<base::DictionaryValue> command,
+                             int* call_id);
 
   DevToolsAgentHost* agent_host_;
   DevToolsProtocolClient client_;
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index d8d8aba..d8005dec 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -12,6 +12,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
 #include "content/shell/browser/shell.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/compositor/compositor_switches.h"
@@ -30,14 +31,23 @@
 class DevToolsProtocolTest : public ContentBrowserTest,
                              public DevToolsAgentHostClient {
  public:
-  DevToolsProtocolTest() : has_dispatched_command(false) {}
+  DevToolsProtocolTest()
+      : last_sent_id_(0),
+        in_dispatch_(false) {
+  }
 
  protected:
   void SendCommand(const std::string& method,
                    scoped_ptr<base::DictionaryValue> params) {
+    SendCommand(method, params.Pass(), true);
+  }
+
+  void SendCommand(const std::string& method,
+                   scoped_ptr<base::DictionaryValue> params,
+                   bool wait) {
+    in_dispatch_ = true;
     base::DictionaryValue command;
-    has_dispatched_command = false;
-    command.SetInteger(kIdParam, 1);
+    command.SetInteger(kIdParam, ++last_sent_id_);
     command.SetString(kMethodParam, method);
     if (params)
       command.Set(kParamsParam, params.release());
@@ -47,8 +57,9 @@
     agent_host_->DispatchProtocolMessage(json_command);
     // Some messages are dispatched synchronously.
     // Only run loop if we are not finished yet.
-    if (!has_dispatched_command)
+    if (in_dispatch_ && wait)
       base::MessageLoop::current()->Run();
+    in_dispatch_ = false;
   }
 
   bool HasValue(const std::string& path) {
@@ -88,25 +99,36 @@
 
   scoped_ptr<base::DictionaryValue> result_;
   scoped_refptr<DevToolsAgentHost> agent_host_;
+  int last_sent_id_;
+  std::vector<int> result_ids_;
+  std::vector<std::string> notifications_;
 
  private:
   void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
                                const std::string& message) override {
     scoped_ptr<base::DictionaryValue> root(static_cast<base::DictionaryValue*>(
         base::JSONReader::DeprecatedRead(message)));
-    base::DictionaryValue* result;
-    EXPECT_TRUE(root->GetDictionary("result", &result));
-    result_.reset(result->DeepCopy());
-    if (base::MessageLoop::current()->is_running())
-      base::MessageLoop::current()->QuitNow();
-    has_dispatched_command = true;
+    int id;
+    if (root->GetInteger("id", &id)) {
+      result_ids_.push_back(id);
+      base::DictionaryValue* result;
+      EXPECT_TRUE(root->GetDictionary("result", &result));
+      result_.reset(result->DeepCopy());
+      in_dispatch_ = false;
+      if (base::MessageLoop::current()->is_running())
+        base::MessageLoop::current()->QuitNow();
+    } else {
+      std::string notification;
+      EXPECT_TRUE(root->GetString("method", &notification));
+      notifications_.push_back(notification);
+    }
   }
 
   void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced) override {
     EXPECT_TRUE(false);
   }
 
-  bool has_dispatched_command;
+  bool in_dispatch_;
 };
 
 class SyntheticKeyEventTest : public DevToolsProtocolTest {
@@ -320,4 +342,32 @@
   ASSERT_GT(scroll_top, 0);
 }
 
+IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, NavigationPreservesMessages) {
+  ASSERT_TRUE(test_server()->Start());
+  GURL test_url = test_server()->GetURL("files/devtools/navigation.html");
+  NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
+  SendCommand("Page.enable", nullptr, false);
+
+  scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
+  test_url = GetTestUrl("devtools", "navigation.html");
+  params->SetString("url", test_url.spec());
+  SendCommand("Page.navigate", params.Pass(), true);
+
+  bool enough_results = result_ids_.size() >= 2u;
+  EXPECT_TRUE(enough_results);
+  if (enough_results) {
+    EXPECT_EQ(1, result_ids_[0]);  // Page.enable
+    EXPECT_EQ(2, result_ids_[1]);  // Page.navigate
+  }
+
+  enough_results = notifications_.size() >= 1u;
+  EXPECT_TRUE(enough_results);
+  bool found_frame_notification = false;
+  for (const std::string& notification : notifications_) {
+    if (notification == "Page.frameStartedLoading")
+      found_frame_notification = true;
+  }
+  EXPECT_TRUE(found_frame_notification);
+}
+
 }  // namespace content
diff --git a/content/browser/devtools/protocol/input_handler.cc b/content/browser/devtools/protocol/input_handler.cc
index 33fd42b..f30edd20 100644
--- a/content/browser/devtools/protocol/input_handler.cc
+++ b/content/browser/devtools/protocol/input_handler.cc
@@ -218,26 +218,6 @@
   return Response::OK();
 }
 
-Response InputHandler::DispatchKeyEvent(
-    const std::string& type,
-    const int* modifiers,
-    const double* timestamp,
-    const std::string* text,
-    const std::string* unmodified_text,
-    const std::string* key_identifier,
-    const std::string* code,
-    const int* windows_virtual_key_code,
-    const int* native_virtual_key_code,
-    const bool* auto_repeat,
-    const bool* is_keypad,
-    const bool* is_system_key) {
-  std::string dom_key;
-  return InputHandler::DispatchKeyEvent(type, modifiers, timestamp, text,
-      unmodified_text, key_identifier, code, &dom_key,
-      windows_virtual_key_code, native_virtual_key_code, auto_repeat,
-      is_keypad, is_system_key);
-}
-
 Response InputHandler::DispatchMouseEvent(
     const std::string& type,
     int x,
diff --git a/content/browser/devtools/protocol/input_handler.h b/content/browser/devtools/protocol/input_handler.h
index 463efe9..c4de0787 100644
--- a/content/browser/devtools/protocol/input_handler.h
+++ b/content/browser/devtools/protocol/input_handler.h
@@ -43,19 +43,6 @@
                             const std::string* unmodified_text,
                             const std::string* key_identifier,
                             const std::string* code,
-                            const int* windows_virtual_key_code,
-                            const int* native_virtual_key_code,
-                            const bool* auto_repeat,
-                            const bool* is_keypad,
-                            const bool* is_system_key);
-
-  Response DispatchKeyEvent(const std::string& type,
-                            const int* modifiers,
-                            const double* timestamp,
-                            const std::string* text,
-                            const std::string* unmodified_text,
-                            const std::string* key_identifier,
-                            const std::string* code,
                             const std::string* key,
                             const int* windows_virtual_key_code,
                             const int* native_virtual_key_code,
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index cc69f7d2..63550c01 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -8,8 +8,11 @@
 
 #include "base/base64.h"
 #include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/worker_pool.h"
 #include "content/browser/devtools/protocol/color_picker.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
@@ -426,10 +429,9 @@
     processing_screencast_frame_ = false;
     if (capture_retry_count_) {
       --capture_retry_count_;
-      base::MessageLoop::current()->PostDelayedTask(
-          FROM_HERE,
-          base::Bind(&PageHandler::InnerSwapCompositorFrame,
-                     weak_factory_.GetWeakPtr()),
+      base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+          FROM_HERE, base::Bind(&PageHandler::InnerSwapCompositorFrame,
+                                weak_factory_.GetWeakPtr()),
           base::TimeDelta::FromMilliseconds(kFrameRetryDelayMs));
     }
     return;
diff --git a/content/browser/devtools/protocol/tethering_handler.h b/content/browser/devtools/protocol/tethering_handler.h
index 246fdd31..21f1a9a2 100644
--- a/content/browser/devtools/protocol/tethering_handler.h
+++ b/content/browser/devtools/protocol/tethering_handler.h
@@ -6,7 +6,6 @@
 #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_TETHERING_HANDLER_H_
 
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "content/browser/devtools/protocol/devtools_protocol_dispatcher.h"
 
 namespace net {
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index bac8a6b..c3e2ec9c 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -72,17 +72,170 @@
 
 }  // namespace
 
+// RenderFrameDevToolsAgentHost::FrameHostHolder -------------------------------
+
+class RenderFrameDevToolsAgentHost::FrameHostHolder {
+ public:
+  FrameHostHolder(
+      RenderFrameDevToolsAgentHost* agent, RenderFrameHostImpl* host);
+  ~FrameHostHolder();
+
+  RenderFrameHostImpl* host() const { return host_; }
+
+  void Attach();
+  void Reattach(FrameHostHolder* old);
+  void Detach();
+  void DispatchProtocolMessage(int call_id, const std::string& message);
+  void InspectElement(int x, int y);
+  void ProcessChunkedMessageFromAgent(const DevToolsMessageChunk& chunk);
+  void Suspend();
+  void Resume();
+
+ private:
+  void GrantPolicy();
+  void RevokePolicy();
+  void SendMessageToClient(const std::string& message);
+
+  RenderFrameDevToolsAgentHost* agent_;
+  RenderFrameHostImpl* host_;
+  bool attached_;
+  bool suspended_;
+  DevToolsMessageChunkProcessor chunk_processor_;
+  std::vector<std::string> pending_messages_;
+  std::map<int, std::string> sent_messages_;
+};
+
+RenderFrameDevToolsAgentHost::FrameHostHolder::FrameHostHolder(
+    RenderFrameDevToolsAgentHost* agent, RenderFrameHostImpl* host)
+    : agent_(agent),
+      host_(host),
+      attached_(false),
+      suspended_(false),
+      chunk_processor_(base::Bind(
+           &RenderFrameDevToolsAgentHost::FrameHostHolder::SendMessageToClient,
+           base::Unretained(this))) {
+  DCHECK(agent_);
+  DCHECK(host_);
+}
+
+RenderFrameDevToolsAgentHost::FrameHostHolder::~FrameHostHolder() {
+  if (attached_)
+    RevokePolicy();
+}
+
+void RenderFrameDevToolsAgentHost::FrameHostHolder::Attach() {
+  host_->Send(new DevToolsAgentMsg_Attach(
+      host_->GetRoutingID(), agent_->GetId()));
+  GrantPolicy();
+  attached_ = true;
+}
+
+void RenderFrameDevToolsAgentHost::FrameHostHolder::Reattach(
+    FrameHostHolder* old) {
+  if (old)
+    chunk_processor_.set_state_cookie(old->chunk_processor_.state_cookie());
+  host_->Send(new DevToolsAgentMsg_Reattach(
+      host_->GetRoutingID(), agent_->GetId(), chunk_processor_.state_cookie()));
+  if (old) {
+    for (const auto& pair : old->sent_messages_)
+      DispatchProtocolMessage(pair.first, pair.second);
+  }
+  GrantPolicy();
+  attached_ = true;
+}
+
+void RenderFrameDevToolsAgentHost::FrameHostHolder::Detach() {
+  host_->Send(new DevToolsAgentMsg_Detach(host_->GetRoutingID()));
+  RevokePolicy();
+  attached_ = false;
+}
+
+void RenderFrameDevToolsAgentHost::FrameHostHolder::GrantPolicy() {
+  ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies(
+      host_->GetProcess()->GetID());
+}
+
+void RenderFrameDevToolsAgentHost::FrameHostHolder::RevokePolicy() {
+  bool process_has_agents = false;
+  RenderProcessHost* process_host = host_->GetProcess();
+  for (RenderFrameDevToolsAgentHost* agent : g_instances.Get()) {
+    if (!agent->IsAttached())
+      continue;
+    if (agent->current_ && agent->current_->host() != host_ &&
+        agent->current_->host()->GetProcess() == process_host) {
+      process_has_agents = true;
+    }
+    if (agent->pending_ && agent->pending_->host() != host_ &&
+        agent->pending_->host()->GetProcess() == process_host) {
+      process_has_agents = true;
+    }
+  }
+
+  // We are the last to disconnect from the renderer -> revoke permissions.
+  if (!process_has_agents) {
+    ChildProcessSecurityPolicyImpl::GetInstance()->RevokeReadRawCookies(
+        process_host->GetID());
+  }
+}
+void RenderFrameDevToolsAgentHost::FrameHostHolder::DispatchProtocolMessage(
+    int call_id, const std::string& message) {
+  host_->Send(new DevToolsAgentMsg_DispatchOnInspectorBackend(
+      host_->GetRoutingID(), message));
+  sent_messages_[call_id] = message;
+}
+
+void RenderFrameDevToolsAgentHost::FrameHostHolder::InspectElement(
+    int x, int y) {
+  host_->Send(new DevToolsAgentMsg_InspectElement(
+      host_->GetRoutingID(), agent_->GetId(), x, y));
+}
+
+void
+RenderFrameDevToolsAgentHost::FrameHostHolder::ProcessChunkedMessageFromAgent(
+    const DevToolsMessageChunk& chunk) {
+  chunk_processor_.ProcessChunkedMessageFromAgent(chunk);
+}
+
+void RenderFrameDevToolsAgentHost::FrameHostHolder::SendMessageToClient(
+    const std::string& message) {
+  sent_messages_.erase(chunk_processor_.last_call_id());
+  if (suspended_)
+    pending_messages_.push_back(message);
+  else
+    agent_->SendMessageToClient(message);
+}
+
+void RenderFrameDevToolsAgentHost::FrameHostHolder::Suspend() {
+  suspended_ = true;
+}
+
+void RenderFrameDevToolsAgentHost::FrameHostHolder::Resume() {
+  suspended_ = false;
+  for (const std::string& message : pending_messages_)
+    agent_->SendMessageToClient(message);
+  std::vector<std::string> empty;
+  pending_messages_.swap(empty);
+}
+
+// RenderFrameDevToolsAgentHost ------------------------------------------------
+
 scoped_refptr<DevToolsAgentHost>
 DevToolsAgentHost::GetOrCreateFor(WebContents* web_contents) {
   RenderFrameDevToolsAgentHost* result = FindAgentHost(web_contents);
-  if (!result)
-    result = new RenderFrameDevToolsAgentHost(web_contents->GetMainFrame());
+  if (!result) {
+    // TODO(dgozman): this check should not be necessary. See
+    // http://crbug.com/489664.
+    if (!web_contents->GetMainFrame())
+      return nullptr;
+    result = new RenderFrameDevToolsAgentHost(
+        static_cast<RenderFrameHostImpl*>(web_contents->GetMainFrame()));
+  }
   return result;
 }
 
 // static
 scoped_refptr<DevToolsAgentHost> RenderFrameDevToolsAgentHost::GetOrCreateFor(
-    RenderFrameHost* host) {
+    RenderFrameHostImpl* host) {
   RenderFrameDevToolsAgentHost* result = FindAgentHost(host);
   if (!result)
     result = new RenderFrameDevToolsAgentHost(host);
@@ -128,12 +281,15 @@
   RenderFrameDevToolsAgentHost* agent_host = FindAgentHost(pending);
   if (!agent_host)
     return;
-  agent_host->ReattachToRenderFrameHost(current);
+  if (agent_host->pending_ && agent_host->pending_->host() == pending) {
+    DCHECK(agent_host->current_ && agent_host->current_->host() == current);
+    agent_host->DiscardPending();
+  }
 }
 
-RenderFrameDevToolsAgentHost::RenderFrameDevToolsAgentHost(RenderFrameHost* rfh)
-    : render_frame_host_(NULL),
-      dom_handler_(new devtools::dom::DOMHandler()),
+RenderFrameDevToolsAgentHost::RenderFrameDevToolsAgentHost(
+    RenderFrameHostImpl* host)
+    : dom_handler_(new devtools::dom::DOMHandler()),
       input_handler_(new devtools::input::InputHandler()),
       inspector_handler_(new devtools::inspector::InspectorHandler()),
       network_handler_(new devtools::network::NetworkHandler()),
@@ -148,8 +304,7 @@
       protocol_handler_(new DevToolsProtocolHandler(
           this,
           base::Bind(&RenderFrameDevToolsAgentHost::SendMessageToClient,
-                     base::Unretained(this)))),
-      reattaching_(false) {
+                     base::Unretained(this)))) {
   DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher();
   dispatcher->SetDOMHandler(dom_handler_.get());
   dispatcher->SetInputHandler(input_handler_.get());
@@ -159,7 +314,7 @@
   dispatcher->SetServiceWorkerHandler(service_worker_handler_.get());
   dispatcher->SetTracingHandler(tracing_handler_.get());
 
-  if (!rfh->GetParent()) {
+  if (!host->GetParent()) {
     page_handler_.reset(new devtools::page::PageHandler());
     emulation_handler_.reset(
         new devtools::emulation::EmulationHandler(page_handler_.get()));
@@ -167,11 +322,50 @@
     dispatcher->SetEmulationHandler(emulation_handler_.get());
   }
 
-  SetRenderFrameHost(rfh);
+  SetPending(host);
+  CommitPending();
+  WebContentsObserver::Observe(WebContents::FromRenderFrameHost(host));
+
   g_instances.Get().push_back(this);
   AddRef();  // Balanced in RenderFrameHostDestroyed.
 }
 
+void RenderFrameDevToolsAgentHost::SetPending(RenderFrameHostImpl* host) {
+  DCHECK(!pending_);
+  pending_.reset(new FrameHostHolder(this, host));
+  if (IsAttached())
+    pending_->Reattach(current_.get());
+
+  // Can only be null in constructor.
+  if (current_)
+    current_->Suspend();
+  pending_->Suspend();
+
+  UpdateProtocolHandlers(host);
+}
+
+void RenderFrameDevToolsAgentHost::CommitPending() {
+  DCHECK(pending_);
+
+  if (!ShouldCreateDevToolsFor(pending_->host())) {
+    DestroyOnRenderFrameGone();
+    // |this| may be deleted at this point.
+    return;
+  }
+
+  current_ = pending_.Pass();
+  UpdateProtocolHandlers(current_->host());
+  current_->Resume();
+}
+
+void RenderFrameDevToolsAgentHost::DiscardPending() {
+  DCHECK(pending_);
+  DCHECK(current_);
+  pending_.reset();
+  UpdateProtocolHandlers(current_->host());
+  current_->Resume();
+}
+
 BrowserContext* RenderFrameDevToolsAgentHost::GetBrowserContext() {
   WebContents* contents = web_contents();
   return contents ? contents->GetBrowserContext() : nullptr;
@@ -182,66 +376,58 @@
 }
 
 void RenderFrameDevToolsAgentHost::Attach() {
-  if (render_frame_host_) {
-    render_frame_host_->Send(new DevToolsAgentMsg_Attach(
-        render_frame_host_->GetRoutingID(), GetId()));
-  }
+  if (current_)
+    current_->Attach();
+  if (pending_)
+    pending_->Attach();
   OnClientAttached();
 }
 
 void RenderFrameDevToolsAgentHost::Detach() {
-  if (render_frame_host_) {
-    render_frame_host_->Send(new DevToolsAgentMsg_Detach(
-        render_frame_host_->GetRoutingID()));
-  }
+  if (current_)
+    current_->Detach();
+  if (pending_)
+    pending_->Detach();
   OnClientDetached();
 }
 
 bool RenderFrameDevToolsAgentHost::DispatchProtocolMessage(
     const std::string& message) {
-  if (protocol_handler_->HandleOptionalMessage(message))
+  int call_id = 0;
+  if (protocol_handler_->HandleOptionalMessage(message, &call_id))
     return true;
 
-  if (render_frame_host_) {
-    render_frame_host_->Send(new DevToolsAgentMsg_DispatchOnInspectorBackend(
-        render_frame_host_->GetRoutingID(), message));
-  }
+  if (current_)
+    current_->DispatchProtocolMessage(call_id, message);
+  if (pending_)
+    pending_->DispatchProtocolMessage(call_id, message);
   return true;
 }
 
 void RenderFrameDevToolsAgentHost::InspectElement(int x, int y) {
-  if (render_frame_host_) {
-    render_frame_host_->Send(new DevToolsAgentMsg_InspectElement(
-        render_frame_host_->GetRoutingID(), GetId(), x, y));
-  }
+  if (current_)
+    current_->InspectElement(x, y);
+  if (pending_)
+    pending_->InspectElement(x, y);
 }
 
 void RenderFrameDevToolsAgentHost::OnClientAttached() {
-  if (!render_frame_host_)
+  if (!web_contents())
     return;
 
-  InnerOnClientAttached();
-
-  // TODO(kaznacheev): Move this call back to DevToolsManager when
-  // extensions::ProcessManager no longer relies on this notification.
-  if (!reattaching_)
-    DevToolsAgentHostImpl::NotifyCallbacks(this, true);
-}
-
-void RenderFrameDevToolsAgentHost::InnerOnClientAttached() {
-  ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies(
-      render_frame_host_->GetProcess()->GetID());
+  frame_trace_recorder_.reset(new DevToolsFrameTraceRecorder());
 
 #if defined(OS_ANDROID)
   power_save_blocker_.reset(static_cast<PowerSaveBlockerImpl*>(
       PowerSaveBlocker::Create(
           PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
           PowerSaveBlocker::kReasonOther, "DevTools").release()));
-  power_save_blocker_->InitDisplaySleepBlocker(
-      WebContents::FromRenderFrameHost(render_frame_host_));
+  power_save_blocker_->InitDisplaySleepBlocker(web_contents());
 #endif
 
-  frame_trace_recorder_.reset(new DevToolsFrameTraceRecorder());
+  // TODO(kaznacheev): Move this call back to DevToolsManager when
+  // extensions::ProcessManager no longer relies on this notification.
+  DevToolsAgentHostImpl::NotifyCallbacks(this, true);
 }
 
 void RenderFrameDevToolsAgentHost::OnClientDetached() {
@@ -255,39 +441,11 @@
   power_handler_->Detached();
   service_worker_handler_->Detached();
   tracing_handler_->Detached();
-  ClientDetachedFromRenderer();
+  frame_trace_recorder_.reset();
 
   // TODO(kaznacheev): Move this call back to DevToolsManager when
   // extensions::ProcessManager no longer relies on this notification.
-  if (!reattaching_)
-    DevToolsAgentHostImpl::NotifyCallbacks(this, false);
-}
-
-void RenderFrameDevToolsAgentHost::ClientDetachedFromRenderer() {
-  if (!render_frame_host_)
-    return;
-
-  InnerClientDetachedFromRenderer();
-}
-
-void RenderFrameDevToolsAgentHost::InnerClientDetachedFromRenderer() {
-  bool process_has_agents = false;
-  RenderProcessHost* render_process_host = render_frame_host_->GetProcess();
-  for (Instances::iterator it = g_instances.Get().begin();
-       it != g_instances.Get().end(); ++it) {
-    if (*it == this || !(*it)->IsAttached())
-      continue;
-    RenderFrameHost* rfh = (*it)->render_frame_host_;
-    if (rfh && rfh->GetProcess() == render_process_host)
-      process_has_agents = true;
-  }
-
-  // We are the last to disconnect from the renderer -> revoke permissions.
-  if (!process_has_agents) {
-    ChildProcessSecurityPolicyImpl::GetInstance()->RevokeReadRawCookies(
-        render_process_host->GetID());
-  }
-  frame_trace_recorder_.reset();
+  DevToolsAgentHostImpl::NotifyCallbacks(this, false);
 }
 
 RenderFrameDevToolsAgentHost::~RenderFrameDevToolsAgentHost() {
@@ -302,60 +460,52 @@
 void RenderFrameDevToolsAgentHost::AboutToNavigateRenderFrame(
     RenderFrameHost* old_host,
     RenderFrameHost* new_host) {
-  if (render_frame_host_ != old_host)
+  DCHECK(!pending_ || pending_->host() != old_host);
+  if (!current_ || current_->host() != old_host)
     return;
-
-  // TODO(creis): This will need to be updated for --site-per-process, since
-  // RenderViewHost is going away and navigations could happen in any frame.
-  if (render_frame_host_ == new_host) {
-    RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
-        render_frame_host_->GetRenderViewHost());
-    if (rvh->render_view_termination_status() ==
-            base::TERMINATION_STATUS_STILL_RUNNING)
-      return;
-  }
-  ReattachToRenderFrameHost(new_host);
+  if (old_host == new_host)
+    return;
+  DCHECK(!pending_);
+  SetPending(static_cast<RenderFrameHostImpl*>(new_host));
 }
 
 void RenderFrameDevToolsAgentHost::RenderFrameHostChanged(
     RenderFrameHost* old_host,
     RenderFrameHost* new_host) {
-  if (old_host == render_frame_host_ && new_host != render_frame_host_) {
-    // AboutToNavigateRenderFrame was not called for renderer-initiated
-    // navigation.
-    ReattachToRenderFrameHost(new_host);
-  }
-}
-
-void
-RenderFrameDevToolsAgentHost::ReattachToRenderFrameHost(RenderFrameHost* rfh) {
-  if (!ShouldCreateDevToolsFor(rfh)) {
-    DestroyOnRenderFrameGone();
-    // |this| may be deleted at this point.
+  DCHECK(!pending_ || pending_->host() != old_host);
+  if (!current_ || current_->host() != old_host)
     return;
-  }
 
-  DCHECK(!reattaching_);
-  reattaching_ = true;
-  DisconnectRenderFrameHost();
-  ConnectRenderFrameHost(rfh);
-  reattaching_ = false;
+  // AboutToNavigateRenderFrame was not called for renderer-initiated
+  // navigation.
+  if (!pending_)
+    SetPending(static_cast<RenderFrameHostImpl*>(new_host));
+
+  CommitPending();
 }
 
 void RenderFrameDevToolsAgentHost::FrameDeleted(RenderFrameHost* rfh) {
-  if (rfh != render_frame_host_)
+  if (pending_ && pending_->host() == rfh) {
+    DiscardPending();
     return;
-  DestroyOnRenderFrameGone();
-  // |this| may be deleted at this point.
+  }
+
+  if (current_ && current_->host() == rfh)
+    DestroyOnRenderFrameGone();  // |this| may be deleted at this point.
+}
+
+void RenderFrameDevToolsAgentHost::RenderFrameDeleted(RenderFrameHost* rfh) {
+  FrameDeleted(rfh);
 }
 
 void RenderFrameDevToolsAgentHost::DestroyOnRenderFrameGone() {
-  DCHECK(render_frame_host_);
+  DCHECK(current_);
   scoped_refptr<RenderFrameDevToolsAgentHost> protect(this);
   if (IsAttached())
     OnClientDetached();
   HostClosed();
-  ClearRenderFrameHost();
+  pending_.reset();
+  current_.reset();
   Release();
 }
 
@@ -364,11 +514,14 @@
   switch(status) {
     case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
+#if defined(OS_CHROMEOS)
+    case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
+#endif
     case base::TERMINATION_STATUS_PROCESS_CRASHED:
 #if defined(OS_ANDROID)
     case base::TERMINATION_STATUS_OOM_PROTECTED:
 #endif
-      RenderFrameCrashed();
+      inspector_handler_->TargetCrashed();
       break;
     default:
       break;
@@ -377,7 +530,7 @@
 
 bool RenderFrameDevToolsAgentHost::OnMessageReceived(
     const IPC::Message& message) {
-  if (!render_frame_host_)
+  if (!current_)
     return false;
   if (message.type() == ViewHostMsg_SwapCompositorFrame::ID)
     OnSwapCompositorFrame(message);
@@ -387,32 +540,36 @@
 bool RenderFrameDevToolsAgentHost::OnMessageReceived(
     const IPC::Message& message,
     RenderFrameHost* render_frame_host) {
-  if (!render_frame_host_ || render_frame_host != render_frame_host_)
+  if (message.type() != DevToolsClientMsg_DispatchOnInspectorFrontend::ID)
+    return false;
+  if (!IsAttached())
     return false;
 
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(RenderFrameDevToolsAgentHost, message)
-    IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend,
-                        OnDispatchOnInspectorFrontend)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
+  FrameHostHolder* holder = nullptr;
+  if (current_ && current_->host() == render_frame_host)
+    holder = current_.get();
+  if (pending_ && pending_->host() == render_frame_host)
+    holder = pending_.get();
+  if (!holder)
+    return false;
+
+  DevToolsClientMsg_DispatchOnInspectorFrontend::Param param;
+  if (!DevToolsClientMsg_DispatchOnInspectorFrontend::Read(&message, &param))
+    return false;
+  holder->ProcessChunkedMessageFromAgent(base::get<0>(param));
+  return true;
 }
 
 void RenderFrameDevToolsAgentHost::DidAttachInterstitialPage() {
   if (page_handler_)
     page_handler_->DidAttachInterstitialPage();
 
-  if (!render_frame_host_)
+  // TODO(dgozman): this may break for cross-process subframes.
+  if (!pending_)
     return;
-  // The rvh set in AboutToNavigateRenderFrame turned out to be interstitial.
+  // Pending set in AboutToNavigateRenderFrame turned out to be interstitial.
   // Connect back to the real one.
-  WebContents* web_contents =
-    WebContents::FromRenderFrameHost(render_frame_host_);
-  if (!web_contents)
-    return;
-  DisconnectRenderFrameHost();
-  ConnectRenderFrameHost(web_contents->GetMainFrame());
+  DiscardPending();
 }
 
 void RenderFrameDevToolsAgentHost::DidDetachInterstitialPage() {
@@ -427,46 +584,45 @@
   service_worker_handler_->UpdateHosts();
 }
 
-void RenderFrameDevToolsAgentHost::SetRenderFrameHost(RenderFrameHost* rfh) {
-  DCHECK(ShouldCreateDevToolsFor(rfh));
-  DCHECK(!render_frame_host_);
-  render_frame_host_ = static_cast<RenderFrameHostImpl*>(rfh);
-  DCHECK(render_frame_host_);
-
-  WebContentsObserver::Observe(WebContents::FromRenderFrameHost(rfh));
-  dom_handler_->SetRenderFrameHost(render_frame_host_);
-  input_handler_->SetRenderWidgetHost(
-      render_frame_host_->GetRenderWidgetHost());
-  network_handler_->SetRenderFrameHost(render_frame_host_);
-  service_worker_handler_->SetRenderFrameHost(render_frame_host_);
-  inspector_handler_->SetRenderFrameHost(render_frame_host_);
-
-  if (emulation_handler_)
-    emulation_handler_->SetRenderFrameHost(render_frame_host_);
-  if (page_handler_)
-    page_handler_->SetRenderFrameHost(render_frame_host_);
+void RenderFrameDevToolsAgentHost::DidFailProvisionalLoad(
+    RenderFrameHost* render_frame_host,
+    const GURL& validated_url,
+    int error_code,
+    const base::string16& error_description) {
+  if (pending_ && pending_->host() == render_frame_host)
+    DiscardPending();
 }
 
-void RenderFrameDevToolsAgentHost::ClearRenderFrameHost() {
-  DCHECK(render_frame_host_);
-  render_frame_host_ = nullptr;
-  dom_handler_->SetRenderFrameHost(nullptr);
+void RenderFrameDevToolsAgentHost::UpdateProtocolHandlers(
+    RenderFrameHostImpl* host) {
+  dom_handler_->SetRenderFrameHost(host);
   if (emulation_handler_)
-    emulation_handler_->SetRenderFrameHost(nullptr);
-  input_handler_->SetRenderWidgetHost(nullptr);
-  network_handler_->SetRenderFrameHost(nullptr);
+    emulation_handler_->SetRenderFrameHost(host);
+  input_handler_->SetRenderWidgetHost(host->GetRenderWidgetHost());
+  inspector_handler_->SetRenderFrameHost(host);
+  network_handler_->SetRenderFrameHost(host);
   if (page_handler_)
-    page_handler_->SetRenderFrameHost(nullptr);
-  service_worker_handler_->SetRenderFrameHost(nullptr);
-  inspector_handler_->SetRenderFrameHost(nullptr);
+    page_handler_->SetRenderFrameHost(host);
+  service_worker_handler_->SetRenderFrameHost(host);
 }
 
 void RenderFrameDevToolsAgentHost::DisconnectWebContents() {
-  DisconnectRenderFrameHost();
+  if (pending_)
+    DiscardPending();
+  UpdateProtocolHandlers(nullptr);
+  current_.reset();
+  WebContentsObserver::Observe(nullptr);
 }
 
 void RenderFrameDevToolsAgentHost::ConnectWebContents(WebContents* wc) {
-  ConnectRenderFrameHost(wc->GetMainFrame());
+  DCHECK(!current_);
+  DCHECK(!pending_);
+  RenderFrameHostImpl* host =
+      static_cast<RenderFrameHostImpl*>(wc->GetMainFrame());
+  DCHECK(host);
+  SetPending(host);
+  CommitPending();
+  WebContentsObserver::Observe(WebContents::FromRenderFrameHost(host));
 }
 
 DevToolsAgentHost::Type RenderFrameDevToolsAgentHost::GetType() {
@@ -482,16 +638,21 @@
 }
 
 GURL RenderFrameDevToolsAgentHost::GetURL() {
+  // Order is important here.
   WebContents* web_contents = GetWebContents();
   if (web_contents && !IsChildFrame())
     return web_contents->GetVisibleURL();
-  return render_frame_host_ ?
-      render_frame_host_->GetLastCommittedURL() : GURL();
+  if (pending_)
+    return pending_->host()->GetLastCommittedURL();
+  if (current_)
+    return current_->host()->GetLastCommittedURL();
+  return GURL();
 }
 
 bool RenderFrameDevToolsAgentHost::Activate() {
-  if (render_frame_host_) {
-    render_frame_host_->GetRenderViewHost()->GetDelegate()->Activate();
+  WebContentsImpl* wc = static_cast<WebContentsImpl*>(web_contents());
+  if (wc) {
+    wc->Activate();
     return true;
   }
   return false;
@@ -505,25 +666,6 @@
   return false;
 }
 
-void RenderFrameDevToolsAgentHost::ConnectRenderFrameHost(
-    RenderFrameHost* rfh) {
-  SetRenderFrameHost(rfh);
-  if (IsAttached() && render_frame_host_) {
-    render_frame_host_->Send(new DevToolsAgentMsg_Reattach(
-        render_frame_host_->GetRoutingID(), GetId(), state_cookie_));
-    OnClientAttached();
-  }
-}
-
-void RenderFrameDevToolsAgentHost::DisconnectRenderFrameHost() {
-  ClientDetachedFromRenderer();
-  ClearRenderFrameHost();
-}
-
-void RenderFrameDevToolsAgentHost::RenderFrameCrashed() {
-  inspector_handler_->TargetCrashed();
-}
-
 void RenderFrameDevToolsAgentHost::OnSwapCompositorFrame(
     const IPC::Message& message) {
   ViewHostMsg_SwapCompositorFrame::Param param;
@@ -535,38 +677,30 @@
     input_handler_->OnSwapCompositorFrame(base::get<1>(param).metadata);
   if (frame_trace_recorder_) {
     frame_trace_recorder_->OnSwapCompositorFrame(
-        render_frame_host_, base::get<1>(param).metadata);
+        current_ ? current_->host() : nullptr, base::get<1>(param).metadata);
   }
 }
 
 void RenderFrameDevToolsAgentHost::SynchronousSwapCompositorFrame(
     const cc::CompositorFrameMetadata& frame_metadata) {
-  if (!render_frame_host_)
-    return;
   if (page_handler_)
     page_handler_->OnSwapCompositorFrame(frame_metadata);
   if (input_handler_)
     input_handler_->OnSwapCompositorFrame(frame_metadata);
   if (frame_trace_recorder_) {
     frame_trace_recorder_->OnSwapCompositorFrame(
-        render_frame_host_, frame_metadata);
+        current_ ? current_->host() : nullptr, frame_metadata);
   }
 }
 
 bool RenderFrameDevToolsAgentHost::HasRenderFrameHost(
     RenderFrameHost* host) {
-  return host == render_frame_host_;
-}
-
-void RenderFrameDevToolsAgentHost::OnDispatchOnInspectorFrontend(
-    const DevToolsMessageChunk& message) {
-  if (!IsAttached() || !render_frame_host_)
-    return;
-  ProcessChunkedMessageFromAgent(message);
+  return (current_ && current_->host() == host) ||
+      (pending_ && pending_->host() == host);
 }
 
 bool RenderFrameDevToolsAgentHost::IsChildFrame() {
-  return render_frame_host_ && render_frame_host_->GetParent();
+  return current_ && current_->host()->GetParent();
 }
 
 }  // namespace content
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h
index 6264bca2..15e6dcd 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -23,7 +23,6 @@
 class BrowserContext;
 class DevToolsFrameTraceRecorder;
 class DevToolsProtocolHandler;
-class RenderFrameHost;
 class RenderFrameHostImpl;
 
 #if defined(OS_ANDROID)
@@ -70,10 +69,11 @@
 
  private:
   friend class DevToolsAgentHost;
-  explicit RenderFrameDevToolsAgentHost(RenderFrameHost*);
+  explicit RenderFrameDevToolsAgentHost(RenderFrameHostImpl*);
   ~RenderFrameDevToolsAgentHost() override;
 
-  static scoped_refptr<DevToolsAgentHost> GetOrCreateFor(RenderFrameHost* host);
+  static scoped_refptr<DevToolsAgentHost> GetOrCreateFor(
+      RenderFrameHostImpl* host);
   static void AppendAgentHostForFrameIfApplicable(
       DevToolsAgentHost::List* result,
       RenderFrameHost* host);
@@ -89,6 +89,7 @@
   void RenderFrameHostChanged(RenderFrameHost* old_host,
                               RenderFrameHost* new_host) override;
   void FrameDeleted(RenderFrameHost* rfh) override;
+  void RenderFrameDeleted(RenderFrameHost* rfh) override;
   void RenderProcessGone(base::TerminationStatus status) override;
   bool OnMessageReceived(const IPC::Message& message,
                          RenderFrameHost* render_frame_host) override;
@@ -99,32 +100,31 @@
       RenderFrameHost* render_frame_host,
       const GURL& url,
       ui::PageTransition transition_type) override;
+  void DidFailProvisionalLoad(
+      RenderFrameHost* render_frame_host,
+      const GURL& validated_url,
+      int error_code,
+      const base::string16& error_description) override;
+
+  void SetPending(RenderFrameHostImpl* host);
+  void CommitPending();
+  void DiscardPending();
+  void UpdateProtocolHandlers(RenderFrameHostImpl* host);
+
+  bool IsChildFrame();
 
   void OnClientAttached();
   void OnClientDetached();
 
-  void DisconnectRenderFrameHost();
-  void ConnectRenderFrameHost(RenderFrameHost* rvh);
-  void ReattachToRenderFrameHost(RenderFrameHost* rvh);
-
-  void SetRenderFrameHost(RenderFrameHost* rvh);
-  void ClearRenderFrameHost();
-
   void RenderFrameCrashed();
   void OnSwapCompositorFrame(const IPC::Message& message);
-  bool OnSetTouchEventEmulationEnabled(const IPC::Message& message);
-
-  void OnDispatchOnInspectorFrontend(const DevToolsMessageChunk& message);
-
-  void ClientDetachedFromRenderer();
-
-  void InnerOnClientAttached();
-  void InnerClientDetachedFromRenderer();
-
-  bool IsChildFrame();
   void DestroyOnRenderFrameGone();
 
-  RenderFrameHostImpl* render_frame_host_;
+  class FrameHostHolder;
+
+  scoped_ptr<FrameHostHolder> current_;
+  scoped_ptr<FrameHostHolder> pending_;
+
   scoped_ptr<devtools::dom::DOMHandler> dom_handler_;
   scoped_ptr<devtools::input::InputHandler> input_handler_;
   scoped_ptr<devtools::inspector::InspectorHandler> inspector_handler_;
@@ -140,7 +140,6 @@
   scoped_ptr<PowerSaveBlockerImpl> power_save_blocker_;
 #endif
   scoped_ptr<DevToolsProtocolHandler> protocol_handler_;
-  bool reattaching_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderFrameDevToolsAgentHost);
 };
diff --git a/content/browser/devtools/worker_devtools_agent_host.cc b/content/browser/devtools/worker_devtools_agent_host.cc
index a4d93ac..32cd668e 100644
--- a/content/browser/devtools/worker_devtools_agent_host.cc
+++ b/content/browser/devtools/worker_devtools_agent_host.cc
@@ -43,7 +43,9 @@
     const std::string& message) {
   if (state_ != WORKER_INSPECTED)
     return true;
-  if (protocol_handler_->HandleOptionalMessage(message))
+
+  int call_id;
+  if (protocol_handler_->HandleOptionalMessage(message, &call_id))
     return true;
 
   if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) {
@@ -81,7 +83,7 @@
     AttachToWorker();
     if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) {
       host->Send(new DevToolsAgentMsg_Reattach(
-          worker_id_.second, GetId(), state_cookie_));
+          worker_id_.second, GetId(), chunk_processor_.state_cookie()));
     }
     OnAttachedStateChanged(true);
   }
@@ -121,6 +123,9 @@
           this,
           base::Bind(&WorkerDevToolsAgentHost::SendMessageToClient,
                      base::Unretained(this)))),
+      chunk_processor_(
+          base::Bind(&WorkerDevToolsAgentHost::SendMessageToClient,
+                     base::Unretained(this))),
       state_(WORKER_UNINSPECTED),
       worker_id_(worker_id) {
   WorkerCreated();
@@ -152,7 +157,7 @@
   if (!IsAttached())
     return;
 
-  ProcessChunkedMessageFromAgent(message);
+  chunk_processor_.ProcessChunkedMessageFromAgent(message);
 }
 
 }  // namespace content
diff --git a/content/browser/devtools/worker_devtools_agent_host.h b/content/browser/devtools/worker_devtools_agent_host.h
index 449cda2..db91c275 100644
--- a/content/browser/devtools/worker_devtools_agent_host.h
+++ b/content/browser/devtools/worker_devtools_agent_host.h
@@ -62,6 +62,7 @@
   void OnDispatchOnInspectorFrontend(const DevToolsMessageChunk& message);
 
   scoped_ptr<DevToolsProtocolHandler> protocol_handler_;
+  DevToolsMessageChunkProcessor chunk_processor_;
   WorkerState state_;
   WorkerId worker_id_;
   DISALLOW_COPY_AND_ASSIGN(WorkerDevToolsAgentHost);
diff --git a/content/browser/dom_storage/dom_storage_area_unittest.cc b/content/browser/dom_storage/dom_storage_area_unittest.cc
index aa5653da..ba91f26 100644
--- a/content/browser/dom_storage/dom_storage_area_unittest.cc
+++ b/content/browser/dom_storage/dom_storage_area_unittest.cc
@@ -5,7 +5,9 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/sequenced_worker_pool.h"
@@ -45,11 +47,10 @@
     // At this point the StartCommitTimer task has run and
     // the OnCommitTimer task is queued. We want to inject after
     // that.
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&DOMStorageAreaTest::InjectedCommitSequencingTask2,
-                   base::Unretained(this),
-                   area));
+                   base::Unretained(this), area));
   }
 
   void InjectedCommitSequencingTask2(
@@ -173,10 +174,10 @@
 
   // This should set up a DOMStorageArea that is correctly backed to disk.
   {
-    scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
-        kOrigin,
-        temp_dir.path(),
-        new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
+    scoped_refptr<DOMStorageArea> area(
+        new DOMStorageArea(kOrigin, temp_dir.path(),
+                           new MockDOMStorageTaskRunner(
+                               base::ThreadTaskRunnerHandle::Get().get())));
 
     EXPECT_TRUE(area->backing_.get());
     DOMStorageDatabase* database = static_cast<LocalStorageDatabaseAdapter*>(
@@ -221,9 +222,8 @@
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
   scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
-      kOrigin,
-      temp_dir.path(),
-      new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
+      kOrigin, temp_dir.path(),
+      new MockDOMStorageTaskRunner(base::ThreadTaskRunnerHandle::Get().get())));
   // Inject an in-memory db to speed up the test.
   area->backing_.reset(new LocalStorageDatabaseAdapter());
 
@@ -300,9 +300,8 @@
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
-      kOrigin,
-      temp_dir.path(),
-      new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
+      kOrigin, temp_dir.path(),
+      new MockDOMStorageTaskRunner(base::ThreadTaskRunnerHandle::Get().get())));
 
   // Inject an in-memory db to speed up the test and also to verify
   // the final changes are commited in it's dtor.
@@ -327,9 +326,8 @@
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
-      kOrigin,
-      temp_dir.path(),
-      new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
+      kOrigin, temp_dir.path(),
+      new MockDOMStorageTaskRunner(base::ThreadTaskRunnerHandle::Get().get())));
 
   // This test puts files on disk.
   base::FilePath db_file_path = static_cast<LocalStorageDatabaseAdapter*>(
@@ -388,9 +386,8 @@
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
-      kOrigin,
-      temp_dir.path(),
-      new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
+      kOrigin, temp_dir.path(),
+      new MockDOMStorageTaskRunner(base::ThreadTaskRunnerHandle::Get().get())));
 
   // Inject an in-memory db to speed up the test.
   area->backing_.reset(new LocalStorageDatabaseAdapter());
diff --git a/content/browser/dom_storage/dom_storage_context_impl_unittest.cc b/content/browser/dom_storage/dom_storage_context_impl_unittest.cc
index 9ea4602..fe99fbf 100644
--- a/content/browser/dom_storage/dom_storage_context_impl_unittest.cc
+++ b/content/browser/dom_storage/dom_storage_context_impl_unittest.cc
@@ -6,8 +6,8 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/time/time.h"
 #include "content/browser/dom_storage/dom_storage_area.h"
@@ -43,7 +43,7 @@
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     storage_policy_ = new MockSpecialStoragePolicy;
     task_runner_ =
-        new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get());
+        new MockDOMStorageTaskRunner(base::ThreadTaskRunnerHandle::Get().get());
     context_ = new DOMStorageContextImpl(temp_dir_.path(),
                                          base::FilePath(),
                                          storage_policy_.get(),
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.cc b/content/browser/dom_storage/dom_storage_context_wrapper.cc
index fef44e8e..db486f3 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper.cc
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.cc
@@ -10,7 +10,9 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/file_path.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/dom_storage/dom_storage_area.h"
 #include "content/browser/dom_storage/dom_storage_context_impl.h"
 #include "content/browser/dom_storage/dom_storage_task_runner.h"
@@ -32,16 +34,15 @@
 }
 
 void GetLocalStorageUsageHelper(
-    base::MessageLoopProxy* reply_loop,
+    base::SingleThreadTaskRunner* reply_task_runner,
     DOMStorageContextImpl* context,
     const DOMStorageContext::GetLocalStorageUsageCallback& callback) {
   std::vector<LocalStorageUsageInfo>* infos =
       new std::vector<LocalStorageUsageInfo>;
   context->GetLocalStorageUsage(infos, true);
-  reply_loop->PostTask(
-      FROM_HERE,
-      base::Bind(&InvokeLocalStorageUsageCallbackHelper,
-                 callback, base::Owned(infos)));
+  reply_task_runner->PostTask(
+      FROM_HERE, base::Bind(&InvokeLocalStorageUsageCallbackHelper, callback,
+                            base::Owned(infos)));
 }
 
 void InvokeSessionStorageUsageCallbackHelper(
@@ -51,16 +52,15 @@
 }
 
 void GetSessionStorageUsageHelper(
-    base::MessageLoopProxy* reply_loop,
+    base::SingleThreadTaskRunner* reply_task_runner,
     DOMStorageContextImpl* context,
     const DOMStorageContext::GetSessionStorageUsageCallback& callback) {
   std::vector<SessionStorageUsageInfo>* infos =
       new std::vector<SessionStorageUsageInfo>;
   context->GetSessionStorageUsage(infos);
-  reply_loop->PostTask(
-      FROM_HERE,
-      base::Bind(&InvokeSessionStorageUsageCallbackHelper,
-                 callback, base::Owned(infos)));
+  reply_task_runner->PostTask(
+      FROM_HERE, base::Bind(&InvokeSessionStorageUsageCallbackHelper, callback,
+                            base::Owned(infos)));
 }
 
 }  // namespace
@@ -89,25 +89,19 @@
 void DOMStorageContextWrapper::GetLocalStorageUsage(
     const GetLocalStorageUsageCallback& callback) {
   DCHECK(context_.get());
-  context_->task_runner()
-      ->PostShutdownBlockingTask(FROM_HERE,
-                                 DOMStorageTaskRunner::PRIMARY_SEQUENCE,
-                                 base::Bind(&GetLocalStorageUsageHelper,
-                                            base::MessageLoopProxy::current(),
-                                            context_,
-                                            callback));
+  context_->task_runner()->PostShutdownBlockingTask(
+      FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE,
+      base::Bind(&GetLocalStorageUsageHelper,
+                 base::ThreadTaskRunnerHandle::Get(), context_, callback));
 }
 
 void DOMStorageContextWrapper::GetSessionStorageUsage(
     const GetSessionStorageUsageCallback& callback) {
   DCHECK(context_.get());
-  context_->task_runner()
-      ->PostShutdownBlockingTask(FROM_HERE,
-                                 DOMStorageTaskRunner::PRIMARY_SEQUENCE,
-                                 base::Bind(&GetSessionStorageUsageHelper,
-                                            base::MessageLoopProxy::current(),
-                                            context_,
-                                            callback));
+  context_->task_runner()->PostShutdownBlockingTask(
+      FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE,
+      base::Bind(&GetSessionStorageUsageHelper,
+                 base::ThreadTaskRunnerHandle::Get(), context_, callback));
 }
 
 void DOMStorageContextWrapper::DeleteLocalStorage(const GURL& origin) {
diff --git a/content/browser/dom_storage/dom_storage_task_runner.cc b/content/browser/dom_storage/dom_storage_task_runner.cc
index aa75c3c..cf2204d 100644
--- a/content/browser/dom_storage/dom_storage_task_runner.cc
+++ b/content/browser/dom_storage/dom_storage_task_runner.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
 #include "base/tracked_objects.h"
 
 namespace content {
@@ -23,8 +23,8 @@
     base::SequencedWorkerPool* sequenced_worker_pool,
     base::SequencedWorkerPool::SequenceToken primary_sequence_token,
     base::SequencedWorkerPool::SequenceToken commit_sequence_token,
-    base::MessageLoopProxy* delayed_task_loop)
-    : message_loop_(delayed_task_loop),
+    base::SingleThreadTaskRunner* delayed_task_task_runner)
+    : task_runner_(delayed_task_task_runner),
       sequenced_worker_pool_(sequenced_worker_pool),
       primary_sequence_token_(primary_sequence_token),
       commit_sequence_token_(commit_sequence_token) {
@@ -46,7 +46,7 @@
         base::SequencedWorkerPool::BLOCK_SHUTDOWN);
   }
   // Post a task to call this->PostTask() after the delay.
-  return message_loop_->PostDelayedTask(
+  return task_runner_->PostDelayedTask(
       FROM_HERE,
       base::Bind(base::IgnoreResult(&DOMStorageWorkerPoolTaskRunner::PostTask),
                  this, from_here, task),
@@ -79,8 +79,8 @@
 // MockDOMStorageTaskRunner
 
 MockDOMStorageTaskRunner::MockDOMStorageTaskRunner(
-    base::MessageLoopProxy* message_loop)
-    : message_loop_(message_loop) {
+    base::SingleThreadTaskRunner* task_runner)
+    : task_runner_(task_runner) {
 }
 
 MockDOMStorageTaskRunner::~MockDOMStorageTaskRunner() {
@@ -90,18 +90,18 @@
     const tracked_objects::Location& from_here,
     const base::Closure& task,
     base::TimeDelta delay) {
-  return message_loop_->PostTask(from_here, task);
+  return task_runner_->PostTask(from_here, task);
 }
 
 bool MockDOMStorageTaskRunner::PostShutdownBlockingTask(
     const tracked_objects::Location& from_here,
     SequenceID sequence_id,
     const base::Closure& task) {
-  return message_loop_->PostTask(from_here, task);
+  return task_runner_->PostTask(from_here, task);
 }
 
 bool MockDOMStorageTaskRunner::IsRunningOnSequence(SequenceID) const {
-  return message_loop_->RunsTasksOnCurrentThread();
+  return task_runner_->RunsTasksOnCurrentThread();
 }
 
 }  // namespace content
diff --git a/content/browser/dom_storage/dom_storage_task_runner.h b/content/browser/dom_storage/dom_storage_task_runner.h
index 1d4485c9b..f71c9c8b 100644
--- a/content/browser/dom_storage/dom_storage_task_runner.h
+++ b/content/browser/dom_storage/dom_storage_task_runner.h
@@ -7,12 +7,13 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/time/time.h"
 #include "content/common/content_export.h"
 
 namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
 }
 
 namespace content {
@@ -73,7 +74,7 @@
       base::SequencedWorkerPool* sequenced_worker_pool,
       base::SequencedWorkerPool::SequenceToken primary_sequence_token,
       base::SequencedWorkerPool::SequenceToken commit_sequence_token,
-      base::MessageLoopProxy* delayed_task_loop);
+      base::SingleThreadTaskRunner* delayed_task_task_runner);
 
   bool PostDelayedTask(const tracked_objects::Location& from_here,
                        const base::Closure& task,
@@ -92,7 +93,7 @@
 
   base::SequencedWorkerPool::SequenceToken IDtoToken(SequenceID id) const;
 
-  const scoped_refptr<base::MessageLoopProxy> message_loop_;
+  const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   const scoped_refptr<base::SequencedWorkerPool> sequenced_worker_pool_;
   base::SequencedWorkerPool::SequenceToken primary_sequence_token_;
   base::SequencedWorkerPool::SequenceToken commit_sequence_token_;
@@ -106,7 +107,7 @@
 class CONTENT_EXPORT MockDOMStorageTaskRunner :
       public DOMStorageTaskRunner {
  public:
-  explicit MockDOMStorageTaskRunner(base::MessageLoopProxy* message_loop);
+  explicit MockDOMStorageTaskRunner(base::SingleThreadTaskRunner* task_runner);
 
   bool PostDelayedTask(const tracked_objects::Location& from_here,
                        const base::Closure& task,
@@ -122,7 +123,7 @@
   ~MockDOMStorageTaskRunner() override;
 
  private:
-  const scoped_refptr<base::MessageLoopProxy> message_loop_;
+  const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 };
 
 }  // namespace content
diff --git a/content/browser/download/download_file_impl.cc b/content/browser/download/download_file_impl.cc
index 5597703..3436722 100644
--- a/content/browser/download/download_file_impl.cc
+++ b/content/browser/download/download_file_impl.cc
@@ -8,7 +8,6 @@
 
 #include "base/bind.h"
 #include "base/files/file_util.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "base/values.h"
diff --git a/content/browser/download/download_file_unittest.cc b/content/browser/download/download_file_unittest.cc
index 620efa3..59cc4a76 100644
--- a/content/browser/download/download_file_unittest.cc
+++ b/content/browser/download/download_file_unittest.cc
@@ -4,10 +4,12 @@
 
 #include "base/files/file.h"
 #include "base/files/file_util.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/test_file_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/byte_stream.h"
 #include "content/browser/download/download_create_info.h"
@@ -650,16 +652,16 @@
     // Rename() will be in front of the QuitClosure(). Running the message loop
     // now causes the just the first retry task to be run. The rename still
     // fails, so another retry task would get queued behind the QuitClosure().
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           first_failing_run.QuitClosure());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, first_failing_run.QuitClosure());
     first_failing_run.Run();
     EXPECT_FALSE(did_run_callback);
 
     // Running another loop should have the same effect as the above as long as
     // kMaxRenameRetries is greater than 2.
     base::RunLoop second_failing_run;
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           second_failing_run.QuitClosure());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, second_failing_run.QuitClosure());
     second_failing_run.Run();
     EXPECT_FALSE(did_run_callback);
   }
@@ -775,9 +777,9 @@
   AppendDataToFile(chunks1, 2);
 
   // Run the message loops for 750ms and check for results.
-  loop_.PostDelayedTask(FROM_HERE,
-                        base::MessageLoop::QuitClosure(),
-                        base::TimeDelta::FromMilliseconds(750));
+  loop_.task_runner()->PostDelayedTask(FROM_HERE,
+                                       base::MessageLoop::QuitClosure(),
+                                       base::TimeDelta::FromMilliseconds(750));
   loop_.Run();
 
   EXPECT_EQ(static_cast<int64>(strlen(kTestData1) + strlen(kTestData2)),
diff --git a/content/browser/download/download_resource_handler.cc b/content/browser/download/download_resource_handler.cc
index ee610e4b..99a57b1 100644
--- a/content/browser/download/download_resource_handler.cc
+++ b/content/browser/download/download_resource_handler.cc
@@ -7,11 +7,13 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/sparse_histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/byte_stream.h"
 #include "content/browser/download/download_create_info.h"
 #include "content/browser/download/download_interrupt_reasons_impl.h"
@@ -191,7 +193,7 @@
   // Create the ByteStream for sending data to the download sink.
   scoped_ptr<ByteStreamReader> stream_reader;
   CreateByteStream(
-      base::MessageLoopProxy::current(),
+      base::ThreadTaskRunnerHandle::Get(),
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
       kDownloadByteStreamSize, &stream_writer_, &stream_reader);
   stream_writer_->RegisterCallback(
diff --git a/content/browser/download/drag_download_file.cc b/content/browser/download/drag_download_file.cc
index 13950a1..2014270 100644
--- a/content/browser/download/drag_download_file.cc
+++ b/content/browser/download/drag_download_file.cc
@@ -6,7 +6,8 @@
 
 #include "base/bind.h"
 #include "base/files/file.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "content/browser/download/download_stats.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/browser_context.h"
@@ -94,7 +95,8 @@
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
     if (!item) {
       DCHECK_NE(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
-      on_completed_loop_->PostTask(FROM_HERE, base::Bind(on_completed_, false));
+      on_completed_loop_->task_runner()->PostTask(
+          FROM_HERE, base::Bind(on_completed_, false));
       return;
     }
     DCHECK_EQ(DOWNLOAD_INTERRUPT_REASON_NONE, interrupt_reason);
@@ -111,8 +113,9 @@
         state == DownloadItem::CANCELLED ||
         state == DownloadItem::INTERRUPTED) {
       if (!on_completed_.is_null()) {
-        on_completed_loop_->PostTask(FROM_HERE, base::Bind(
-            on_completed_, state == DownloadItem::COMPLETE));
+        on_completed_loop_->task_runner()->PostTask(
+            FROM_HERE,
+            base::Bind(on_completed_, state == DownloadItem::COMPLETE));
         on_completed_.Reset();
       }
       download_item_->RemoveObserver(this);
@@ -127,8 +130,8 @@
     if (!on_completed_.is_null()) {
       const bool is_complete =
           download_item_->GetState() == DownloadItem::COMPLETE;
-      on_completed_loop_->PostTask(FROM_HERE, base::Bind(
-          on_completed_, is_complete));
+      on_completed_loop_->task_runner()->PostTask(
+          FROM_HERE, base::Bind(on_completed_, is_complete));
       on_completed_.Reset();
     }
     download_item_->RemoveObserver(this);
diff --git a/content/browser/fileapi/blob_url_request_job_unittest.cc b/content/browser/fileapi/blob_url_request_job_unittest.cc
index ed90f1d..e2fa5fe 100644
--- a/content/browser/fileapi/blob_url_request_job_unittest.cc
+++ b/content/browser/fileapi/blob_url_request_job_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "content/browser/fileapi/mock_url_request_delegate.h"
 #include "content/public/test/async_file_test_helper.h"
@@ -71,7 +72,7 @@
       return new BlobURLRequestJob(request, network_delegate,
                                    test_->GetSnapshotFromBuilder(),
                                    test_->file_system_context_.get(),
-                                   base::MessageLoopProxy::current().get());
+                                   base::ThreadTaskRunnerHandle::Get().get());
     }
 
    private:
diff --git a/content/browser/fileapi/copy_or_move_file_validator_unittest.cc b/content/browser/fileapi/copy_or_move_file_validator_unittest.cc
index f9b8d15..c07db9d 100644
--- a/content/browser/fileapi/copy_or_move_file_validator_unittest.cc
+++ b/content/browser/fileapi/copy_or_move_file_validator_unittest.cc
@@ -6,7 +6,10 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/test/async_file_test_helper.h"
 #include "content/public/test/mock_special_storage_policy.h"
 #include "content/public/test/test_file_system_backend.h"
@@ -221,7 +224,7 @@
     void StartPreWriteValidation(
         const ResultCallback& result_callback) override {
       // Post the result since a real validator must do work asynchronously.
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, base::Bind(result_callback, result_));
     }
 
@@ -229,7 +232,7 @@
         const base::FilePath& dest_platform_path,
         const ResultCallback& result_callback) override {
       // Post the result since a real validator must do work asynchronously.
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, base::Bind(result_callback, write_result_));
     }
 
diff --git a/content/browser/fileapi/copy_or_move_operation_delegate_unittest.cc b/content/browser/fileapi/copy_or_move_operation_delegate_unittest.cc
index 451353d1..bbcae16 100644
--- a/content/browser/fileapi/copy_or_move_operation_delegate_unittest.cc
+++ b/content/browser/fileapi/copy_or_move_operation_delegate_unittest.cc
@@ -9,9 +9,11 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/quota/mock_quota_manager.h"
 #include "content/browser/quota/mock_quota_manager_proxy.h"
 #include "content/public/test/async_file_test_helper.h"
@@ -79,7 +81,7 @@
     void StartPreWriteValidation(
         const ResultCallback& result_callback) override {
       // Post the result since a real validator must do work asynchronously.
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, base::Bind(result_callback, result_));
     }
 
@@ -92,7 +94,7 @@
         result = base::File::FILE_ERROR_SECURITY;
       }
       // Post the result since a real validator must do work asynchronously.
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, base::Bind(result_callback, result));
     }
 
@@ -147,7 +149,7 @@
     if (thread_) {
       // Give another chance for deleted streams to perform Close.
       base::RunLoop run_loop;
-      thread_->message_loop_proxy()->PostTaskAndReply(
+      thread_->task_runner()->PostTaskAndReply(
           FROM_HERE, base::Bind(&base::DoNothing), run_loop.QuitClosure());
       run_loop.Run();
       thread_->Stop();
@@ -191,13 +193,12 @@
     ASSERT_TRUE(base_.CreateUniqueTempDir());
     base::FilePath base_dir = base_.path();
     quota_manager_ =
-        new MockQuotaManager(false /* is_incognito */,
-                                    base_dir,
-                                    base::MessageLoopProxy::current().get(),
-                                    base::MessageLoopProxy::current().get(),
-                                    NULL /* special storage policy */);
+        new MockQuotaManager(false /* is_incognito */, base_dir,
+                             base::ThreadTaskRunnerHandle::Get().get(),
+                             base::ThreadTaskRunnerHandle::Get().get(),
+                             NULL /* special storage policy */);
     quota_manager_proxy_ = new MockQuotaManagerProxy(
-        quota_manager_.get(), base::MessageLoopProxy::current().get());
+        quota_manager_.get(), base::ThreadTaskRunnerHandle::Get().get());
     file_system_context_ =
         CreateFileSystemContextForTesting(quota_manager_proxy_.get(), base_dir);
 
@@ -728,8 +729,8 @@
   ScopedThreadStopper thread_stopper(&file_thread);
   ASSERT_TRUE(thread_stopper.is_valid());
 
-  scoped_refptr<base::MessageLoopProxy> task_runner =
-      file_thread.message_loop_proxy();
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+      file_thread.task_runner();
 
   scoped_ptr<storage::FileStreamReader> reader(
       storage::FileStreamReader::CreateForLocalFile(
@@ -784,8 +785,8 @@
   ScopedThreadStopper thread_stopper(&file_thread);
   ASSERT_TRUE(thread_stopper.is_valid());
 
-  scoped_refptr<base::MessageLoopProxy> task_runner =
-      file_thread.message_loop_proxy();
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+      file_thread.task_runner();
 
   scoped_ptr<storage::FileStreamReader> reader(
       storage::FileStreamReader::CreateForLocalFile(
@@ -835,8 +836,8 @@
   ScopedThreadStopper thread_stopper(&file_thread);
   ASSERT_TRUE(thread_stopper.is_valid());
 
-  scoped_refptr<base::MessageLoopProxy> task_runner =
-      file_thread.message_loop_proxy();
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+      file_thread.task_runner();
 
   scoped_ptr<storage::FileStreamReader> reader(
       storage::FileStreamReader::CreateForLocalFile(
@@ -854,7 +855,7 @@
       base::TimeDelta());  // For testing, we need all the progress.
 
   // Call Cancel() later.
-  base::MessageLoopProxy::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&CopyOrMoveOperationDelegate::StreamCopyHelper::Cancel,
                  base::Unretained(&helper)));
diff --git a/content/browser/fileapi/dragged_file_util_unittest.cc b/content/browser/fileapi/dragged_file_util_unittest.cc
index 98b2ceec..38d8337 100644
--- a/content/browser/fileapi/dragged_file_util_unittest.cc
+++ b/content/browser/fileapi/dragged_file_util_unittest.cc
@@ -13,7 +13,6 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/time/time.h"
 #include "content/public/test/async_file_test_helper.h"
 #include "content/public/test/test_file_system_context.h"
diff --git a/content/browser/fileapi/file_system_browsertest.cc b/content/browser/fileapi/file_system_browsertest.cc
index 79e9f3cb..5ff9600 100644
--- a/content/browser/fileapi/file_system_browsertest.cc
+++ b/content/browser/fileapi/file_system_browsertest.cc
@@ -5,7 +5,9 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
 #include "base/test/thread_test_helper.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/browser_context.h"
diff --git a/content/browser/fileapi/file_system_context_unittest.cc b/content/browser/fileapi/file_system_context_unittest.cc
index c071c4b4..b1ffb63 100644
--- a/content/browser/fileapi/file_system_context_unittest.cc
+++ b/content/browser/fileapi/file_system_context_unittest.cc
@@ -5,8 +5,8 @@
 #include "storage/browser/fileapi/file_system_context.h"
 
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/quota/mock_quota_manager.h"
 #include "content/public/test/mock_special_storage_policy.h"
 #include "content/public/test/test_file_system_options.h"
@@ -54,26 +54,21 @@
 
     storage_policy_ = new MockSpecialStoragePolicy();
 
-    mock_quota_manager_ =
-        new MockQuotaManager(false /* is_incognito */,
-                                    data_dir_.path(),
-                                    base::MessageLoopProxy::current().get(),
-                                    base::MessageLoopProxy::current().get(),
-                                    storage_policy_.get());
+    mock_quota_manager_ = new MockQuotaManager(
+        false /* is_incognito */, data_dir_.path(),
+        base::ThreadTaskRunnerHandle::Get().get(),
+        base::ThreadTaskRunnerHandle::Get().get(), storage_policy_.get());
   }
 
  protected:
   FileSystemContext* CreateFileSystemContextForTest(
       storage::ExternalMountPoints* external_mount_points) {
     return new FileSystemContext(
-        base::MessageLoopProxy::current().get(),
-        base::MessageLoopProxy::current().get(),
-        external_mount_points,
-        storage_policy_.get(),
-        mock_quota_manager_->proxy(),
+        base::ThreadTaskRunnerHandle::Get().get(),
+        base::ThreadTaskRunnerHandle::Get().get(), external_mount_points,
+        storage_policy_.get(), mock_quota_manager_->proxy(),
         ScopedVector<FileSystemBackend>(),
-        std::vector<storage::URLRequestAutoMountHandler>(),
-        data_dir_.path(),
+        std::vector<storage::URLRequestAutoMountHandler>(), data_dir_.path(),
         CreateAllowFileAccessOptions());
   }
 
diff --git a/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc b/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc
index ff913eca..43dd8129 100644
--- a/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc
+++ b/content/browser/fileapi/file_system_dir_url_request_job_unittest.cc
@@ -10,12 +10,13 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/format_macros.h"
+#include "base/location.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/test/mock_special_storage_policy.h"
 #include "content/public/test/test_file_system_backend.h"
 #include "content/public/test/test_file_system_context.h"
@@ -153,7 +154,7 @@
 
     ScopedVector<storage::FileSystemBackend> additional_providers;
     additional_providers.push_back(new TestFileSystemBackend(
-        base::MessageLoopProxy::current().get(), *mnt_point));
+        base::ThreadTaskRunnerHandle::Get().get(), *mnt_point));
 
     std::vector<storage::URLRequestAutoMountHandler> handlers;
     handlers.push_back(base::Bind(&TestAutoMountForURLRequest));
@@ -285,7 +286,7 @@
   }
 
   // Put the message loop at the top, so that it's the last thing deleted.
-  // Delete all MessageLoopProxy objects before the MessageLoop, to help prevent
+  // Delete all task runner objects before the MessageLoop, to help prevent
   // leaks caused by tasks posted during shutdown.
   base::MessageLoopForIO message_loop_;
 
diff --git a/content/browser/fileapi/file_system_operation_impl_unittest.cc b/content/browser/fileapi/file_system_operation_impl_unittest.cc
index 6f84204a..e4a1e6c 100644
--- a/content/browser/fileapi/file_system_operation_impl_unittest.cc
+++ b/content/browser/fileapi/file_system_operation_impl_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/fileapi/mock_file_change_observer.h"
 #include "content/browser/fileapi/mock_file_update_observer.h"
 #include "content/browser/quota/mock_quota_manager.h"
@@ -57,13 +58,12 @@
 
     base::FilePath base_dir = base_.path().AppendASCII("filesystem");
     quota_manager_ =
-        new MockQuotaManager(false /* is_incognito */,
-                                    base_dir,
-                                    base::MessageLoopProxy::current().get(),
-                                    base::MessageLoopProxy::current().get(),
-                                    NULL /* special storage policy */);
+        new MockQuotaManager(false /* is_incognito */, base_dir,
+                             base::ThreadTaskRunnerHandle::Get().get(),
+                             base::ThreadTaskRunnerHandle::Get().get(),
+                             NULL /* special storage policy */);
     quota_manager_proxy_ = new MockQuotaManagerProxy(
-        quota_manager(), base::MessageLoopProxy::current().get());
+        quota_manager(), base::ThreadTaskRunnerHandle::Get().get());
     sandbox_file_system_.SetUp(base_dir, quota_manager_proxy_.get());
     sandbox_file_system_.AddFileChangeObserver(&change_observer_);
     sandbox_file_system_.AddFileUpdateObserver(&update_observer_);
diff --git a/content/browser/fileapi/file_system_operation_impl_write_unittest.cc b/content/browser/fileapi/file_system_operation_impl_write_unittest.cc
index ca324ae..ae3277f 100644
--- a/content/browser/fileapi/file_system_operation_impl_write_unittest.cc
+++ b/content/browser/fileapi/file_system_operation_impl_write_unittest.cc
@@ -7,8 +7,8 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/fileapi/mock_file_change_observer.h"
 #include "content/browser/quota/mock_quota_manager.h"
 #include "content/public/test/mock_blob_url_request_context.h"
@@ -66,11 +66,10 @@
     ASSERT_TRUE(dir_.CreateUniqueTempDir());
 
     quota_manager_ =
-        new MockQuotaManager(false /* is_incognito */,
-                                    dir_.path(),
-                                    base::MessageLoopProxy::current().get(),
-                                    base::MessageLoopProxy::current().get(),
-                                    NULL /* special storage policy */);
+        new MockQuotaManager(false /* is_incognito */, dir_.path(),
+                             base::ThreadTaskRunnerHandle::Get().get(),
+                             base::ThreadTaskRunnerHandle::Get().get(),
+                             NULL /* special storage policy */);
     virtual_path_ = base::FilePath(FILE_PATH_LITERAL("temporary file"));
 
     file_system_context_ = CreateFileSystemContextForTesting(
diff --git a/content/browser/fileapi/file_system_quota_client_unittest.cc b/content/browser/fileapi/file_system_quota_client_unittest.cc
index 5ab33e1..b3333a0 100644
--- a/content/browser/fileapi/file_system_quota_client_unittest.cc
+++ b/content/browser/fileapi/file_system_quota_client_unittest.cc
@@ -6,7 +6,6 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
 #include "content/public/test/async_file_test_helper.h"
 #include "content/public/test/test_file_system_context.h"
diff --git a/content/browser/fileapi/file_system_url_request_job_unittest.cc b/content/browser/fileapi/file_system_url_request_job_unittest.cc
index 5e932f2b..dca1c53 100644
--- a/content/browser/fileapi/file_system_url_request_job_unittest.cc
+++ b/content/browser/fileapi/file_system_url_request_job_unittest.cc
@@ -11,15 +11,15 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/format_macros.h"
+#include "base/location.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/rand_util.h"
 #include "base/run_loop.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/test/async_file_test_helper.h"
 #include "content/public/test/test_file_system_backend.h"
 #include "content/public/test/test_file_system_context.h"
@@ -160,7 +160,7 @@
 
     ScopedVector<storage::FileSystemBackend> additional_providers;
     additional_providers.push_back(new TestFileSystemBackend(
-        base::MessageLoopProxy::current().get(), mnt_point));
+        base::ThreadTaskRunnerHandle::Get().get(), mnt_point));
 
     std::vector<storage::URLRequestAutoMountHandler> handlers;
     handlers.push_back(base::Bind(&TestAutoMountForURLRequest));
diff --git a/content/browser/fileapi/file_system_usage_cache_unittest.cc b/content/browser/fileapi/file_system_usage_cache_unittest.cc
index 13f1d65..f67485c 100644
--- a/content/browser/fileapi/file_system_usage_cache_unittest.cc
+++ b/content/browser/fileapi/file_system_usage_cache_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/message_loop/message_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using storage::FileSystemUsageCache;
@@ -17,7 +18,7 @@
 class FileSystemUsageCacheTest : public testing::Test {
  public:
   FileSystemUsageCacheTest()
-      : usage_cache_(base::MessageLoopProxy::current().get()) {}
+      : usage_cache_(base::ThreadTaskRunnerHandle::Get().get()) {}
 
   void SetUp() override { ASSERT_TRUE(data_dir_.CreateUniqueTempDir()); }
 
diff --git a/content/browser/fileapi/file_writer_delegate_unittest.cc b/content/browser/fileapi/file_writer_delegate_unittest.cc
index 1aacaccd..af60d3fc 100644
--- a/content/browser/fileapi/file_writer_delegate_unittest.cc
+++ b/content/browser/fileapi/file_writer_delegate_unittest.cc
@@ -9,8 +9,10 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/test/async_file_test_helper.h"
 #include "content/public/test/test_file_system_context.h"
 #include "net/base/io_buffer.h"
@@ -96,8 +98,8 @@
 
   int64 GetFileSizeOnDisk(const char* test_file_path) {
     // There might be in-flight flush/write.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE, base::Bind(&base::DoNothing));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(&base::DoNothing));
     base::RunLoop().RunUntilIdle();
 
     FileSystemURL url = GetFileSystemURL(test_file_path);
@@ -177,7 +179,7 @@
   }
 
   void Start() override {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&FileWriterDelegateTestJob::NotifyHeadersComplete, this));
   }
diff --git a/content/browser/fileapi/local_file_stream_reader_unittest.cc b/content/browser/fileapi/local_file_stream_reader_unittest.cc
index 5e17165d..d8e30ce 100644
--- a/content/browser/fileapi/local_file_stream_reader_unittest.cc
+++ b/content/browser/fileapi/local_file_stream_reader_unittest.cc
@@ -10,8 +10,10 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
@@ -101,8 +103,8 @@
                                 new_modified_time));
   }
 
-  base::MessageLoopProxy* file_task_runner() const {
-    return file_thread_.message_loop_proxy().get();
+  base::SingleThreadTaskRunner* file_task_runner() const {
+    return file_thread_.task_runner().get();
   }
 
   base::FilePath test_dir() const { return dir_.path(); }
diff --git a/content/browser/fileapi/local_file_stream_writer_unittest.cc b/content/browser/fileapi/local_file_stream_writer_unittest.cc
index 48f5560..9e05310e 100644
--- a/content/browser/fileapi/local_file_stream_writer_unittest.cc
+++ b/content/browser/fileapi/local_file_stream_writer_unittest.cc
@@ -11,8 +11,8 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "net/base/io_buffer.h"
 #include "net/base/test_completion_callback.h"
@@ -77,8 +77,8 @@
     return path;
   }
 
-  base::MessageLoopProxy* file_task_runner() const {
-    return file_thread_.message_loop_proxy().get();
+  base::SingleThreadTaskRunner* file_task_runner() const {
+    return file_thread_.task_runner().get();
   }
 
   LocalFileStreamWriter* CreateWriter(const base::FilePath& path,
diff --git a/content/browser/fileapi/local_file_util_unittest.cc b/content/browser/fileapi/local_file_util_unittest.cc
index bf2f2f8..a0c9615 100644
--- a/content/browser/fileapi/local_file_util_unittest.cc
+++ b/content/browser/fileapi/local_file_util_unittest.cc
@@ -8,7 +8,6 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/content/browser/fileapi/mock_file_change_observer.cc b/content/browser/fileapi/mock_file_change_observer.cc
index f6a86e9..6677607 100644
--- a/content/browser/fileapi/mock_file_change_observer.cc
+++ b/content/browser/fileapi/mock_file_change_observer.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/fileapi/mock_file_change_observer.h"
 
+#include "base/thread_task_runner_handle.h"
+
 namespace storage {
 
 MockFileChangeObserver::MockFileChangeObserver()
@@ -20,7 +22,7 @@
 ChangeObserverList MockFileChangeObserver::CreateList(
     MockFileChangeObserver* observer) {
   ChangeObserverList list;
-  return list.AddObserver(observer, base::MessageLoopProxy::current().get());
+  return list.AddObserver(observer, base::ThreadTaskRunnerHandle::Get().get());
 }
 
 void MockFileChangeObserver::OnCreateFile(const FileSystemURL& url) {
diff --git a/content/browser/fileapi/obfuscated_file_util_unittest.cc b/content/browser/fileapi/obfuscated_file_util_unittest.cc
index 7abaf7e8..06638ff 100644
--- a/content/browser/fileapi/obfuscated_file_util_unittest.cc
+++ b/content/browser/fileapi/obfuscated_file_util_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/fileapi/mock_file_change_observer.h"
 #include "content/public/test/async_file_test_helper.h"
 #include "content/public/test/mock_special_storage_policy.h"
@@ -156,12 +157,10 @@
 
     storage_policy_ = new MockSpecialStoragePolicy();
 
-    quota_manager_ =
-        new storage::QuotaManager(false /* is_incognito */,
-                                  data_dir_.path(),
-                                  base::MessageLoopProxy::current().get(),
-                                  base::MessageLoopProxy::current().get(),
-                                  storage_policy_.get());
+    quota_manager_ = new storage::QuotaManager(
+        false /* is_incognito */, data_dir_.path(),
+        base::ThreadTaskRunnerHandle::Get().get(),
+        base::ThreadTaskRunnerHandle::Get().get(), storage_policy_.get());
 
     // Every time we create a new sandbox_file_system helper,
     // it creates another context, which creates another path manager,
@@ -231,10 +230,9 @@
 
   scoped_ptr<ObfuscatedFileUtil> CreateObfuscatedFileUtil(
       storage::SpecialStoragePolicy* storage_policy) {
-    return scoped_ptr<ObfuscatedFileUtil>(
-      ObfuscatedFileUtil::CreateForTesting(
-          storage_policy, data_dir_path(), NULL,
-          base::MessageLoopProxy::current().get()));
+    return scoped_ptr<ObfuscatedFileUtil>(ObfuscatedFileUtil::CreateForTesting(
+        storage_policy, data_dir_path(), NULL,
+        base::ThreadTaskRunnerHandle::Get().get()));
   }
 
   ObfuscatedFileUtil* ofu() {
diff --git a/content/browser/fileapi/plugin_private_file_system_backend_unittest.cc b/content/browser/fileapi/plugin_private_file_system_backend_unittest.cc
index ef88fed..8c5e45d0d 100644
--- a/content/browser/fileapi/plugin_private_file_system_backend_unittest.cc
+++ b/content/browser/fileapi/plugin_private_file_system_backend_unittest.cc
@@ -7,7 +7,6 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
 #include "content/public/test/async_file_test_helper.h"
 #include "content/public/test/test_file_system_context.h"
diff --git a/content/browser/fileapi/recursive_operation_delegate_unittest.cc b/content/browser/fileapi/recursive_operation_delegate_unittest.cc
index 3885384..54b9626a 100644
--- a/content/browser/fileapi/recursive_operation_delegate_unittest.cc
+++ b/content/browser/fileapi/recursive_operation_delegate_unittest.cc
@@ -10,9 +10,10 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/test/sandbox_file_system_test_helper.h"
 #include "storage/browser/fileapi/file_system_file_util.h"
 #include "storage/browser/fileapi/file_system_operation.h"
@@ -115,7 +116,7 @@
 void CallCancelLater(storage::RecursiveOperationDelegate* operation,
                      int counter) {
   if (counter > 0) {
-    base::MessageLoopProxy::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&CallCancelLater, base::Unretained(operation), counter - 1));
     return;
diff --git a/content/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc b/content/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc
index 1b5b19b1..fd25aa7f 100644
--- a/content/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc
+++ b/content/browser/fileapi/sandbox_file_system_backend_delegate_unittest.cc
@@ -8,8 +8,7 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/test/test_file_system_options.h"
 #include "storage/browser/fileapi/file_system_url.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -37,10 +36,8 @@
     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
     delegate_.reset(new storage::SandboxFileSystemBackendDelegate(
         NULL /* quota_manager_proxy */,
-        base::MessageLoopProxy::current().get(),
-        data_dir_.path(),
-        NULL /* special_storage_policy */,
-        CreateAllowFileAccessOptions()));
+        base::ThreadTaskRunnerHandle::Get().get(), data_dir_.path(),
+        NULL /* special_storage_policy */, CreateAllowFileAccessOptions()));
   }
 
   bool IsAccessValid(const FileSystemURL& url) const {
diff --git a/content/browser/fileapi/sandbox_file_system_backend_unittest.cc b/content/browser/fileapi/sandbox_file_system_backend_unittest.cc
index efa7259..38630b8 100644
--- a/content/browser/fileapi/sandbox_file_system_backend_unittest.cc
+++ b/content/browser/fileapi/sandbox_file_system_backend_unittest.cc
@@ -10,8 +10,8 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/test/test_file_system_options.h"
 #include "storage/browser/fileapi/file_system_backend.h"
 #include "storage/browser/fileapi/file_system_url.h"
@@ -79,10 +79,8 @@
   void SetUpNewDelegate(const storage::FileSystemOptions& options) {
     delegate_.reset(new SandboxFileSystemBackendDelegate(
         NULL /* quota_manager_proxy */,
-        base::MessageLoopProxy::current().get(),
-        data_dir_.path(),
-        NULL /* special_storage_policy */,
-        options));
+        base::ThreadTaskRunnerHandle::Get().get(), data_dir_.path(),
+        NULL /* special_storage_policy */, options));
   }
 
   void SetUpNewBackend(const storage::FileSystemOptions& options) {
diff --git a/content/browser/fileapi/timed_task_helper_unittest.cc b/content/browser/fileapi/timed_task_helper_unittest.cc
index 5a6ac8d..1bdc25d 100644
--- a/content/browser/fileapi/timed_task_helper_unittest.cc
+++ b/content/browser/fileapi/timed_task_helper_unittest.cc
@@ -6,8 +6,8 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "storage/browser/fileapi/timed_task_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -21,7 +21,8 @@
 class Embedder {
  public:
   Embedder()
-      : timer_(base::MessageLoopProxy::current().get()), timer_fired_(false) {}
+      : timer_(base::ThreadTaskRunnerHandle::Get().get()),
+        timer_fired_(false) {}
 
   void OnTimerFired() {
     timer_fired_ = true;
diff --git a/content/browser/frame_host/frame_navigation_entry.cc b/content/browser/frame_host/frame_navigation_entry.cc
index 02af2af..b2def39 100644
--- a/content/browser/frame_host/frame_navigation_entry.cc
+++ b/content/browser/frame_host/frame_navigation_entry.cc
@@ -25,16 +25,18 @@
 
 FrameNavigationEntry* FrameNavigationEntry::Clone() const {
   FrameNavigationEntry* copy = new FrameNavigationEntry(frame_tree_node_id_);
-  copy->UpdateEntry(site_instance_.get(), url_, referrer_);
+  copy->UpdateEntry(site_instance_.get(), url_, referrer_, page_state_);
   return copy;
 }
 
 void FrameNavigationEntry::UpdateEntry(SiteInstanceImpl* site_instance,
                                        const GURL& url,
-                                       const Referrer& referrer) {
+                                       const Referrer& referrer,
+                                       const PageState& page_state) {
   site_instance_ = site_instance;
   url_ = url;
   referrer_ = referrer;
+  page_state_ = page_state;
 }
 
 }  // namespace content
diff --git a/content/browser/frame_host/frame_navigation_entry.h b/content/browser/frame_host/frame_navigation_entry.h
index 15d224c..6fbd7541 100644
--- a/content/browser/frame_host/frame_navigation_entry.h
+++ b/content/browser/frame_host/frame_navigation_entry.h
@@ -8,6 +8,7 @@
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
 #include "content/browser/site_instance_impl.h"
+#include "content/public/common/page_state.h"
 #include "content/public/common/referrer.h"
 
 namespace content {
@@ -41,7 +42,8 @@
   // Updates all the members of this entry.
   void UpdateEntry(SiteInstanceImpl* site_instance,
                    const GURL& url,
-                   const Referrer& referrer);
+                   const Referrer& referrer,
+                   const PageState& page_state);
 
   // The ID of the FrameTreeNode this entry is for.  -1 for the main frame,
   // since we don't always know the FrameTreeNode ID when creating the overall
@@ -67,6 +69,9 @@
   void set_referrer(const Referrer& referrer) { referrer_ = referrer; }
   const Referrer& referrer() const { return referrer_; }
 
+  void set_page_state(const PageState& page_state) { page_state_ = page_state; }
+  const PageState& page_state() const { return page_state_; }
+
  private:
   friend class base::RefCounted<FrameNavigationEntry>;
   virtual ~FrameNavigationEntry();
@@ -82,6 +87,8 @@
   scoped_refptr<SiteInstanceImpl> site_instance_;
   GURL url_;
   Referrer referrer_;
+  // TODO(creis): Change this to FrameState.
+  PageState page_state_;
 
   DISALLOW_COPY_AND_ASSIGN(FrameNavigationEntry);
 };
diff --git a/content/browser/frame_host/frame_tree.cc b/content/browser/frame_host/frame_tree.cc
index e463c3ce..814980e 100644
--- a/content/browser/frame_host/frame_tree.cc
+++ b/content/browser/frame_host/frame_tree.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/command_line.h"
 #include "base/containers/hash_tables.h"
 #include "base/lazy_instance.h"
 #include "content/browser/frame_host/frame_tree_node.h"
@@ -17,6 +18,7 @@
 #include "content/browser/frame_host/render_frame_proxy_host.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/public/common/content_switches.h"
 #include "third_party/WebKit/public/web/WebSandboxFlags.h"
 
 namespace content {
@@ -226,9 +228,14 @@
     RenderViewHostImpl* render_view_host =
         source->frame_tree()->GetRenderViewHost(site_instance);
     if (!render_view_host) {
-      root()->render_manager()->CreateRenderFrame(
-          site_instance, nullptr, MSG_ROUTING_NONE,
-          CREATE_RF_SWAPPED_OUT | CREATE_RF_HIDDEN, nullptr);
+      if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kSitePerProcess)) {
+        root()->render_manager()->CreateRenderFrameProxy(site_instance);
+      } else {
+        root()->render_manager()->CreateRenderFrame(
+            site_instance, nullptr, MSG_ROUTING_NONE,
+            CREATE_RF_SWAPPED_OUT | CREATE_RF_HIDDEN, nullptr);
+      }
     } else {
       root()->render_manager()->EnsureRenderViewInitialized(
           source, render_view_host, site_instance);
@@ -265,7 +272,6 @@
                                                     int main_frame_routing_id,
                                                     bool swapped_out,
                                                     bool hidden) {
-  DCHECK(main_frame_routing_id != MSG_ROUTING_NONE);
   RenderViewHostMap::iterator iter =
       render_view_host_map_.find(site_instance->GetId());
   if (iter != render_view_host_map_.end()) {
@@ -274,7 +280,8 @@
     // Otherwise return the existing RenderViewHost for the SiteInstance.
     RenderFrameHostImpl* main_frame = static_cast<RenderFrameHostImpl*>(
         iter->second->GetMainFrame());
-    if (main_frame->frame_tree_node()->render_manager()->IsPendingDeletion(
+    if (main_frame &&
+        main_frame->frame_tree_node()->render_manager()->IsPendingDeletion(
             main_frame)) {
       render_view_host_pending_shutdown_map_.insert(
           std::pair<int, RenderViewHostImpl*>(site_instance->GetId(),
diff --git a/content/browser/frame_host/frame_tree_unittest.cc b/content/browser/frame_host/frame_tree_unittest.cc
index d74d97c..fa01867 100644
--- a/content/browser/frame_host/frame_tree_unittest.cc
+++ b/content/browser/frame_host/frame_tree_unittest.cc
@@ -229,9 +229,12 @@
 
 // Ensure frames can be found by frame_tree_node_id, routing ID, or name.
 TEST_F(FrameTreeTest, FindFrames) {
+  main_test_rfh()->InitializeRenderFrameIfNeeded();
+
   // Add a few child frames to the main frame.
   FrameTree* frame_tree = contents()->GetFrameTree();
   FrameTreeNode* root = frame_tree->root();
+
   main_test_rfh()->OnCreateChildFrame(22, blink::WebTreeScopeType::Document,
                                       "child0", blink::WebSandboxFlags::None);
   main_test_rfh()->OnCreateChildFrame(23, blink::WebTreeScopeType::Document,
@@ -278,6 +281,8 @@
 
 // Check that PreviousSibling() is retrieved correctly.
 TEST_F(FrameTreeTest, PreviousSibling) {
+  main_test_rfh()->InitializeRenderFrameIfNeeded();
+
   // Add a few child frames to the main frame.
   FrameTree* frame_tree = contents()->GetFrameTree();
   FrameTreeNode* root = frame_tree->root();
@@ -387,6 +392,8 @@
 // Ensure that frames removed while a process has crashed are not preserved in
 // the global map of id->frame.
 TEST_F(FrameTreeTest, ProcessCrashClearsGlobalMap) {
+  main_test_rfh()->InitializeRenderFrameIfNeeded();
+
   // Add a couple child frames to the main frame.
   FrameTreeNode* root = contents()->GetFrameTree()->root();
 
diff --git a/content/browser/frame_host/interstitial_page_impl.cc b/content/browser/frame_host/interstitial_page_impl.cc
index 455ac74..88d720f 100644
--- a/content/browser/frame_host/interstitial_page_impl.cc
+++ b/content/browser/frame_host/interstitial_page_impl.cc
@@ -8,9 +8,11 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "content/browser/dom_storage/dom_storage_context_wrapper.h"
 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
@@ -289,10 +291,9 @@
   // Delete this and call Shutdown on the RVH asynchronously, as we may have
   // been called from a RVH delegate method, and we can't delete the RVH out
   // from under itself.
-  base::MessageLoop::current()->PostNonNestableTask(
-      FROM_HERE,
-      base::Bind(&InterstitialPageImpl::Shutdown,
-                 weak_ptr_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostNonNestableTask(
+      FROM_HERE, base::Bind(&InterstitialPageImpl::Shutdown,
+                            weak_ptr_factory_.GetWeakPtr()));
   render_view_host_ = NULL;
   frame_tree_.root()->ResetForNewProcess();
   controller_->delegate()->DetachInterstitialPage();
@@ -565,6 +566,7 @@
                                       MSG_ROUTING_NONE,
                                       MSG_ROUTING_NONE,
                                       max_page_id,
+                                      FrameReplicationState(),
                                       false);
   controller_->delegate()->RenderFrameForInterstitialPageCreated(
       frame_tree_.root()->current_frame_host());
diff --git a/content/browser/frame_host/navigation_controller_android.cc b/content/browser/frame_host/navigation_controller_android.cc
index 4820dc07..686403e 100644
--- a/content/browser/frame_host/navigation_controller_android.cc
+++ b/content/browser/frame_host/navigation_controller_android.cc
@@ -340,4 +340,35 @@
   return navigation_controller_->RemoveEntryAtIndex(index);
 }
 
+jboolean NavigationControllerAndroid::CanCopyStateOver(JNIEnv* env,
+                                                       jobject obj) {
+  return navigation_controller_->GetEntryCount() == 0 &&
+      !navigation_controller_->GetPendingEntry();
+}
+
+jboolean NavigationControllerAndroid::CanPruneAllButLastCommitted(JNIEnv* env,
+                                                                  jobject obj) {
+  return navigation_controller_->CanPruneAllButLastCommitted();
+}
+
+void NavigationControllerAndroid::CopyStateFrom(
+    JNIEnv* env,
+    jobject obj,
+    jlong source_navigation_controller_android) {
+  navigation_controller_->CopyStateFrom(
+      *(reinterpret_cast<NavigationControllerAndroid*>(
+          source_navigation_controller_android)->navigation_controller_));
+}
+
+void NavigationControllerAndroid::CopyStateFromAndPrune(
+    JNIEnv* env,
+    jobject obj,
+    jlong source_navigation_controller_android,
+    jboolean replace_entry) {
+  navigation_controller_->CopyStateFromAndPrune(
+      reinterpret_cast<NavigationControllerAndroid*>(
+          source_navigation_controller_android)->navigation_controller_,
+      replace_entry);
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/navigation_controller_android.h b/content/browser/frame_host/navigation_controller_android.h
index 591d095..0d67d1c13 100644
--- a/content/browser/frame_host/navigation_controller_android.h
+++ b/content/browser/frame_host/navigation_controller_android.h
@@ -83,6 +83,15 @@
   void ClearHistory(JNIEnv* env, jobject obj);
   int GetLastCommittedEntryIndex(JNIEnv* env, jobject obj);
   jboolean RemoveEntryAtIndex(JNIEnv* env, jobject obj, jint index);
+  jboolean CanCopyStateOver(JNIEnv* env, jobject obj);
+  jboolean CanPruneAllButLastCommitted(JNIEnv* env, jobject obj);
+  void CopyStateFrom(JNIEnv* env,
+                     jobject obj,
+                     jlong source_native_navigation_controller_android);
+  void CopyStateFromAndPrune(JNIEnv* env,
+                     jobject obj,
+                     jlong source_native_navigation_controller_android,
+                     jboolean replace_entry);
 
  private:
   NavigationController* navigation_controller_;
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index 253c818..5d4dee8 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -106,43 +106,6 @@
   }
 }
 
-// There are two general cases where a navigation is in page:
-// 1. A fragment navigation, in which the url is kept the same except for the
-//    reference fragment.
-// 2. A history API navigation (pushState and replaceState). This case is
-//    always in-page, but the urls are not guaranteed to match excluding the
-//    fragment. The relevant spec allows pushState/replaceState to any URL on
-//    the same origin.
-// However, due to reloads, even identical urls are *not* guaranteed to be
-// in-page navigations, we have to trust the renderer almost entirely.
-// The one thing we do know is that cross-origin navigations will *never* be
-// in-page. Therefore, trust the renderer if the URLs are on the same origin,
-// and assume the renderer is malicious if a cross-origin navigation claims to
-// be in-page.
-bool AreURLsInPageNavigation(const GURL& existing_url,
-                             const GURL& new_url,
-                             bool renderer_says_in_page,
-                             RenderFrameHost* rfh) {
-  WebPreferences prefs = rfh->GetRenderViewHost()->GetWebkitPreferences();
-  bool is_same_origin = existing_url.is_empty() ||
-                        // TODO(japhet): We should only permit navigations
-                        // originating from about:blank to be in-page if the
-                        // about:blank is the first document that frame loaded.
-                        // We don't have sufficient information to identify
-                        // that case at the moment, so always allow about:blank
-                        // for now.
-                        existing_url == GURL(url::kAboutBlankURL) ||
-                        existing_url.GetOrigin() == new_url.GetOrigin() ||
-                        !prefs.web_security_enabled ||
-                        (prefs.allow_universal_access_from_file_urls &&
-                         existing_url.SchemeIs(url::kFileScheme));
-  if (!is_same_origin && renderer_says_in_page) {
-    bad_message::ReceivedBadMessage(rfh->GetProcess(),
-                                    bad_message::NC_IN_PAGE_NAVIGATION);
-  }
-  return is_same_origin && renderer_says_in_page;
-}
-
 // Determines whether or not we should be carrying over a user agent override
 // between two NavigationEntries.
 bool ShouldKeepOverride(const NavigationEntry* last_entry) {
@@ -857,7 +820,7 @@
   }
 
   // is_in_page must be computed before the entry gets committed.
-  details->is_in_page = AreURLsInPageNavigation(rfh->GetLastCommittedURL(),
+  details->is_in_page = IsURLInPageNavigation(
       params.url, params.was_within_same_page, rfh);
 
   switch (details->type) {
@@ -914,6 +877,8 @@
   NavigationEntryImpl* active_entry = GetLastCommittedEntry();
   active_entry->SetTimestamp(timestamp);
   active_entry->SetHttpStatusCode(params.http_status_code);
+  // TODO(creis): Do this on the frame entry instead, once we have them for
+  // manual subframe navigations in --site-per-process.
   active_entry->SetPageState(params.page_state);
   active_entry->SetRedirectChain(params.redirects);
 
@@ -932,7 +897,7 @@
   // The active entry's SiteInstance should match our SiteInstance.
   // TODO(creis): This check won't pass for subframes until we create entries
   // for subframe navigations.
-  if (ui::PageTransitionIsMainFrame(params.transition))
+  if (!rfh->GetParent())
     CHECK(active_entry->site_instance() == rfh->GetSiteInstance());
 
   // Remember the bindings the renderer process has at this point, so that
@@ -941,8 +906,7 @@
 
   // Now prep the rest of the details for the notification and broadcast.
   details->entry = active_entry;
-  details->is_main_frame =
-      ui::PageTransitionIsMainFrame(params.transition);
+  details->is_main_frame = !rfh->GetParent();
   details->serialized_security_info = params.security_info;
   details->http_status_code = params.http_status_code;
   NotifyNavigationEntryCommitted(details);
@@ -980,7 +944,7 @@
     // Greater page IDs than we've ever seen before are new pages. We may or may
     // not have a pending entry for the page, and this may or may not be the
     // main frame.
-    if (ui::PageTransitionIsMainFrame(params.transition))
+    if (!rfh->GetParent())
       return NAVIGATION_TYPE_NEW_PAGE;
 
     // When this is a new subframe navigation, we should have a committed page
@@ -1044,7 +1008,7 @@
   }
   NavigationEntryImpl* existing_entry = entries_[existing_entry_index].get();
 
-  if (!ui::PageTransitionIsMainFrame(params.transition)) {
+  if (rfh->GetParent()) {
     // All manual subframes would get new IDs and were handled above, so we
     // know this is auto. Since the current page was found in the navigation
     // entry list, we're guaranteed to have a last committed entry.
@@ -1089,10 +1053,8 @@
   // the time this doesn't matter since WebKit doesn't tell us about subframe
   // navigations that don't actually navigate, but it can happen when there is
   // an encoding override (it always sends a navigation request).
-  if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url,
-                              params.was_within_same_page, rfh)) {
+  if (IsURLInPageNavigation(params.url, params.was_within_same_page, rfh))
     return NAVIGATION_TYPE_IN_PAGE;
-  }
 
   // Since we weeded out "new" navigations above, we know this is an existing
   // (back/forward) navigation.
@@ -1105,10 +1067,7 @@
   if (params.did_create_new_entry) {
     // A new entry. We may or may not have a pending entry for the page, and
     // this may or may not be the main frame.
-    if (ui::PageTransitionIsMainFrame(params.transition)) {
-      // TODO(avi): I want to use |if (!rfh->GetParent())| here but lots of unit
-      // tests fake auto subframe commits by sending the main frame a
-      // PAGE_TRANSITION_AUTO_SUBFRAME transition. Fix those, and adjust here.
+    if (!rfh->GetParent()) {
       return NAVIGATION_TYPE_NEW_PAGE;
     }
 
@@ -1127,7 +1086,7 @@
   // We only clear the session history when navigating to a new page.
   DCHECK(!params.history_list_was_cleared);
 
-  if (!ui::PageTransitionIsMainFrame(params.transition)) {
+  if (rfh->GetParent()) {
     // All manual subframes would be did_create_new_entry and handled above, so
     // we know this is auto.
     if (GetLastCommittedEntry()) {
@@ -1150,8 +1109,7 @@
     if (!last_committed)
       return NAVIGATION_TYPE_NAV_IGNORE;
 
-    if (AreURLsInPageNavigation(last_committed->GetURL(), params.url,
-                                params.was_within_same_page, rfh)) {
+    if (IsURLInPageNavigation(params.url, params.was_within_same_page, rfh)) {
       // This is history.replaceState(), which is renderer-initiated yet within
       // the same page.
       return NAVIGATION_TYPE_IN_PAGE;
@@ -1205,11 +1163,8 @@
   // of the time this doesn't matter since Blink doesn't tell us about subframe
   // navigations that don't actually navigate, but it can happen when there is
   // an encoding override (it always sends a navigation request).
-  NavigationEntryImpl* existing_entry = entries_[existing_entry_index].get();
-  if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url,
-                              params.was_within_same_page, rfh)) {
+  if (IsURLInPageNavigation(params.url, params.was_within_same_page, rfh))
     return NAVIGATION_TYPE_IN_PAGE;
-  }
 
   // Since we weeded out "new" navigations above, we know this is an existing
   // (back/forward) navigation.
@@ -1293,7 +1248,7 @@
     RenderFrameHostImpl* rfh,
     const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
   // We should only get here for main frame navigations.
-  DCHECK(ui::PageTransitionIsMainFrame(params.transition));
+  DCHECK(!rfh->GetParent());
 
   // This is a back/forward navigation. The existing page for the ID is
   // guaranteed to exist by ClassifyNavigation, and we just need to update it
@@ -1377,8 +1332,8 @@
     RenderFrameHostImpl* rfh,
     const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
     bool* did_replace_entry) {
-  DCHECK(ui::PageTransitionIsMainFrame(params.transition)) <<
-      "WebKit should only tell us about in-page navs for the main frame.";
+  DCHECK(!rfh->GetParent()) <<
+      "Blink should only tell us about in-page navs for the main frame.";
   // We're guaranteed to have an entry for this one.
   NavigationEntryImpl* existing_entry = GetEntryWithPageID(
       rfh->GetSiteInstance(), params.page_id);
@@ -1488,7 +1443,7 @@
     NavigationEntryImpl* last_committed = GetLastCommittedEntry();
     last_committed->AddOrUpdateFrameEntry(rfh->frame_tree_node(),
                                           rfh->GetSiteInstance(), params.url,
-                                          params.referrer);
+                                          params.referrer, params.page_state);
 
     // Cross-process subframe navigations may leave a pending entry around.
     // Clear it if it's actually for the subframe.
@@ -1515,13 +1470,54 @@
   return (i == entries_.end()) ? -1 : static_cast<int>(i - entries_.begin());
 }
 
+// There are two general cases where a navigation is "in page":
+// 1. A fragment navigation, in which the url is kept the same except for the
+//    reference fragment.
+// 2. A history API navigation (pushState and replaceState). This case is
+//    always in-page, but the urls are not guaranteed to match excluding the
+//    fragment. The relevant spec allows pushState/replaceState to any URL on
+//    the same origin.
+// However, due to reloads, even identical urls are *not* guaranteed to be
+// in-page navigations, we have to trust the renderer almost entirely.
+// The one thing we do know is that cross-origin navigations will *never* be
+// in-page. Therefore, trust the renderer if the URLs are on the same origin,
+// and assume the renderer is malicious if a cross-origin navigation claims to
+// be in-page.
 bool NavigationControllerImpl::IsURLInPageNavigation(
     const GURL& url,
     bool renderer_says_in_page,
     RenderFrameHost* rfh) const {
-  NavigationEntry* last_committed = GetLastCommittedEntry();
-  return last_committed && AreURLsInPageNavigation(
-      last_committed->GetURL(), url, renderer_says_in_page, rfh);
+  GURL last_committed_url;
+  if (rfh->GetParent()) {
+    last_committed_url = rfh->GetLastCommittedURL();
+  } else {
+    NavigationEntry* last_committed = GetLastCommittedEntry();
+    // There must be a last-committed entry to compare URLs to. TODO(avi): When
+    // might Blink say that a navigation is in-page yet there be no last-
+    // committed entry?
+    if (!last_committed)
+      return false;
+    last_committed_url = last_committed->GetURL();
+  }
+
+  WebPreferences prefs = rfh->GetRenderViewHost()->GetWebkitPreferences();
+  bool is_same_origin = last_committed_url.is_empty() ||
+                        // TODO(japhet): We should only permit navigations
+                        // originating from about:blank to be in-page if the
+                        // about:blank is the first document that frame loaded.
+                        // We don't have sufficient information to identify
+                        // that case at the moment, so always allow about:blank
+                        // for now.
+                        last_committed_url == GURL(url::kAboutBlankURL) ||
+                        last_committed_url.GetOrigin() == url.GetOrigin() ||
+                        !prefs.web_security_enabled ||
+                        (prefs.allow_universal_access_from_file_urls &&
+                         last_committed_url.SchemeIs(url::kFileScheme));
+  if (!is_same_origin && renderer_says_in_page) {
+    bad_message::ReceivedBadMessage(rfh->GetProcess(),
+                                    bad_message::NC_IN_PAGE_NAVIGATION);
+  }
+  return is_same_origin && renderer_says_in_page;
 }
 
 void NavigationControllerImpl::CopyStateFrom(
diff --git a/content/browser/frame_host/navigation_controller_impl.h b/content/browser/frame_host/navigation_controller_impl.h
index 3a38bd05..91fb27d 100644
--- a/content/browser/frame_host/navigation_controller_impl.h
+++ b/content/browser/frame_host/navigation_controller_impl.h
@@ -151,11 +151,10 @@
   // so that we know to load URLs that were pending as "lazy" loads.
   void SetActive(bool is_active);
 
-  // Returns true if the given URL would be an in-page navigation (i.e. only
-  // the reference fragment is different) from the "last committed entry". We do
-  // not compare it against the "active entry" since the active entry can be
-  // pending and in page navigations only happen on committed pages. If there
-  // is no last committed entry, then nothing will be in-page.
+  // Returns true if the given URL would be an in-page navigation (i.e. only the
+  // reference fragment is different) from the last committed URL in the
+  // specified frame. If there is no last committed entry, then nothing will be
+  // in-page.
   //
   // Special note: if the URLs are the same, it does NOT automatically count as
   // an in-page navigation. Neither does an input URL that has no ref, even if
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index a1bfd03f..3565d33 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -744,6 +744,7 @@
     capturer.Wait();
     EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
     EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
+    EXPECT_TRUE(capturer.details().is_in_page);
   }
 
   // Back and forward across a fragment navigation.
@@ -765,6 +766,7 @@
               | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
               capturer.params().transition);
     EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
+    EXPECT_TRUE(capturer.details().is_in_page);
   }
 
   {
@@ -775,6 +777,7 @@
     EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_FORWARD_BACK,
               capturer.params().transition);
     EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
+    EXPECT_TRUE(capturer.details().is_in_page);
   }
 
   // Back and forward across a pushState-created navigation.
@@ -794,6 +797,7 @@
               | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR,
               capturer.params().transition);
     EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
+    EXPECT_TRUE(capturer.details().is_in_page);
   }
 
   {
@@ -804,6 +808,7 @@
     EXPECT_EQ(ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_FORWARD_BACK,
               capturer.params().transition);
     EXPECT_EQ(NAVIGATION_TYPE_IN_PAGE, capturer.details().type);
+    EXPECT_TRUE(capturer.details().is_in_page);
   }
 }
 
@@ -982,6 +987,84 @@
   }
 }
 
+// Verify that the LoadCommittedDetails::is_in_page value is properly set for
+// non-IN_PAGE navigations. (It's tested for IN_PAGE navigations with the
+// NavigationTypeClassification_InPage test.)
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+                       LoadCommittedDetails_IsInPage) {
+  GURL links_url(embedded_test_server()->GetURL(
+      "/navigation_controller/page_with_links.html"));
+  NavigateToURL(shell(), links_url);
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+  FrameTreeNode* root =
+      static_cast<WebContentsImpl*>(shell()->web_contents())->
+          GetFrameTree()->root();
+
+  {
+    // Do a fragment link click.
+    FrameNavigateParamsCapturer capturer(root);
+    std::string script = "document.getElementById('fraglink').click()";
+    EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+    capturer.Wait();
+    EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
+    EXPECT_TRUE(capturer.details().is_in_page);
+  }
+
+  {
+    // Do a non-fragment link click.
+    FrameNavigateParamsCapturer capturer(root);
+    std::string script = "document.getElementById('thelink').click()";
+    EXPECT_TRUE(content::ExecuteScript(root->current_frame_host(), script));
+    capturer.Wait();
+    EXPECT_EQ(ui::PAGE_TRANSITION_LINK, capturer.params().transition);
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_PAGE, capturer.details().type);
+    EXPECT_FALSE(capturer.details().is_in_page);
+  }
+
+  // Second verse, same as the first. (But in a subframe.)
+
+  GURL iframe_url(embedded_test_server()->GetURL(
+      "/navigation_controller/page_with_iframe.html"));
+  NavigateToURL(shell(), iframe_url);
+
+  root = static_cast<WebContentsImpl*>(shell()->web_contents())->
+      GetFrameTree()->root();
+
+  ASSERT_EQ(1U, root->child_count());
+  ASSERT_NE(nullptr, root->child_at(0));
+
+  NavigateFrameToURL(root->child_at(0), links_url);
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+  {
+    // Do a fragment link click.
+    FrameNavigateParamsCapturer capturer(root->child_at(0));
+    std::string script = "document.getElementById('fraglink').click()";
+    EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
+                script));
+    capturer.Wait();
+    EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
+              capturer.params().transition);
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
+    EXPECT_TRUE(capturer.details().is_in_page);
+  }
+
+  {
+    // Do a non-fragment link click.
+    FrameNavigateParamsCapturer capturer(root->child_at(0));
+    std::string script = "document.getElementById('thelink').click()";
+    EXPECT_TRUE(content::ExecuteScript(root->child_at(0)->current_frame_host(),
+                script));
+    capturer.Wait();
+    EXPECT_EQ(ui::PAGE_TRANSITION_MANUAL_SUBFRAME,
+              capturer.params().transition);
+    EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME, capturer.details().type);
+    EXPECT_FALSE(capturer.details().is_in_page);
+  }
+}
+
 // Verify the tree of FrameNavigationEntries after initial about:blank commits
 // in subframes, which should not count as real committed loads.
 IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
index 13d5bf4..f8133933 100644
--- a/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -1201,7 +1201,7 @@
   // Going back, the first entry should still appear unprivileged.
   controller.GoBack();
   new_rfh->PrepareForCommit();
-  orig_rfh->SendNavigate(0, entry1_id, false, url1);
+  contents()->GetPendingMainFrame()->SendNavigate(0, entry1_id, false, url1);
   EXPECT_EQ(0, controller.GetLastCommittedEntryIndex());
   EXPECT_EQ(0, controller.GetLastCommittedEntry()->bindings());
 }
@@ -2074,6 +2074,11 @@
   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   navigation_entry_committed_counter_ = 0;
 
+  main_test_rfh()->OnCreateChildFrame(
+      MSG_ROUTING_NONE, blink::WebTreeScopeType::Document, std::string(),
+      blink::WebSandboxFlags::None);
+  RenderFrameHostImpl* subframe =
+      contents()->GetFrameTree()->root()->child_at(0)->current_frame_host();
   const GURL url2("http://foo2");
   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   params.page_id = 1;
@@ -2087,8 +2092,7 @@
   params.page_state = PageState::CreateFromURL(url2);
 
   LoadCommittedDetails details;
-  EXPECT_TRUE(controller.RendererDidNavigate(main_test_rfh(), params,
-                                             &details));
+  EXPECT_TRUE(controller.RendererDidNavigate(subframe, params, &details));
   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   navigation_entry_committed_counter_ = 0;
   EXPECT_EQ(url1, details.previous_url);
@@ -2853,6 +2857,7 @@
   fail_load_params.error_description = base::string16();
   fail_load_params.url = url;
   fail_load_params.showing_repost_interstitial = false;
+  main_test_rfh()->InitializeRenderFrameIfNeeded();
   main_test_rfh()->OnMessageReceived(
       FrameHostMsg_DidFailProvisionalLoadWithError(0,  // routing_id
                                                   fail_load_params));
diff --git a/content/browser/frame_host/navigation_entry_impl.cc b/content/browser/frame_host/navigation_entry_impl.cc
index 7ba5cf30..8d889c9 100644
--- a/content/browser/frame_host/navigation_entry_impl.cc
+++ b/content/browser/frame_host/navigation_entry_impl.cc
@@ -155,11 +155,11 @@
 }
 
 void NavigationEntryImpl::SetPageState(const PageState& state) {
-  page_state_ = state;
+  frame_tree_->frame_entry->set_page_state(state);
 }
 
 const PageState& NavigationEntryImpl::GetPageState() const {
-  return page_state_;
+  return frame_tree_->frame_entry->page_state();
 }
 
 void NavigationEntryImpl::SetPageID(int page_id) {
@@ -365,7 +365,6 @@
   copy->update_virtual_url_with_url_ = update_virtual_url_with_url_;
   copy->title_ = title_;
   copy->favicon_ = favicon_;
-  copy->page_state_ = page_state_;
   copy->page_id_ = page_id_;
   copy->ssl_ = ssl_;
   copy->transition_type_ = transition_type_;
@@ -485,7 +484,8 @@
 void NavigationEntryImpl::AddOrUpdateFrameEntry(FrameTreeNode* frame_tree_node,
                                                 SiteInstanceImpl* site_instance,
                                                 const GURL& url,
-                                                const Referrer& referrer) {
+                                                const Referrer& referrer,
+                                                const PageState& page_state) {
   // We should already have a TreeNode for the parent node by the time this node
   // commits.  Find it first.
   DCHECK(frame_tree_node->parent());
@@ -504,7 +504,7 @@
   for (TreeNode* child : parent_node->children) {
     if (child->frame_entry->frame_tree_node_id() == frame_tree_node_id) {
       // Update the existing FrameNavigationEntry.
-      child->frame_entry->UpdateEntry(site_instance, url, referrer);
+      child->frame_entry->UpdateEntry(site_instance, url, referrer, page_state);
       return;
     }
   }
@@ -516,6 +516,7 @@
     return;
   FrameNavigationEntry* frame_entry = new FrameNavigationEntry(
       frame_tree_node_id, site_instance, url, referrer);
+  frame_entry->set_page_state(page_state);
   parent_node->children.push_back(
       new NavigationEntryImpl::TreeNode(frame_entry));
 }
diff --git a/content/browser/frame_host/navigation_entry_impl.h b/content/browser/frame_host/navigation_entry_impl.h
index 8fb41c3..646a0fb 100644
--- a/content/browser/frame_host/navigation_entry_impl.h
+++ b/content/browser/frame_host/navigation_entry_impl.h
@@ -165,7 +165,8 @@
   void AddOrUpdateFrameEntry(FrameTreeNode* frame_tree_node,
                              SiteInstanceImpl* site_instance,
                              const GURL& url,
-                             const Referrer& referrer);
+                             const Referrer& referrer,
+                             const PageState& page_state);
 
   // Returns whether this entry has a FrameNavigationEntry for the given
   // |frame_tree_node|.
@@ -344,7 +345,6 @@
   bool update_virtual_url_with_url_;
   base::string16 title_;
   FaviconStatus favicon_;
-  PageState page_state_;
   int32 page_id_;
   SSLStatus ssl_;
   ui::PageTransition transition_type_;
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index 888a2b7..aff92459 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -125,37 +125,9 @@
   render_process_host->FilterURL(false, &validated_url);
 
   bool is_main_frame = render_frame_host->frame_tree_node()->IsMainFrame();
-  NavigationEntryImpl* pending_entry = controller_->GetPendingEntry();
-  if (is_main_frame) {
-    // If there is no browser-initiated pending entry for this navigation and it
-    // is not for the error URL, create a pending entry using the current
-    // SiteInstance, and ensure the address bar updates accordingly.  We don't
-    // know the referrer or extra headers at this point, but the referrer will
-    // be set properly upon commit.
-    bool has_browser_initiated_pending_entry = pending_entry &&
-        !pending_entry->is_renderer_initiated();
-    if (!has_browser_initiated_pending_entry && !is_error_page) {
-      NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
-          controller_->CreateNavigationEntry(validated_url,
-                                             content::Referrer(),
-                                             ui::PAGE_TRANSITION_LINK,
-                                             true /* is_renderer_initiated */,
-                                             std::string(),
-                                             controller_->GetBrowserContext()));
-      entry->set_site_instance(render_frame_host->GetSiteInstance());
-      // TODO(creis): If there's a pending entry already, find a safe way to
-      // update it instead of replacing it and copying over things like this.
-      if (pending_entry) {
-        entry->set_transferred_global_request_id(
-            pending_entry->transferred_global_request_id());
-        entry->set_should_replace_entry(pending_entry->should_replace_entry());
-        entry->SetRedirectChain(pending_entry->GetRedirectChain());
-      }
-      controller_->SetPendingEntry(entry);
-      if (delegate_)
-        delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL);
-    }
-  }
+  if (is_main_frame && !is_error_page)
+    DidStartMainFrameNavigation(validated_url,
+                                render_frame_host->GetSiteInstance());
 
   if (delegate_) {
     // Notify the observer about the start of the provisional load.
@@ -640,6 +612,8 @@
     const CommonNavigationParams& common_params,
     const BeginNavigationParams& begin_params,
     scoped_refptr<ResourceRequestBody> body) {
+  // TODO(clamy): the url sent by the renderer should be validated with
+  // FilterURL.
   // This is a renderer-initiated navigation.
   CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kEnableBrowserSideNavigation));
@@ -667,8 +641,19 @@
           controller_->GetEntryCount());
   frame_tree_node->SetNavigationRequest(navigation_request.Pass());
 
-  if (frame_tree_node->IsMainFrame())
+  if (frame_tree_node->IsMainFrame()) {
+    // Renderer-initiated main-frame navigations that need to swap processes
+    // will go to the browser via a OpenURL call, and then be handled by the
+    // same code path as browser-initiated navigations. For renderer-initiated
+    // main frame navigation that start via a BeginNavigation IPC, the
+    // RenderFrameHost will not be swapped. Therefore it is safe to call
+    // DidStartMainFrameNavigation with the SiteInstance from the current
+    // RenderFrameHost.
+    DidStartMainFrameNavigation(
+        common_params.url,
+        frame_tree_node->current_frame_host()->GetSiteInstance());
     navigation_data_.reset();
+  }
 
   BeginNavigation(frame_tree_node);
 }
@@ -911,4 +896,36 @@
   navigation_data_.reset();
 }
 
+void NavigatorImpl::DidStartMainFrameNavigation(
+    const GURL& url,
+    SiteInstanceImpl* site_instance) {
+  // If there is no browser-initiated pending entry for this navigation and it
+  // is not for the error URL, create a pending entry using the current
+  // SiteInstance, and ensure the address bar updates accordingly.  We don't
+  // know the referrer or extra headers at this point, but the referrer will
+  // be set properly upon commit.
+  NavigationEntryImpl* pending_entry = controller_->GetPendingEntry();
+  bool has_browser_initiated_pending_entry =
+      pending_entry && !pending_entry->is_renderer_initiated();
+  if (!has_browser_initiated_pending_entry) {
+    NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
+        controller_->CreateNavigationEntry(
+            url, content::Referrer(), ui::PAGE_TRANSITION_LINK,
+            true /* is_renderer_initiated */, std::string(),
+            controller_->GetBrowserContext()));
+    entry->set_site_instance(site_instance);
+    // TODO(creis): If there's a pending entry already, find a safe way to
+    // update it instead of replacing it and copying over things like this.
+    if (pending_entry) {
+      entry->set_transferred_global_request_id(
+          pending_entry->transferred_global_request_id());
+      entry->set_should_replace_entry(pending_entry->should_replace_entry());
+      entry->SetRedirectChain(pending_entry->GetRedirectChain());
+    }
+    controller_->SetPendingEntry(entry);
+    if (delegate_)
+      delegate_->NotifyChangedNavigationState(content::INVALIDATE_TYPE_URL);
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/navigator_impl.h b/content/browser/frame_host/navigator_impl.h
index acae7a8..a1adf41 100644
--- a/content/browser/frame_host/navigator_impl.h
+++ b/content/browser/frame_host/navigator_impl.h
@@ -125,6 +125,12 @@
       const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
       SiteInstance* site_instance);
 
+  // Called when a navigation has started in a main frame, to update the pending
+  // NavigationEntry if the controller does not currently have a
+  // browser-initiated one.
+  void DidStartMainFrameNavigation(const GURL& url,
+                                   SiteInstanceImpl* site_instance);
+
   // The NavigationController that will keep track of session history for all
   // RenderFrameHost objects using this NavigatorImpl.
   // TODO(nasko): Move ownership of the NavigationController from
diff --git a/content/browser/frame_host/navigator_impl_unittest.cc b/content/browser/frame_host/navigator_impl_unittest.cc
index c72708b..8f1886f 100644
--- a/content/browser/frame_host/navigator_impl_unittest.cc
+++ b/content/browser/frame_host/navigator_impl_unittest.cc
@@ -931,6 +931,13 @@
 // using the same SiteInstance.
 TEST_F(NavigatorTestWithBrowserSideNavigation,
        SpeculativeRendererReuseSwappedOutRFH) {
+  // This test doesn't make sense in --site-per-process where swapped out
+  // RenderFrameHost is no longer used.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    return;
+  }
+
   // Navigate to an initial site.
   const GURL kUrl1("http://wikipedia.org/");
   contents()->NavigateAndCommit(kUrl1);
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 73d22c6..0c9bcb9e 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -442,12 +442,8 @@
   Send(new AccessibilityMsg_DoDefaultAction(routing_id_, object_id));
 }
 
-void RenderFrameHostImpl::AccessibilityShowMenu(
-    const gfx::Point& global_point) {
-  RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
-      render_view_host_->GetView());
-  if (view)
-    view->AccessibilityShowMenu(global_point);
+void RenderFrameHostImpl::AccessibilityShowContextMenu(int acc_obj_id) {
+  Send(new AccessibilityMsg_ShowContextMenu(routing_id_, acc_obj_id));
 }
 
 void RenderFrameHostImpl::AccessibilityScrollToMakeVisible(
@@ -652,12 +648,6 @@
 bool RenderFrameHostImpl::IsRenderFrameLive() {
   bool is_live = GetProcess()->HasConnection() && render_frame_created_;
 
-  // If the process is for an isolated guest (e.g. <webview>), rely on the
-  // RenderViewHost liveness check. Once https://crbug.com/492830 is fixed,
-  // this can be removed.
-  if (GetProcess()->IsIsolatedGuest())
-    is_live = render_view_host_->IsRenderViewLive();
-
   // Sanity check: the RenderView should always be live if the RenderFrame is.
   DCHECK_IMPLIES(is_live, render_view_host_->IsRenderViewLive());
 
@@ -805,6 +795,10 @@
   TRACE_EVENT1("navigation", "RenderFrameHostImpl::OnDidCommitProvisionalLoad",
                "url", validated_params.url.possibly_invalid_spec());
 
+  // Sanity-check the page transition for frame type.
+  DCHECK_EQ(ui::PageTransitionIsMainFrame(validated_params.transition),
+            !GetParent());
+
   // If we're waiting for a cross-site beforeunload ack from this renderer and
   // we receive a Navigate message from the main frame, then the renderer was
   // navigating already and sent it before hearing the FrameMsg_Stop message.
@@ -813,7 +807,7 @@
   // to allow the pending navigation to continue.
   if (is_waiting_for_beforeunload_ack_ &&
       unload_ack_is_for_navigation_ &&
-      ui::PageTransitionIsMainFrame(validated_params.transition)) {
+      !GetParent()) {
     base::TimeTicks approx_renderer_start_time = send_before_unload_start_time_;
     OnBeforeUnloadACK(true, approx_renderer_start_time, base::TimeTicks::Now());
     return;
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 0ca0948..60764c6 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -159,7 +159,7 @@
   // BrowserAccessibilityDelegate
   void AccessibilitySetFocus(int acc_obj_id) override;
   void AccessibilityDoDefaultAction(int acc_obj_id) override;
-  void AccessibilityShowMenu(const gfx::Point& global_point) override;
+  void AccessibilityShowContextMenu(int acc_obj_id) override;
   void AccessibilityScrollToMakeVisible(int acc_obj_id,
                                         const gfx::Rect& subfocus) override;
   void AccessibilityScrollToPoint(int acc_obj_id,
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 7c0cf40..952b0b0 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -204,7 +204,8 @@
     // soon anyway, and we don't have the NavigationEntry for this host.
     delegate_->CreateRenderViewForRenderManager(
         render_frame_host_->render_view_host(), MSG_ROUTING_NONE,
-        MSG_ROUTING_NONE, frame_tree_node_->IsMainFrame());
+        MSG_ROUTING_NONE, frame_tree_node_->current_replication_state(),
+        frame_tree_node_->IsMainFrame());
   }
 
   // If the renderer crashed, then try to create a new one to satisfy this
@@ -609,18 +610,16 @@
   // SwapOut creates a RenderFrameProxy, so set the proxy to be initialized.
   proxy->set_render_frame_proxy_created(true);
 
-  bool is_main_frame = frame_tree_node_->IsMainFrame();
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kSitePerProcess) &&
-      !is_main_frame) {
-    // In --site-per-process, subframes delete their RFH rather than storing it
+          switches::kSitePerProcess)) {
+    // In --site-per-process, frames delete their RFH rather than storing it
     // in the proxy.  Schedule it for deletion once the SwapOutACK comes in.
     // TODO(creis): This will be the default when we remove swappedout://.
     MoveToPendingDeleteHosts(old_render_frame_host.Pass());
   } else {
     // We shouldn't get here for subframes, since we only swap subframes when
     // --site-per-process is used.
-    DCHECK(is_main_frame);
+    DCHECK(frame_tree_node_->IsMainFrame());
 
     // The old RenderFrameHost will stay alive inside the proxy so that existing
     // JavaScript window references to it stay valid.
@@ -635,6 +634,8 @@
 
   // If the SiteInstance for the pending RFH is being used by others don't
   // delete the RFH. Just swap it out and it can be reused at a later point.
+  // In --site-per-process, RenderFrameHosts are not kept around and are
+  // deleted when not used, replaced by RenderFrameProxyHosts.
   SiteInstanceImpl* site_instance = render_frame_host->GetSiteInstance();
   if (site_instance->HasSite() && site_instance->active_frame_count() > 1) {
     // Any currently suspended navigations are no longer needed.
@@ -650,9 +651,14 @@
     if (!render_frame_host->is_swapped_out())
       render_frame_host->SwapOut(proxy, false);
 
-    if (frame_tree_node_->IsMainFrame())
+    if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+      DCHECK(frame_tree_node_->IsMainFrame());
       proxy->TakeFrameHostOwnership(render_frame_host.Pass());
-  } else {
+    }
+  }
+
+  if (render_frame_host) {
     // We won't be coming back, so delete this one.
     ShutdownProxiesIfLastActiveFrameInSiteInstance(render_frame_host.get());
     render_frame_host.reset();
@@ -920,7 +926,9 @@
     if (node->IsMainFrame() &&
         proxy->render_frame_host() &&
         proxy->render_frame_host()->rfh_state() ==
-        RenderFrameHostImpl::STATE_PENDING_SWAP_OUT) {
+            RenderFrameHostImpl::STATE_PENDING_SWAP_OUT) {
+      DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess));
       scoped_ptr<RenderFrameHostImpl> swapped_out_rfh =
           proxy->PassFrameHostOwnership();
       node->render_manager()->MoveToPendingDeleteHosts(swapped_out_rfh.Pass());
@@ -1458,14 +1466,15 @@
     int flags,
     int* view_routing_id_ptr) {
   bool swapped_out = !!(flags & CREATE_RF_SWAPPED_OUT);
-  CHECK(instance);
-  // Swapped out views should always be hidden.
-  DCHECK(!swapped_out || (flags & CREATE_RF_HIDDEN));
+  bool is_site_per_process = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kSitePerProcess);
 
-  // TODO(nasko): Remove the following CHECK once cross-process navigation no
-  // longer relies on swapped out RFH for the top-level frame.
-  if (!frame_tree_node_->IsMainFrame())
-    CHECK(!swapped_out);
+  CHECK(instance);
+  CHECK_IMPLIES(is_site_per_process, !swapped_out);
+  CHECK_IMPLIES(!is_site_per_process, frame_tree_node_->IsMainFrame());
+
+  // Swapped out views should always be hidden.
+  DCHECK_IMPLIES(swapped_out, (flags & CREATE_RF_HIDDEN));
 
   scoped_ptr<RenderFrameHostImpl> new_render_frame_host;
   bool success = true;
@@ -1481,6 +1490,7 @@
   // remove it from the list of proxy hosts below if it will be active.
   RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
   if (proxy && proxy->render_frame_host()) {
+    CHECK(!is_site_per_process);
     if (view_routing_id_ptr)
       *view_routing_id_ptr = proxy->GetRenderViewHost()->GetRoutingID();
     // Delete the existing RenderFrameProxyHost, but reuse the RenderFrameHost.
@@ -1527,7 +1537,13 @@
         // will be created later and hidden.
         if (render_view_host->GetView())
           render_view_host->GetView()->Hide();
-      } else if (!swapped_out) {
+      }
+      // With --site-per-process, RenderViewHost for |instance| might exist
+      // prior to calling CreateRenderFrame, due to a subframe in
+      // |instance|. In such a case, InitRenderView will not create the
+      // RenderFrame in the renderer process and it needs to be done
+      // explicitly.
+      if (is_site_per_process) {
         // Init the RFH, so a RenderFrame is created in the renderer.
         DCHECK(new_render_frame_host);
         success = InitRenderFrame(new_render_frame_host.get());
@@ -1569,17 +1585,40 @@
   CHECK(instance);
   CHECK_NE(instance, render_frame_host_->GetSiteInstance());
 
+  bool is_site_per_process = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kSitePerProcess);
+  RenderViewHostImpl* render_view_host = nullptr;
+
+  // Ensure a RenderViewHost exists for |instance|, as it creates the page
+  // level structure in Blink.
+  if (is_site_per_process) {
+    render_view_host =
+        frame_tree_node_->frame_tree()->GetRenderViewHost(instance);
+    if (!render_view_host) {
+      CHECK(frame_tree_node_->IsMainFrame());
+      render_view_host = frame_tree_node_->frame_tree()->CreateRenderViewHost(
+          instance, MSG_ROUTING_NONE, MSG_ROUTING_NONE, true, true);
+    }
+  }
+
   RenderFrameProxyHost* proxy = GetRenderFrameProxyHost(instance);
   if (proxy && proxy->is_render_frame_proxy_live())
     return proxy->GetRoutingID();
 
   if (!proxy) {
     proxy = new RenderFrameProxyHost(
-        instance, frame_tree_node_->frame_tree()->GetRenderViewHost(instance),
-        frame_tree_node_);
+        instance, render_view_host, frame_tree_node_);
     proxy_hosts_[instance->GetId()] = proxy;
   }
-  proxy->InitRenderFrameProxy();
+
+  if (is_site_per_process && frame_tree_node_->IsMainFrame()) {
+    InitRenderView(
+        render_view_host, MSG_ROUTING_NONE, proxy->GetRoutingID(), true);
+    proxy->set_render_frame_proxy_created(true);
+  } else {
+    proxy->InitRenderFrameProxy();
+  }
+
   return proxy->GetRoutingID();
 }
 
@@ -1613,15 +1652,15 @@
     int opener_route_id,
     int proxy_routing_id,
     bool for_main_frame_navigation) {
-  // We may have initialized this RenderViewHost for another RenderFrameHost.
-  if (render_view_host->IsRenderViewLive())
-    return true;
-
   // Ensure the renderer process is initialized before creating the
   // RenderView.
   if (!render_view_host->GetProcess()->Init())
     return false;
 
+  // We may have initialized this RenderViewHost for another RenderFrameHost.
+  if (render_view_host->IsRenderViewLive())
+    return true;
+
   // If the ongoing navigation is to a WebUI and the RenderView is not in a
   // guest process, tell the RenderViewHost about any bindings it will need
   // enabled.
@@ -1644,10 +1683,12 @@
     }
   }
 
-  return delegate_->CreateRenderViewForRenderManager(render_view_host,
-                                                     opener_route_id,
-                                                     proxy_routing_id,
-                                                     for_main_frame_navigation);
+  return delegate_->CreateRenderViewForRenderManager(
+      render_view_host,
+      opener_route_id,
+      proxy_routing_id,
+      frame_tree_node_->current_replication_state(),
+      for_main_frame_navigation);
 }
 
 bool RenderFrameHostManager::InitRenderFrame(
@@ -1717,6 +1758,9 @@
   bool browser_side_navigation =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableBrowserSideNavigation);
+  bool is_site_per_process = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kSitePerProcess);
+
   // First check whether we're going to want to focus the location bar after
   // this commit.  We do this now because the navigation hasn't formally
   // committed yet, so if we've already cleared |pending_web_ui_| the call chain
@@ -1818,6 +1862,17 @@
   delegate_->NotifySwappedFromRenderManager(
       old_render_frame_host.get(), render_frame_host_.get(), is_main_frame);
 
+  // The RenderViewHost keeps track of the main RenderFrameHost routing id.
+  // If this is committing a main frame navigation, update it and set the
+  // routing id in the RenderViewHost associated with the old RenderFrameHost
+  // to MSG_ROUTING_NONE.
+  if (is_main_frame && is_site_per_process) {
+    render_frame_host_->render_view_host()->set_main_frame_routing_id(
+        render_frame_host_->routing_id());
+    old_render_frame_host->render_view_host()->set_main_frame_routing_id(
+        MSG_ROUTING_NONE);
+  }
+
   // Swap out the old frame now that the new one is visible.
   // This will swap it out and then put it on the proxy list (if there are other
   // active views in its SiteInstance) or schedule it for deletion when the swap
@@ -1826,9 +1881,7 @@
   // the proxy.
   SwapOutOldFrame(old_render_frame_host.Pass());
 
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kSitePerProcess) &&
-      !is_main_frame) {
+  if (is_site_per_process) {
     // Since the new RenderFrameHost is now committed, there must be no proxies
     // for its SiteInstance. Delete any existing ones.
     RenderFrameProxyHostMap::iterator iter =
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h
index cc7dd6c..9b28575a 100644
--- a/content/browser/frame_host/render_frame_host_manager.h
+++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -44,6 +44,7 @@
 class TestWebContents;
 class WebUIImpl;
 struct CommonNavigationParams;
+struct FrameReplicationState;
 
 // Manages RenderFrameHosts for a FrameTreeNode. It maintains a
 // current_frame_host() which is the content currently visible to the user. When
@@ -121,6 +122,7 @@
         RenderViewHost* render_view_host,
         int opener_route_id,
         int proxy_routing_id,
+        const FrameReplicationState& replicated_frame_state,
         bool for_main_frame_navigation) = 0;
     virtual bool CreateRenderFrameForRenderManager(
         RenderFrameHost* render_frame_host,
diff --git a/content/browser/frame_host/render_frame_host_manager_browsertest.cc b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
index aec9dac..6072302 100644
--- a/content/browser/frame_host/render_frame_host_manager_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
@@ -6,9 +6,12 @@
 
 #include "base/command_line.h"
 #include "base/json/json_reader.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/path_service.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
@@ -1160,6 +1163,12 @@
 // Swapping out a render view should update its visiblity state.
 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
                        SwappedOutViewHasCorrectVisibilityState) {
+  // This test is invalid in --site-per-process mode, as swapped-out is no
+  // longer used.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    return;
+  }
   StartServer();
 
   // Load a page with links that open in a new window.
@@ -1760,7 +1769,7 @@
     }
 
     if (deleted_ && message_loop_runner_->loop_running()) {
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, message_loop_runner_->QuitClosure());
     }
   }
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc
index c03a0bb..6bf1476 100644
--- a/content/browser/frame_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -330,7 +330,9 @@
     if (old_rfh != active_rfh && !rfh_observer.deleted()) {
       EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT,
                 old_rfh->rfh_state());
-      if (!old_rfh->GetSiteInstance()->active_frame_count()) {
+      if (!old_rfh->GetSiteInstance()->active_frame_count() ||
+          base::CommandLine::ForCurrentProcess()->HasSwitch(
+               switches::kSitePerProcess)) {
         expecting_rfh_shutdown = true;
         EXPECT_TRUE(
             old_rfh->frame_tree_node()->render_manager()->IsPendingDeletion(
@@ -344,7 +346,10 @@
       old_rfh->OnSwappedOut();
       if (expecting_rfh_shutdown) {
         EXPECT_TRUE(rfh_observer.deleted());
-        EXPECT_TRUE(rvh_observer.deleted());
+        if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+              switches::kSitePerProcess)) {
+          EXPECT_TRUE(rvh_observer.deleted());
+        }
       } else {
         EXPECT_EQ(RenderFrameHostImpl::STATE_SWAPPED_OUT,
                   old_rfh->rfh_state());
@@ -527,6 +532,7 @@
   // Navigate our first tab to a chrome url and then to the destination.
   NavigateActiveAndCommit(kChromeURL);
   TestRenderFrameHost* ntp_rfh = contents()->GetMainFrame();
+  TestRenderViewHost* ntp_rvh = ntp_rfh->GetRenderViewHost();
 
   // Send an update favicon message and make sure it works.
   {
@@ -559,16 +565,22 @@
 
   // The old renderer, being slow, now updates the favicon. It should be
   // filtered out and not take effect.
-  EXPECT_TRUE(ntp_rfh->is_swapped_out());
   {
     PluginFaviconMessageObserver observer(contents());
     EXPECT_TRUE(
-        ntp_rfh->GetRenderViewHost()->OnMessageReceived(
+        ntp_rvh->OnMessageReceived(
             ViewHostMsg_UpdateFaviconURL(
                 dest_rfh->GetRenderViewHost()->GetRoutingID(), icons)));
     EXPECT_FALSE(observer.favicon_received());
   }
 
+  // In --site-per-process, the RenderFrameHost is deleted on cross-process
+  // navigation, so the rest of the test case doesn't apply.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    return;
+  }
+
 #if defined(ENABLE_PLUGINS)
   // The same logic should apply to RenderFrameHosts as well and routing through
   // swapped out RFH shouldn't be allowed. Use a PluginCrashObserver to check
@@ -673,6 +685,13 @@
   const GURL kUrl1("http://foo.com");
   const GURL kUrl2("http://www.google.com/");
 
+  // This test is invalid in --site-per-process mode, as swapped-out is no
+  // longer used.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    return;
+  }
+
   // Navigate to the first site.
   NavigateActiveAndCommit(kUrl1);
   TestRenderFrameHost* initial_rfh = contents()->GetMainFrame();
@@ -711,6 +730,12 @@
 }
 
 TEST_F(RenderFrameHostManagerTest, WhiteListSwapCompositorFrame) {
+  // TODO(nasko): Check with kenrb whether this test can be rewritten and
+  // whether it makes sense when swapped out is replaced with proxies.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    return;
+  }
   TestRenderFrameHost* swapped_out_rfh = CreateSwappedOutRenderFrameHost();
   TestRenderWidgetHostView* swapped_out_rwhv =
       static_cast<TestRenderWidgetHostView*>(
@@ -731,6 +756,13 @@
 // Test if RenderViewHost::GetRenderWidgetHosts() only returns active
 // widgets.
 TEST_F(RenderFrameHostManagerTest, GetRenderWidgetHostsReturnsActiveViews) {
+  // This test is invalid in --site-per-process mode, as swapped-out is no
+  // longer used.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    return;
+  }
+
   TestRenderFrameHost* swapped_out_rfh = CreateSwappedOutRenderFrameHost();
   EXPECT_TRUE(swapped_out_rfh->is_swapped_out());
 
@@ -752,6 +784,13 @@
 // including swapped out ones.
 TEST_F(RenderFrameHostManagerTest,
        GetRenderWidgetHostsWithinGetAllRenderWidgetHosts) {
+  // This test is invalid in --site-per-process mode, as swapped-out is no
+  // longer used.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    return;
+  }
+
   TestRenderFrameHost* swapped_out_rfh = CreateSwappedOutRenderFrameHost();
   EXPECT_TRUE(swapped_out_rfh->is_swapped_out());
 
@@ -1109,7 +1148,8 @@
       web_contents1->GetRenderManagerForTesting();
   // Test the case that new RVH is considered live.
   manager1->current_host()->CreateRenderView(
-      base::string16(), -1, MSG_ROUTING_NONE, -1, false);
+      base::string16(), -1, MSG_ROUTING_NONE, -1,
+      FrameReplicationState(), false);
   EXPECT_TRUE(manager1->current_host()->IsRenderViewLive());
   EXPECT_TRUE(manager1->current_frame_host()->IsRenderFrameLive());
 
@@ -1143,7 +1183,8 @@
   // Make sure the new RVH is considered live.  This is usually done in
   // RenderWidgetHost::Init when opening a new tab from a link.
   manager2->current_host()->CreateRenderView(
-      base::string16(), -1, MSG_ROUTING_NONE, -1, false);
+      base::string16(), -1, MSG_ROUTING_NONE, -1,
+      FrameReplicationState(), false);
   EXPECT_TRUE(manager2->current_host()->IsRenderViewLive());
 
   const GURL kUrl2("chrome://foo/bar");
@@ -1313,8 +1354,8 @@
 
   // The back navigation commits.
   const NavigationEntry* entry1 = contents()->GetController().GetPendingEntry();
-  rfh1->SendNavigate(entry1->GetPageID(), entry1->GetUniqueID(), false,
-                     entry1->GetURL());
+  contents()->GetPendingMainFrame()->SendNavigate(
+      entry1->GetPageID(), entry1->GetUniqueID(), false, entry1->GetURL());
   EXPECT_TRUE(rfh2->IsWaitingForUnloadACK());
   EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT, rfh2->rfh_state());
 
@@ -1322,14 +1363,17 @@
   contents()->GetController().GoForward();
   contents()->GetMainFrame()->PrepareForCommit();
   const NavigationEntry* entry2 = contents()->GetController().GetPendingEntry();
-  rfh2->SendNavigate(entry2->GetPageID(), entry2->GetUniqueID(), false,
-                     entry2->GetURL());
-  EXPECT_EQ(rfh2, main_test_rfh());
-  EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, rfh2->rfh_state());
-  EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT, rfh1->rfh_state());
-  rfh1->OnSwappedOut();
-  EXPECT_TRUE(rfh1->is_swapped_out());
-  EXPECT_EQ(RenderFrameHostImpl::STATE_SWAPPED_OUT, rfh1->rfh_state());
+  contents()->GetPendingMainFrame()->SendNavigate(
+      entry2->GetPageID(), entry2->GetUniqueID(), false, entry2->GetURL());
+  EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT, main_test_rfh()->rfh_state());
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    EXPECT_EQ(rfh2, main_test_rfh());
+    EXPECT_EQ(RenderFrameHostImpl::STATE_PENDING_SWAP_OUT, rfh1->rfh_state());
+    rfh1->OnSwappedOut();
+    EXPECT_TRUE(rfh1->is_swapped_out());
+    EXPECT_EQ(RenderFrameHostImpl::STATE_SWAPPED_OUT, rfh1->rfh_state());
+  }
 }
 
 // Test that we create swapped out RFHs for the opener chain when navigating an
@@ -1339,23 +1383,27 @@
   const GURL kUrl1("http://www.google.com/");
   const GURL kUrl2("http://www.chromium.org/");
   const GURL kChromeUrl("chrome://foo");
+  bool is_site_per_process = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kSitePerProcess);
 
   // Navigate to an initial URL.
   contents()->NavigateAndCommit(kUrl1);
   RenderFrameHostManager* manager = contents()->GetRenderManagerForTesting();
   TestRenderFrameHost* rfh1 = main_test_rfh();
+  scoped_refptr<SiteInstanceImpl> site_instance1 = rfh1->GetSiteInstance();
+  RenderFrameHostDeletedObserver rfh1_deleted_observer(rfh1);
   TestRenderViewHost* rvh1 = test_rvh();
 
   // Create 2 new tabs and simulate them being the opener chain for the main
   // tab.  They should be in the same SiteInstance.
   scoped_ptr<TestWebContents> opener1(
-      TestWebContents::Create(browser_context(), rfh1->GetSiteInstance()));
+      TestWebContents::Create(browser_context(), site_instance1.get()));
   RenderFrameHostManager* opener1_manager =
       opener1->GetRenderManagerForTesting();
   contents()->SetOpener(opener1.get());
 
   scoped_ptr<TestWebContents> opener2(
-      TestWebContents::Create(browser_context(), rfh1->GetSiteInstance()));
+      TestWebContents::Create(browser_context(), site_instance1.get()));
   RenderFrameHostManager* opener2_manager =
       opener2->GetRenderManagerForTesting();
   opener1->SetOpener(opener2.get());
@@ -1365,16 +1413,21 @@
   contents()->NavigateAndCommit(kUrl2);
   TestRenderFrameHost* rfh2 = main_test_rfh();
   TestRenderViewHost* rvh2 = test_rvh();
-  EXPECT_NE(rfh1->GetSiteInstance(), rfh2->GetSiteInstance());
-  EXPECT_TRUE(rfh1->GetSiteInstance()->IsRelatedSiteInstance(
-                  rfh2->GetSiteInstance()));
+  EXPECT_NE(site_instance1, rfh2->GetSiteInstance());
+  EXPECT_TRUE(site_instance1->IsRelatedSiteInstance(rfh2->GetSiteInstance()));
 
   // Ensure rvh1 is placed on swapped out list of the current tab.
-  EXPECT_TRUE(manager->IsOnSwappedOutList(rfh1));
-  EXPECT_TRUE(manager->IsRVHOnSwappedOutList(rvh1));
-  EXPECT_EQ(rfh1,
-            manager->GetRenderFrameProxyHost(rfh1->GetSiteInstance())
-                ->render_frame_host());
+  if (!is_site_per_process) {
+    EXPECT_TRUE(manager->IsRVHOnSwappedOutList(rvh1));
+    EXPECT_FALSE(rfh1_deleted_observer.deleted());
+    EXPECT_TRUE(manager->IsOnSwappedOutList(rfh1));
+    EXPECT_EQ(rfh1,
+              manager->GetRenderFrameProxyHost(site_instance1.get())
+                  ->render_frame_host());
+  } else {
+    EXPECT_TRUE(rfh1_deleted_observer.deleted());
+    EXPECT_TRUE(manager->GetRenderFrameProxyHost(site_instance1.get()));
+  }
   EXPECT_EQ(rvh1,
             manager->GetSwappedOutRenderViewHost(rvh1->GetSiteInstance()));
 
@@ -1384,9 +1437,13 @@
   RenderFrameHostImpl* opener1_rfh = opener1_proxy->render_frame_host();
   TestRenderViewHost* opener1_rvh = static_cast<TestRenderViewHost*>(
       opener1_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
-  EXPECT_TRUE(opener1_manager->IsOnSwappedOutList(opener1_rfh));
-  EXPECT_TRUE(opener1_manager->IsRVHOnSwappedOutList(opener1_rvh));
-  EXPECT_TRUE(opener1_rfh->is_swapped_out());
+  if (!is_site_per_process) {
+    EXPECT_TRUE(opener1_manager->IsOnSwappedOutList(opener1_rfh));
+    EXPECT_TRUE(opener1_manager->IsRVHOnSwappedOutList(opener1_rvh));
+    EXPECT_TRUE(opener1_rfh->is_swapped_out());
+  } else {
+    EXPECT_FALSE(opener1_rfh);
+  }
   EXPECT_FALSE(opener1_rvh->is_active());
 
   // Ensure a swapped out RFH and RVH is created in the second opener tab.
@@ -1395,17 +1452,20 @@
   RenderFrameHostImpl* opener2_rfh = opener2_proxy->render_frame_host();
   TestRenderViewHost* opener2_rvh = static_cast<TestRenderViewHost*>(
       opener2_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
-  EXPECT_TRUE(opener2_manager->IsOnSwappedOutList(opener2_rfh));
-  EXPECT_TRUE(opener2_manager->IsRVHOnSwappedOutList(opener2_rvh));
-  EXPECT_TRUE(opener2_rfh->is_swapped_out());
+  if (!is_site_per_process) {
+    EXPECT_TRUE(opener2_manager->IsOnSwappedOutList(opener2_rfh));
+    EXPECT_TRUE(opener2_manager->IsRVHOnSwappedOutList(opener2_rvh));
+    EXPECT_TRUE(opener2_rfh->is_swapped_out());
+  } else {
+    EXPECT_FALSE(opener2_rfh);
+  }
   EXPECT_FALSE(opener2_rvh->is_active());
 
   // Navigate to a cross-BrowsingInstance URL.
   contents()->NavigateAndCommit(kChromeUrl);
   TestRenderFrameHost* rfh3 = main_test_rfh();
-  EXPECT_NE(rfh1->GetSiteInstance(), rfh3->GetSiteInstance());
-  EXPECT_FALSE(rfh1->GetSiteInstance()->IsRelatedSiteInstance(
-                   rfh3->GetSiteInstance()));
+  EXPECT_NE(site_instance1, rfh3->GetSiteInstance());
+  EXPECT_FALSE(site_instance1->IsRelatedSiteInstance(rfh3->GetSiteInstance()));
 
   // No scripting is allowed across BrowsingInstances, so we should not create
   // swapped out RVHs for the opener chain in this case.
@@ -1427,6 +1487,7 @@
   // Navigate to an initial URL.
   contents()->NavigateAndCommit(kUrl1);
   TestRenderFrameHost* rfh1 = main_test_rfh();
+  scoped_refptr<SiteInstanceImpl> site_instance1 = rfh1->GetSiteInstance();
 
   // Create a new tab and simulate having it be the opener for the main tab.
   scoped_ptr<TestWebContents> opener1(
@@ -1438,7 +1499,7 @@
   // BrowsingInstance).
   contents()->NavigateAndCommit(kUrl2);
   TestRenderFrameHost* rfh2 = main_test_rfh();
-  EXPECT_NE(rfh1->GetSiteInstance(), rfh2->GetSiteInstance());
+  EXPECT_NE(site_instance1, rfh2->GetSiteInstance());
 
   // Disown the opener from rfh2.
   rfh2->DidDisownOpener();
@@ -1476,11 +1537,12 @@
 
   // Navigate to an initial URL.
   contents()->NavigateAndCommit(kUrl1);
-  TestRenderFrameHost* rfh1 = main_test_rfh();
+  scoped_refptr<SiteInstanceImpl> site_instance1 =
+      main_test_rfh()->GetSiteInstance();
 
   // Create a new tab and simulate having it be the opener for the main tab.
   scoped_ptr<TestWebContents> opener1(
-      TestWebContents::Create(browser_context(), rfh1->GetSiteInstance()));
+      TestWebContents::Create(browser_context(), site_instance1.get()));
   contents()->SetOpener(opener1.get());
   EXPECT_TRUE(contents()->HasOpener());
 
@@ -1488,9 +1550,9 @@
   // BrowsingInstance).
   contents()->NavigateAndCommit(kUrl2);
   TestRenderFrameHost* rfh2 = main_test_rfh();
-  EXPECT_NE(rfh1->GetSiteInstance(), rfh2->GetSiteInstance());
+  EXPECT_NE(site_instance1, rfh2->GetSiteInstance());
 
-  // Start a back navigation so that rfh1 becomes the pending RFH.
+  // Start a back navigation.
   contents()->GetController().GoBack();
   contents()->GetMainFrame()->PrepareForCommit();
 
@@ -1502,8 +1564,8 @@
 
   // The back navigation commits.
   const NavigationEntry* entry1 = contents()->GetController().GetPendingEntry();
-  rfh1->SendNavigate(entry1->GetPageID(), entry1->GetUniqueID(), false,
-                     entry1->GetURL());
+  contents()->GetPendingMainFrame()->SendNavigate(
+      entry1->GetPageID(), entry1->GetUniqueID(), false, entry1->GetURL());
 
   // Ensure the opener is still cleared.
   EXPECT_FALSE(contents()->HasOpener());
@@ -1517,11 +1579,12 @@
 
   // Navigate to an initial URL.
   contents()->NavigateAndCommit(kUrl1);
-  TestRenderFrameHost* rfh1 = main_test_rfh();
+  scoped_refptr<SiteInstanceImpl> site_instance1 =
+      main_test_rfh()->GetSiteInstance();
 
   // Create a new tab and simulate having it be the opener for the main tab.
   scoped_ptr<TestWebContents> opener1(
-      TestWebContents::Create(browser_context(), rfh1->GetSiteInstance()));
+      TestWebContents::Create(browser_context(), site_instance1.get()));
   contents()->SetOpener(opener1.get());
   EXPECT_TRUE(contents()->HasOpener());
 
@@ -1529,15 +1592,14 @@
   // BrowsingInstance).
   contents()->NavigateAndCommit(kUrl2);
   TestRenderFrameHost* rfh2 = main_test_rfh();
-  EXPECT_NE(rfh1->GetSiteInstance(), rfh2->GetSiteInstance());
+  EXPECT_NE(site_instance1, rfh2->GetSiteInstance());
 
   // Commit a back navigation before the DidDisownOpener message arrives.
-  // rfh1 will be kept alive because of the opener tab.
   contents()->GetController().GoBack();
   contents()->GetMainFrame()->PrepareForCommit();
   const NavigationEntry* entry1 = contents()->GetController().GetPendingEntry();
-  rfh1->SendNavigate(entry1->GetPageID(), entry1->GetUniqueID(), false,
-                     entry1->GetURL());
+  contents()->GetPendingMainFrame()->SendNavigate(
+      entry1->GetPageID(), entry1->GetUniqueID(), false, entry1->GetURL());
 
   // Disown the opener from rfh2.
   rfh2->DidDisownOpener();
@@ -1563,7 +1625,8 @@
 
   // Make sure the new opener RVH is considered live.
   opener1_manager->current_host()->CreateRenderView(
-      base::string16(), -1, MSG_ROUTING_NONE, -1, false);
+      base::string16(), -1, MSG_ROUTING_NONE, -1,
+      FrameReplicationState(), false);
   EXPECT_TRUE(opener1_manager->current_host()->IsRenderViewLive());
   EXPECT_TRUE(opener1_manager->current_frame_host()->IsRenderFrameLive());
 
@@ -1634,9 +1697,14 @@
   RenderFrameHostImpl* opener1_rfh = opener1_proxy->render_frame_host();
   TestRenderViewHost* opener1_rvh = static_cast<TestRenderViewHost*>(
       opener1_manager->GetSwappedOutRenderViewHost(rvh2->GetSiteInstance()));
-  EXPECT_TRUE(opener1_manager->IsOnSwappedOutList(opener1_rfh));
-  EXPECT_TRUE(opener1_manager->IsRVHOnSwappedOutList(opener1_rvh));
-  EXPECT_TRUE(opener1_rfh->is_swapped_out());
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    EXPECT_TRUE(opener1_manager->IsOnSwappedOutList(opener1_rfh));
+    EXPECT_TRUE(opener1_manager->IsRVHOnSwappedOutList(opener1_rvh));
+    EXPECT_TRUE(opener1_rfh->is_swapped_out());
+  } else {
+    EXPECT_FALSE(opener1_rfh);
+  }
   EXPECT_FALSE(opener1_rvh->is_active());
 
   // Ensure the new RVH has WebUI bindings.
@@ -1874,9 +1942,14 @@
   // Simulate the swap out ack.
   rfh1->OnSwappedOut();
 
-  // rfh1 should be swapped out.
-  EXPECT_FALSE(rfh_deleted_observer.deleted());
-  EXPECT_TRUE(rfh1->is_swapped_out());
+  // rfh1 should be swapped out or deleted in --site-per-process.
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    EXPECT_FALSE(rfh_deleted_observer.deleted());
+    EXPECT_TRUE(rfh1->is_swapped_out());
+  } else {
+    EXPECT_TRUE(rfh_deleted_observer.deleted());
+  }
 }
 
 // Test that the RenderViewHost is properly swapped out if a navigation in the
@@ -1896,7 +1969,8 @@
 
   // Increment the number of active frames in SiteInstanceImpl so that rfh1 is
   // not deleted on swap out.
-  rfh1->GetSiteInstance()->increment_active_frame_count();
+  scoped_refptr<SiteInstanceImpl> site_instance = rfh1->GetSiteInstance();
+  site_instance->increment_active_frame_count();
 
   // Navigate to new site, simulating onbeforeunload approval.
   controller().LoadURL(
@@ -1919,12 +1993,19 @@
   rfh1->OnSwappedOut();
 
   // rfh1 should be swapped out.
-  EXPECT_FALSE(rfh_deleted_observer.deleted());
-  EXPECT_TRUE(rfh1->is_swapped_out());
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    EXPECT_TRUE(rfh_deleted_observer.deleted());
+    EXPECT_TRUE(contents()->GetFrameTree()->root()->render_manager()
+                ->GetRenderFrameProxyHost(site_instance.get()));
+  } else {
+    EXPECT_FALSE(rfh_deleted_observer.deleted());
+    EXPECT_TRUE(rfh1->is_swapped_out());
+  }
 }
 
-// Test that a RenderFrameHost is properly deleted or swapped out when a
-// cross-site navigation is cancelled.
+// Test that a RenderFrameHost is properly deleted when a cross-site navigation
+// is cancelled.
 TEST_F(RenderFrameHostManagerTest,
        CancelPendingProperlyDeletesOrSwaps) {
   const GURL kUrl1("http://www.google.com/");
@@ -1964,13 +2045,24 @@
     RenderFrameHostDeletedObserver rfh_deleted_observer(pending_rfh);
 
     // Increment the number of active frames in the new SiteInstance, which will
-    // cause the pending RFH to be swapped out instead of deleted.
-    pending_rfh->GetSiteInstance()->increment_active_frame_count();
+    // cause the pending RFH to be deleted and a RenderFrameProxyHost to be
+    // created.
+    scoped_refptr<SiteInstanceImpl> site_instance =
+        pending_rfh->GetSiteInstance();
+    site_instance->increment_active_frame_count();
 
     contents()->GetMainFrame()->OnMessageReceived(
         FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
     EXPECT_FALSE(contents()->CrossProcessNavigationPending());
-    EXPECT_FALSE(rfh_deleted_observer.deleted());
+
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+      EXPECT_TRUE(rfh_deleted_observer.deleted());
+      EXPECT_TRUE(contents()->GetFrameTree()->root()->render_manager()
+                  ->GetRenderFrameProxyHost(site_instance.get()));
+    } else {
+      EXPECT_FALSE(rfh_deleted_observer.deleted());
+    }
   }
 }
 
diff --git a/content/browser/gamepad/gamepad_provider.cc b/content/browser/gamepad/gamepad_provider.cc
index e16339c..eef90013 100644
--- a/content/browser/gamepad/gamepad_provider.cc
+++ b/content/browser/gamepad/gamepad_provider.cc
@@ -7,10 +7,11 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
 #include "content/browser/gamepad/gamepad_data_fetcher.h"
@@ -29,9 +30,8 @@
 
 GamepadProvider::ClosureAndThread::ClosureAndThread(
     const base::Closure& c,
-    const scoped_refptr<base::MessageLoopProxy>& m)
-    : closure(c),
-      message_loop(m) {
+    const scoped_refptr<base::SingleThreadTaskRunner>& m)
+    : closure(c), task_runner(m) {
 }
 
 GamepadProvider::ClosureAndThread::~ClosureAndThread() {
@@ -83,7 +83,7 @@
     is_paused_ = true;
   }
   base::MessageLoop* polling_loop = polling_thread_->message_loop();
-  polling_loop->PostTask(
+  polling_loop->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&GamepadProvider::SendPauseHint, Unretained(this), true));
 }
@@ -97,18 +97,18 @@
   }
 
   base::MessageLoop* polling_loop = polling_thread_->message_loop();
-  polling_loop->PostTask(
+  polling_loop->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&GamepadProvider::SendPauseHint, Unretained(this), false));
-  polling_loop->PostTask(
+  polling_loop->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&GamepadProvider::ScheduleDoPoll, Unretained(this)));
 }
 
 void GamepadProvider::RegisterForUserGesture(const base::Closure& closure) {
   base::AutoLock lock(user_gesture_lock_);
-  user_gesture_observers_.push_back(ClosureAndThread(
-      closure, base::MessageLoop::current()->message_loop_proxy()));
+  user_gesture_observers_.push_back(
+      ClosureAndThread(closure, base::MessageLoop::current()->task_runner()));
 }
 
 void GamepadProvider::OnDevicesChanged(base::SystemMonitor::DeviceType type) {
@@ -144,11 +144,9 @@
 #endif
   polling_thread_->StartWithOptions(base::Thread::Options(kMessageLoopType, 0));
 
-  polling_thread_->message_loop()->PostTask(
-      FROM_HERE,
-      base::Bind(&GamepadProvider::DoInitializePollingThread,
-                 base::Unretained(this),
-                 base::Passed(&fetcher)));
+  polling_thread_->task_runner()->PostTask(
+      FROM_HERE, base::Bind(&GamepadProvider::DoInitializePollingThread,
+                            base::Unretained(this), base::Passed(&fetcher)));
 }
 
 void GamepadProvider::DoInitializePollingThread(
@@ -264,9 +262,8 @@
       return;
   }
 
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&GamepadProvider::DoPoll, Unretained(this)),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&GamepadProvider::DoPoll, Unretained(this)),
       base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs));
   have_scheduled_do_poll_ = true;
 }
@@ -313,8 +310,8 @@
   if (GamepadsHaveUserGesture(pads)) {
     ever_had_user_gesture_ = true;
     for (size_t i = 0; i < user_gesture_observers_.size(); i++) {
-      user_gesture_observers_[i].message_loop->PostTask(FROM_HERE,
-          user_gesture_observers_[i].closure);
+      user_gesture_observers_[i].task_runner->PostTask(
+          FROM_HERE, user_gesture_observers_[i].closure);
     }
     user_gesture_observers_.clear();
   }
diff --git a/content/browser/gamepad/gamepad_provider.h b/content/browser/gamepad/gamepad_provider.h
index a81061a..ce9c11a8 100644
--- a/content/browser/gamepad/gamepad_provider.h
+++ b/content/browser/gamepad/gamepad_provider.h
@@ -13,14 +13,13 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/shared_memory.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/synchronization/lock.h"
 #include "base/system_monitor/system_monitor.h"
 #include "content/common/content_export.h"
 #include "third_party/WebKit/public/platform/WebGamepads.h"
 
 namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
 class Thread;
 }
 
@@ -105,11 +104,11 @@
   base::Lock user_gesture_lock_;
   struct ClosureAndThread {
     ClosureAndThread(const base::Closure& c,
-                     const scoped_refptr<base::MessageLoopProxy>& m);
+                     const scoped_refptr<base::SingleThreadTaskRunner>& m);
     ~ClosureAndThread();
 
     base::Closure closure;
-    scoped_refptr<base::MessageLoopProxy> message_loop;
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner;
   };
   typedef std::vector<ClosureAndThread> UserGestureObserverVector;
   UserGestureObserverVector user_gesture_observers_;
diff --git a/content/browser/geofencing/geofencing_service.cc b/content/browser/geofencing/geofencing_service.cc
index 11df952..c9ea83d 100644
--- a/content/browser/geofencing/geofencing_service.cc
+++ b/content/browser/geofencing/geofencing_service.cc
@@ -4,8 +4,10 @@
 
 #include "content/browser/geofencing/geofencing_service.h"
 
+#include "base/location.h"
 #include "base/memory/singleton.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/geofencing/geofencing_provider.h"
 #include "content/browser/geofencing/geofencing_registration_delegate.h"
 #include "content/public/browser/browser_thread.h"
@@ -17,7 +19,7 @@
 
 void RunSoon(const base::Closure& callback) {
   if (!callback.is_null())
-    base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 }  // namespace
diff --git a/content/browser/geofencing/mock_geofencing_service.cc b/content/browser/geofencing/mock_geofencing_service.cc
index e53b8c7..c3a1f27a 100644
--- a/content/browser/geofencing/mock_geofencing_service.cc
+++ b/content/browser/geofencing/mock_geofencing_service.cc
@@ -10,7 +10,9 @@
 #include <cmath>
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/geofencing/geofencing_registration_delegate.h"
 #include "third_party/WebKit/public/platform/WebCircularGeofencingRegion.h"
 
@@ -21,7 +23,7 @@
 void RegisterRegionResult(GeofencingRegistrationDelegate* delegate,
                           int64 geofencing_registration_id,
                           GeofencingStatus status) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&GeofencingRegistrationDelegate::RegistrationFinished,
                  base::Unretained(delegate), geofencing_registration_id,
@@ -109,7 +111,7 @@
       PositionInRegion(last_latitude_, last_longitude_, region);
   RegisterRegionResult(delegate, id, GEOFENCING_STATUS_OK);
   if (registration.is_inside) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&GeofencingRegistrationDelegate::RegionEntered,
                               base::Unretained(delegate), id));
   }
diff --git a/content/browser/geolocation/fake_access_token_store.cc b/content/browser/geolocation/fake_access_token_store.cc
index 0e5fe4012..9e8704a 100644
--- a/content/browser/geolocation/fake_access_token_store.cc
+++ b/content/browser/geolocation/fake_access_token_store.cc
@@ -7,16 +7,14 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.h"
 
-using base::MessageLoopProxy;
 using testing::_;
 using testing::Invoke;
 
 namespace content {
 
-FakeAccessTokenStore::FakeAccessTokenStore()
-    : originating_message_loop_(NULL) {
+FakeAccessTokenStore::FakeAccessTokenStore() : originating_task_runner_(NULL) {
   ON_CALL(*this, LoadAccessTokens(_))
       .WillByDefault(Invoke(this,
                             &FakeAccessTokenStore::DefaultLoadAccessTokens));
@@ -26,9 +24,9 @@
 }
 
 void FakeAccessTokenStore::NotifyDelegateTokensLoaded() {
-  DCHECK(originating_message_loop_);
-  if (!originating_message_loop_->BelongsToCurrentThread()) {
-    originating_message_loop_->PostTask(
+  DCHECK(originating_task_runner_);
+  if (!originating_task_runner_->BelongsToCurrentThread()) {
+    originating_task_runner_->PostTask(
         FROM_HERE,
         base::Bind(&FakeAccessTokenStore::NotifyDelegateTokensLoaded, this));
     return;
@@ -40,7 +38,7 @@
 
 void FakeAccessTokenStore::DefaultLoadAccessTokens(
     const LoadAccessTokensCallbackType& callback) {
-  originating_message_loop_ = MessageLoopProxy::current().get();
+  originating_task_runner_ = base::ThreadTaskRunnerHandle::Get().get();
   callback_ = callback;
 }
 
diff --git a/content/browser/geolocation/fake_access_token_store.h b/content/browser/geolocation/fake_access_token_store.h
index 30a01859..423b317 100644
--- a/content/browser/geolocation/fake_access_token_store.h
+++ b/content/browser/geolocation/fake_access_token_store.h
@@ -5,7 +5,7 @@
 #ifndef CONTENT_BROWSER_GEOLOCATION_FAKE_ACCESS_TOKEN_STORE_H_
 #define CONTENT_BROWSER_GEOLOCATION_FAKE_ACCESS_TOKEN_STORE_H_
 
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "content/public/browser/access_token_store.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -42,7 +42,7 @@
   // In some tests, NotifyDelegateTokensLoaded() is called on a thread
   // other than the originating thread, in which case we must post
   // back to it.
-  base::MessageLoopProxy* originating_message_loop_;
+  base::SingleThreadTaskRunner* originating_task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeAccessTokenStore);
 };
diff --git a/content/browser/geolocation/geolocation_provider_impl.cc b/content/browser/geolocation/geolocation_provider_impl.cc
index 7375d57..4c322696 100644
--- a/content/browser/geolocation/geolocation_provider_impl.cc
+++ b/content/browser/geolocation/geolocation_provider_impl.cc
@@ -10,7 +10,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/singleton.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "content/browser/geolocation/location_arbitrator_impl.h"
 #include "content/public/browser/browser_thread.h"
 
@@ -121,7 +121,7 @@
                       use_high_accuracy);
   }
 
-  message_loop()->PostTask(FROM_HERE, task);
+  task_runner()->PostTask(FROM_HERE, task);
 }
 
 void GeolocationProviderImpl::StopProviders() {
@@ -139,7 +139,7 @@
 void GeolocationProviderImpl::InformProvidersPermissionGranted() {
   DCHECK(IsRunning());
   if (!OnGeolocationThread()) {
-    message_loop()->PostTask(
+    task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&GeolocationProviderImpl::InformProvidersPermissionGranted,
                    base::Unretained(this)));
diff --git a/content/browser/geolocation/geolocation_provider_impl_unittest.cc b/content/browser/geolocation/geolocation_provider_impl_unittest.cc
index 685818b..3ba4dae1 100644
--- a/content/browser/geolocation/geolocation_provider_impl_unittest.cc
+++ b/content/browser/geolocation/geolocation_provider_impl_unittest.cc
@@ -4,9 +4,10 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string16.h"
 #include "base/time/time.h"
 #include "content/browser/geolocation/geolocation_provider_impl.h"
@@ -140,11 +141,9 @@
   DCHECK(provider_->IsRunning());
   DCHECK(base::MessageLoop::current() == &message_loop_);
   bool started;
-  provider_->message_loop_proxy()->PostTaskAndReply(
-      FROM_HERE,
-      base::Bind(&GeolocationProviderTest::GetProvidersStarted,
-                 base::Unretained(this),
-                 &started),
+  provider_->task_runner()->PostTaskAndReply(
+      FROM_HERE, base::Bind(&GeolocationProviderTest::GetProvidersStarted,
+                            base::Unretained(this), &started),
       base::MessageLoop::QuitClosure());
   message_loop_.Run();
   return started;
@@ -158,11 +157,9 @@
 void GeolocationProviderTest::SendMockLocation(const Geoposition& position) {
   DCHECK(provider_->IsRunning());
   DCHECK(base::MessageLoop::current() == &message_loop_);
-  provider_->message_loop()
-      ->PostTask(FROM_HERE,
-                 base::Bind(&GeolocationProviderImpl::OnLocationUpdate,
-                            base::Unretained(provider_.get()),
-                            position));
+  provider_->task_runner()->PostTask(
+      FROM_HERE, base::Bind(&GeolocationProviderImpl::OnLocationUpdate,
+                            base::Unretained(provider_.get()), position));
 }
 
 // Regression test for http://crbug.com/59377
diff --git a/content/browser/geolocation/location_api_adapter_android.cc b/content/browser/geolocation/location_api_adapter_android.cc
index 84cfd10..a78cae22 100644
--- a/content/browser/geolocation/location_api_adapter_android.cc
+++ b/content/browser/geolocation/location_api_adapter_android.cc
@@ -8,6 +8,7 @@
 #include "base/android/jni_string.h"
 #include "base/bind.h"
 #include "base/location.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/geolocation/location_provider_android.h"
 #include "jni/LocationProviderAdapter_jni.h"
 
@@ -41,7 +42,7 @@
 
 AndroidLocationApiAdapter::~AndroidLocationApiAdapter() {
   CHECK(!location_provider_);
-  CHECK(!message_loop_.get());
+  CHECK(!task_runner_.get());
   CHECK(java_location_provider_android_object_.is_null());
 }
 
@@ -54,14 +55,14 @@
     CreateJavaObject(env);
     {
       base::AutoLock lock(lock_);
-      CHECK(!message_loop_.get());
-      message_loop_ = base::MessageLoopProxy::current();
+      CHECK(!task_runner_.get());
+      task_runner_ = base::ThreadTaskRunnerHandle::Get();
     }
   }
   // At this point we should have all our pre-conditions ready, and they'd only
   // change in Stop() which must be called on the same thread as here.
   CHECK(location_provider_);
-  CHECK(message_loop_.get());
+  CHECK(task_runner_.get());
   CHECK(!java_location_provider_android_object_.is_null());
   // We'll start receiving notifications from java in the main thread looper
   // until Stop() is called.
@@ -71,14 +72,14 @@
 
 void AndroidLocationApiAdapter::Stop() {
   if (!location_provider_) {
-    CHECK(!message_loop_.get());
+    CHECK(!task_runner_.get());
     CHECK(java_location_provider_android_object_.is_null());
     return;
   }
 
   {
     base::AutoLock lock(lock_);
-    message_loop_ = NULL;
+    task_runner_ = NULL;
   }
 
   location_provider_ = NULL;
@@ -94,7 +95,7 @@
     const Geoposition& geoposition) {
   // Called on the geolocation thread, safe to access location_provider_ here.
   if (GetInstance()->location_provider_) {
-    CHECK(GetInstance()->message_loop_->BelongsToCurrentThread());
+    CHECK(GetInstance()->task_runner_->BelongsToCurrentThread());
     GetInstance()->location_provider_->NotifyNewGeoposition(geoposition);
   }
 }
@@ -152,13 +153,12 @@
 void AndroidLocationApiAdapter::OnNewGeopositionInternal(
     const Geoposition& geoposition) {
   base::AutoLock lock(lock_);
-  if (!message_loop_.get())
+  if (!task_runner_.get())
     return;
-  message_loop_->PostTask(
+  task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(
-          &AndroidLocationApiAdapter::NotifyProviderNewGeoposition,
-          geoposition));
+      base::Bind(&AndroidLocationApiAdapter::NotifyProviderNewGeoposition,
+                 geoposition));
 }
 
 }  // namespace content
diff --git a/content/browser/geolocation/location_api_adapter_android.h b/content/browser/geolocation/location_api_adapter_android.h
index d1d2fa5..8cba148 100644
--- a/content/browser/geolocation/location_api_adapter_android.h
+++ b/content/browser/geolocation/location_api_adapter_android.h
@@ -9,9 +9,12 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/singleton.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/synchronization/lock.h"
 
+namespace base {
+class SingleThreadTaskRunner;
+}
+
 namespace content {
 class LocationProviderAndroid;
 struct Geoposition;
@@ -73,7 +76,7 @@
   // Guards against the following member which is accessed on Geolocation
   // thread and the JNI main thread looper.
   base::Lock lock_;
-  scoped_refptr<base::MessageLoopProxy> message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 };
 
 }  // namespace content
diff --git a/content/browser/geolocation/mock_location_provider.cc b/content/browser/geolocation/mock_location_provider.cc
index 2953ba1b..0bb760f 100644
--- a/content/browser/geolocation/mock_location_provider.cc
+++ b/content/browser/geolocation/mock_location_provider.cc
@@ -10,10 +10,10 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.h"
 
 namespace content {
 MockLocationProvider* MockLocationProvider::instance_ = NULL;
@@ -22,7 +22,7 @@
     : state_(STOPPED),
       is_permission_granted_(false),
       self_ref_(self_ref),
-      provider_loop_(base::MessageLoopProxy::current()) {
+      provider_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
   CHECK(self_ref_);
   CHECK(*self_ref_ == NULL);
   *self_ref_ = this;
@@ -34,16 +34,15 @@
 }
 
 void MockLocationProvider::HandlePositionChanged(const Geoposition& position) {
-  if (provider_loop_->BelongsToCurrentThread()) {
+  if (provider_task_runner_->BelongsToCurrentThread()) {
     // The location arbitrator unit tests rely on this method running
     // synchronously.
     position_ = position;
     NotifyCallback(position_);
   } else {
-    provider_loop_->PostTask(
-        FROM_HERE,
-        base::Bind(&MockLocationProvider::HandlePositionChanged,
-                   base::Unretained(this), position));
+    provider_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&MockLocationProvider::HandlePositionChanged,
+                              base::Unretained(this), position));
   }
 }
 
@@ -104,11 +103,9 @@
   void UpdateListenersIfNeeded() {
     if (!listeners_updated_) {
       listeners_updated_ = true;
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&MockLocationProvider::HandlePositionChanged,
-                     weak_factory_.GetWeakPtr(),
-                     position_));
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&MockLocationProvider::HandlePositionChanged,
+                                weak_factory_.GetWeakPtr(), position_));
     }
   }
 
diff --git a/content/browser/geolocation/mock_location_provider.h b/content/browser/geolocation/mock_location_provider.h
index 882a447..bedd2a4f 100644
--- a/content/browser/geolocation/mock_location_provider.h
+++ b/content/browser/geolocation/mock_location_provider.h
@@ -8,6 +8,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "content/browser/geolocation/location_provider_base.h"
 #include "content/public/common/geoposition.h"
@@ -36,7 +37,7 @@
   bool is_permission_granted_;
   MockLocationProvider** self_ref_;
 
-  scoped_refptr<base::MessageLoopProxy> provider_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> provider_task_runner_;
 
   // Set when an instance of the mock is created via a factory function.
   static MockLocationProvider* instance_;
diff --git a/content/browser/geolocation/network_location_provider.cc b/content/browser/geolocation/network_location_provider.cc
index 13a6504..5db43fa 100644
--- a/content/browser/geolocation/network_location_provider.cc
+++ b/content/browser/geolocation/network_location_provider.cc
@@ -5,7 +5,10 @@
 #include "content/browser/geolocation/network_location_provider.h"
 
 #include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "content/public/browser/access_token_store.h"
 
@@ -199,10 +202,9 @@
   wifi_data_provider_manager_ =
       WifiDataProviderManager::Register(&wifi_data_update_callback_);
 
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&NetworkLocationProvider::RequestPosition,
-                 weak_factory_.GetWeakPtr()),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&NetworkLocationProvider::RequestPosition,
+                            weak_factory_.GetWeakPtr()),
       base::TimeDelta::FromSeconds(kDataCompleteWaitSeconds));
   // Get the wifi data.
   is_wifi_data_complete_ = wifi_data_provider_manager_->GetData(&wifi_data_);
diff --git a/content/browser/geolocation/wifi_data_provider.cc b/content/browser/geolocation/wifi_data_provider.cc
index cd739e7..71b78c4765 100644
--- a/content/browser/geolocation/wifi_data_provider.cc
+++ b/content/browser/geolocation/wifi_data_provider.cc
@@ -27,8 +27,8 @@
 }
 
 void WifiDataProvider::RunCallbacks() {
-  client_loop_->PostTask(FROM_HERE,
-                         base::Bind(&WifiDataProvider::DoRunCallbacks, this));
+  client_loop_->task_runner()->PostTask(
+      FROM_HERE, base::Bind(&WifiDataProvider::DoRunCallbacks, this));
 }
 
 bool WifiDataProvider::CalledOnClientThread() const {
diff --git a/content/browser/geolocation/wifi_data_provider_common.cc b/content/browser/geolocation/wifi_data_provider_common.cc
index 388a17e..7bac7abf 100644
--- a/content/browser/geolocation/wifi_data_provider_common.cc
+++ b/content/browser/geolocation/wifi_data_provider_common.cc
@@ -5,6 +5,8 @@
 #include "content/browser/geolocation/wifi_data_provider_common.h"
 
 #include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 
@@ -80,10 +82,9 @@
 }
 
 void WifiDataProviderCommon::ScheduleNextScan(int interval) {
-  client_loop()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&WifiDataProviderCommon::DoWifiScanTask,
-                 weak_factory_.GetWeakPtr()),
+  client_loop()->task_runner()->PostDelayedTask(
+      FROM_HERE, base::Bind(&WifiDataProviderCommon::DoWifiScanTask,
+                            weak_factory_.GetWeakPtr()),
       base::TimeDelta::FromMilliseconds(interval));
 }
 
diff --git a/content/browser/gpu/browser_gpu_channel_host_factory.cc b/content/browser/gpu/browser_gpu_channel_host_factory.cc
index 4019ccb..d14dd4c 100644
--- a/content/browser/gpu/browser_gpu_channel_host_factory.cc
+++ b/content/browser/gpu/browser_gpu_channel_host_factory.cc
@@ -7,8 +7,11 @@
 #include <set>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/profiler/scoped_tracker.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/trace_event/trace_event.h"
 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
@@ -123,7 +126,7 @@
   IPC::ChannelHandle channel_handle_;
   gpu::GPUInfo gpu_info_;
   bool finished_;
-  scoped_refptr<base::MessageLoopProxy> main_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
 };
 
 scoped_refptr<BrowserGpuChannelHostFactory::EstablishRequest>
@@ -132,10 +135,10 @@
                                                        int gpu_host_id) {
   scoped_refptr<EstablishRequest> establish_request =
       new EstablishRequest(cause, gpu_client_id, gpu_host_id);
-  scoped_refptr<base::MessageLoopProxy> loop =
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
   // PostTask outside the constructor to ensure at least one reference exists.
-  loop->PostTask(
+  task_runner->PostTask(
       FROM_HERE,
       base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO,
                  establish_request));
@@ -152,7 +155,7 @@
       gpu_host_id_(gpu_host_id),
       reused_gpu_process_(false),
       finished_(false),
-      main_loop_(base::MessageLoopProxy::current()) {
+      main_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
 }
 
 void BrowserGpuChannelHostFactory::EstablishRequest::EstablishOnIO() {
@@ -212,7 +215,7 @@
 
 void BrowserGpuChannelHostFactory::EstablishRequest::FinishOnIO() {
   event_.Signal();
-  main_loop_->PostTask(
+  main_task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&BrowserGpuChannelHostFactory::EstablishRequest::FinishOnMain,
                  this));
@@ -228,7 +231,7 @@
 }
 
 void BrowserGpuChannelHostFactory::EstablishRequest::Wait() {
-  DCHECK(main_loop_->BelongsToCurrentThread());
+  DCHECK(main_task_runner_->BelongsToCurrentThread());
   {
     // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed.
     tracked_objects::ScopedTracker tracking_profile(
@@ -248,7 +251,7 @@
 }
 
 void BrowserGpuChannelHostFactory::EstablishRequest::Cancel() {
-  DCHECK(main_loop_->BelongsToCurrentThread());
+  DCHECK(main_task_runner_->BelongsToCurrentThread());
   finished_ = true;
 }
 
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 512170a..bc80323 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -109,6 +109,7 @@
   switches::kVModule,
 #if defined(OS_MACOSX)
   switches::kDisableRemoteCoreAnimation,
+  switches::kEnableNSGLSurfaces,
   switches::kEnableSandboxLogging,
 #endif
 #if defined(USE_AURA)
@@ -483,6 +484,11 @@
       case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
         message = "You killed the GPU process! Why?";
         break;
+#if defined(OS_CHROMEOS)
+      case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
+        message = "The GUP process was killed due to out of memory.";
+        break;
+#endif
       case base::TERMINATION_STATUS_PROCESS_CRASHED:
         message = "The GPU process crashed!";
         break;
diff --git a/content/browser/gpu/gpu_process_host_ui_shim.cc b/content/browser/gpu/gpu_process_host_ui_shim.cc
index 1df45fc8..6c7aa9c 100644
--- a/content/browser/gpu/gpu_process_host_ui_shim.cc
+++ b/content/browser/gpu/gpu_process_host_ui_shim.cc
@@ -225,8 +225,10 @@
                         OnLogMessage)
     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceInitialized,
                         OnAcceleratedSurfaceInitialized)
+#if defined(OS_MACOSX)
     IPC_MESSAGE_HANDLER(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
                         OnAcceleratedSurfaceBuffersSwapped)
+#endif
     IPC_MESSAGE_HANDLER(GpuHostMsg_GraphicsInfoCollected,
                         OnGraphicsInfoCollected)
     IPC_MESSAGE_HANDLER(GpuHostMsg_VideoMemoryUsageStats,
@@ -268,9 +270,9 @@
   view->AcceleratedSurfaceInitialized(route_id);
 }
 
+#if defined(OS_MACOSX)
 void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped(
     const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) {
-#if defined(OS_MACOSX)
   TRACE_EVENT0("renderer",
       "GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped");
   if (!ui::LatencyInfo::Verify(params.latency_info,
@@ -298,14 +300,13 @@
     ui::AcceleratedWidgetMacGotAcceleratedFrame(
         native_widget, params.surface_handle, params.latency_info, params.size,
         params.scale_factor,
+        params.damage_rect,
         base::Bind(&OnSurfaceDisplayedCallback, params.surface_id),
         &ack_params.disable_throttling, &ack_params.renderer_id);
   }
   Send(new AcceleratedSurfaceMsg_BufferPresented(params.route_id, ack_params));
-#else
-  NOTREACHED();
-#endif
 }
+#endif
 
 void GpuProcessHostUIShim::OnVideoMemoryUsageStatsReceived(
     const GPUVideoMemoryUsageStats& video_memory_usage_stats) {
diff --git a/content/browser/gpu/gpu_process_host_ui_shim.h b/content/browser/gpu/gpu_process_host_ui_shim.h
index ecd58d7c..366ff67 100644
--- a/content/browser/gpu/gpu_process_host_ui_shim.h
+++ b/content/browser/gpu/gpu_process_host_ui_shim.h
@@ -24,7 +24,9 @@
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_sender.h"
 
+#if defined(OS_MACOSX)
 struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params;
+#endif
 
 namespace ui {
 struct LatencyInfo;
@@ -90,8 +92,10 @@
   void OnGraphicsInfoCollected(const gpu::GPUInfo& gpu_info);
 
   void OnAcceleratedSurfaceInitialized(int32 surface_id, int32 route_id);
+#if defined(OS_MACOSX)
   void OnAcceleratedSurfaceBuffersSwapped(
       const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params);
+#endif
   void OnVideoMemoryUsageStatsReceived(
       const GPUVideoMemoryUsageStats& video_memory_usage_stats);
   void OnResourcesRelinquished();
diff --git a/content/browser/histogram_synchronizer.cc b/content/browser/histogram_synchronizer.cc
index 9b15b73..5851790 100644
--- a/content/browser/histogram_synchronizer.cc
+++ b/content/browser/histogram_synchronizer.cc
@@ -6,10 +6,12 @@
 
 #include "base/bind.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/histogram_delta_serialization.h"
 #include "base/pickle.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
 #include "content/browser/histogram_controller.h"
@@ -319,7 +321,7 @@
                                              const base::Closure& callback) {
   if (callback.is_null() || !thread)
     return;
-  thread->PostTask(FROM_HERE, callback);
+  thread->task_runner()->PostTask(FROM_HERE, callback);
 }
 
 int HistogramSynchronizer::GetNextAvailableSequenceNumber(
diff --git a/content/browser/indexed_db/indexed_db_browsertest.cc b/content/browser/indexed_db/indexed_db_browsertest.cc
index 2ab58c2cd..cf5b049 100644
--- a/content/browser/indexed_db/indexed_db_browsertest.cc
+++ b/content/browser/indexed_db/indexed_db_browsertest.cc
@@ -9,8 +9,9 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/thread_test_helper.h"
 #include "content/browser/browser_main_loop.h"
@@ -142,8 +143,7 @@
                    GURL("file:///")),
         base::Bind(&IndexedDBBrowserTest::DidGetDiskUsage, this));
     scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
-        BrowserMainLoop::GetInstance()->indexed_db_thread()->
-            message_loop_proxy()));
+        BrowserMainLoop::GetInstance()->indexed_db_thread()->task_runner()));
     EXPECT_TRUE(helper->Run());
     // Wait for DidGetDiskUsage to be called.
     base::MessageLoop::current()->RunUntilIdle();
@@ -156,10 +156,8 @@
         base::Bind(&IndexedDBContextImpl::GetOriginBlobFileCount, GetContext(),
                    GURL("file:///")),
         base::Bind(&IndexedDBBrowserTest::DidGetBlobFileCount, this));
-    scoped_refptr<base::ThreadTestHelper> helper(
-        new base::ThreadTestHelper(BrowserMainLoop::GetInstance()
-                                       ->indexed_db_thread()
-                                       ->message_loop_proxy()));
+    scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
+        BrowserMainLoop::GetInstance()->indexed_db_thread()->task_runner()));
     EXPECT_TRUE(helper->Run());
     // Wait for DidGetBlobFileCount to be called.
     base::MessageLoop::current()->RunUntilIdle();
@@ -323,8 +321,7 @@
         base::Bind(
             &CopyLevelDBToProfile, shell(), context, EnclosingLevelDBDir()));
     scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
-        BrowserMainLoop::GetInstance()->indexed_db_thread()->
-            message_loop_proxy()));
+        BrowserMainLoop::GetInstance()->indexed_db_thread()->task_runner()));
     ASSERT_TRUE(helper->Run());
   }
 
@@ -477,10 +474,8 @@
   GetContext()->TaskRunner()->PostTask(
       FROM_HERE, base::Bind(&IndexedDBContextImpl::DeleteForOrigin,
                             GetContext(), GURL("file:///")));
-  scoped_refptr<base::ThreadTestHelper> helper(
-      new base::ThreadTestHelper(BrowserMainLoop::GetInstance()
-                                     ->indexed_db_thread()
-                                     ->message_loop_proxy()));
+  scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper(
+      BrowserMainLoop::GetInstance()->indexed_db_thread()->task_runner()));
   ASSERT_TRUE(helper->Run());
   EXPECT_EQ(0, RequestDiskUsage());
 }
diff --git a/content/browser/indexed_db/indexed_db_quota_client.h b/content/browser/indexed_db/indexed_db_quota_client.h
index b9e9bce..a99588ca 100644
--- a/content/browser/indexed_db/indexed_db_quota_client.h
+++ b/content/browser/indexed_db/indexed_db_quota_client.h
@@ -10,7 +10,6 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "content/common/content_export.h"
 #include "storage/browser/quota/quota_client.h"
 #include "storage/browser/quota/quota_task.h"
diff --git a/content/browser/indexed_db/indexed_db_quota_client_unittest.cc b/content/browser/indexed_db/indexed_db_quota_client_unittest.cc
index f0befd2..3bec0b0 100644
--- a/content/browser/indexed_db/indexed_db_quota_client_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_quota_client_unittest.cc
@@ -8,7 +8,6 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread.h"
 #include "content/browser/browser_thread_impl.h"
@@ -44,10 +43,9 @@
     browser_context_.reset(new TestBrowserContext());
 
     scoped_refptr<storage::QuotaManager> quota_manager =
-        new MockQuotaManager(false /*in_memory*/,
-                             browser_context_->GetPath(),
-                             base::MessageLoop::current()->message_loop_proxy(),
-                             base::MessageLoop::current()->message_loop_proxy(),
+        new MockQuotaManager(false /*in_memory*/, browser_context_->GetPath(),
+                             base::MessageLoop::current()->task_runner(),
+                             base::MessageLoop::current()->task_runner(),
                              browser_context_->GetSpecialStoragePolicy());
 
     idb_context_ =
diff --git a/content/browser/indexed_db/indexed_db_transaction.cc b/content/browser/indexed_db/indexed_db_transaction.cc
index cb6fad6..926799971 100644
--- a/content/browser/indexed_db/indexed_db_transaction.cc
+++ b/content/browser/indexed_db/indexed_db_transaction.cc
@@ -5,9 +5,11 @@
 #include "content/browser/indexed_db/indexed_db_transaction.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/indexed_db/indexed_db_backing_store.h"
 #include "content/browser/indexed_db/indexed_db_cursor.h"
 #include "content/browser/indexed_db/indexed_db_database.h"
@@ -122,7 +124,7 @@
     return;
 
   should_process_queue_ = true;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&IndexedDBTransaction::ProcessTaskQueue, this));
 }
 
diff --git a/content/browser/loader/buffered_resource_handler.cc b/content/browser/loader/buffered_resource_handler.cc
index 2d4e0883..a160eed 100644
--- a/content/browser/loader/buffered_resource_handler.cc
+++ b/content/browser/loader/buffered_resource_handler.cc
@@ -7,9 +7,12 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "components/mime_util/mime_util.h"
 #include "content/browser/download/download_resource_handler.h"
 #include "content/browser/download/download_stats.h"
@@ -196,7 +199,7 @@
       NOTREACHED();
       break;
     case STATE_REPLAYING:
-      base::MessageLoop::current()->PostTask(
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE,
           base::Bind(&BufferedResourceHandler::CallReplayReadCompleted,
                      weak_ptr_factory_.GetWeakPtr()));
diff --git a/content/browser/loader/cross_site_resource_handler.h b/content/browser/loader/cross_site_resource_handler.h
index 2f70225..b73a5a1 100644
--- a/content/browser/loader/cross_site_resource_handler.h
+++ b/content/browser/loader/cross_site_resource_handler.h
@@ -49,9 +49,6 @@
   CONTENT_EXPORT static void SetLeakRequestsForTesting(
       bool leak_requests_for_testing);
 
-  // Returns whether the handler is deferred.
-  bool did_defer_for_testing() const { return did_defer_; }
-
  private:
   // Prepare to transfer the cross-site response to a new RenderFrameHost, by
   // asking it to issue an identical request (on the UI thread).
diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc
index c3b4eca5..5df1109 100644
--- a/content/browser/loader/resource_dispatcher_host_unittest.cc
+++ b/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -8,13 +8,15 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/shared_memory.h"
-#include "base/message_loop/message_loop.h"
 #include "base/pickle.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/loader/cross_site_resource_handler.h"
@@ -442,7 +444,7 @@
   }
 
   base::TaskRunner* GetTaskRunner() const override {
-    return base::MessageLoopProxy::current().get();
+    return base::ThreadTaskRunnerHandle::Get().get();
   }
 
  private:
@@ -922,7 +924,7 @@
     scoped_ptr<IPC::Message> ack(
         new ResourceHostMsg_DataReceived_ACK(request_id));
 
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&GenerateIPCMessage, filter_, base::Passed(&ack)));
   }
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index f3be2a8..ba39867c 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -5,9 +5,11 @@
 #include "content/browser/loader/resource_loader.h"
 
 #include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/metrics/histogram.h"
 #include "base/profiler/scoped_tracker.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "content/browser/appcache/appcache_interceptor.h"
 #include "content/browser/child_process_security_policy_impl.h"
@@ -63,12 +65,7 @@
   response->head.socket_address = request->GetSocketAddress();
   if (ServiceWorkerRequestHandler* handler =
           ServiceWorkerRequestHandler::GetHandler(request)) {
-    handler->GetExtraResponseInfo(
-        &response->head.was_fetched_via_service_worker,
-        &response->head.was_fallback_required_by_service_worker,
-        &response->head.original_url_via_service_worker,
-        &response->head.response_type_via_service_worker,
-        &response->head.service_worker_start_time);
+    handler->GetExtraResponseInfo(&response->head);
   }
   AppCacheInterceptor::GetExtraResponseInfo(
       request,
@@ -465,23 +462,20 @@
       request_->FollowDeferredRedirect();
       break;
     case DEFERRED_READ:
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&ResourceLoader::ResumeReading,
-                     weak_ptr_factory_.GetWeakPtr()));
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&ResourceLoader::ResumeReading,
+                                weak_ptr_factory_.GetWeakPtr()));
       break;
     case DEFERRED_RESPONSE_COMPLETE:
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&ResourceLoader::ResponseCompleted,
-                     weak_ptr_factory_.GetWeakPtr()));
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
+                                weak_ptr_factory_.GetWeakPtr()));
       break;
     case DEFERRED_FINISH:
       // Delay self-destruction since we don't know how we were reached.
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&ResourceLoader::CallDidFinishLoading,
-                     weak_ptr_factory_.GetWeakPtr()));
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&ResourceLoader::CallDidFinishLoading,
+                                weak_ptr_factory_.GetWeakPtr()));
       break;
   }
 }
@@ -545,10 +539,9 @@
     // If the request isn't in flight, then we won't get an asynchronous
     // notification from the request, so we have to signal ourselves to finish
     // this request.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&ResourceLoader::ResponseCompleted,
-                   weak_ptr_factory_.GetWeakPtr()));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&ResourceLoader::ResponseCompleted,
+                              weak_ptr_factory_.GetWeakPtr()));
   }
 }
 
@@ -623,12 +616,10 @@
   } else {
     // Else, trigger OnReadCompleted asynchronously to avoid starving the IO
     // thread in case the URLRequest can provide data synchronously.
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&ResourceLoader::OnReadCompleted,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   request_.get(),
-                   bytes_read));
+                   weak_ptr_factory_.GetWeakPtr(), request_.get(), bytes_read));
   }
 }
 
diff --git a/content/browser/loader/resource_loader_unittest.cc b/content/browser/loader/resource_loader_unittest.cc
index 16cab3a..7b4000e 100644
--- a/content/browser/loader/resource_loader_unittest.cc
+++ b/content/browser/loader/resource_loader_unittest.cc
@@ -6,9 +6,11 @@
 
 #include "base/files/file.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/loader/redirect_to_file_resource_handler.h"
 #include "content/browser/loader/resource_loader_delegate.h"
@@ -104,7 +106,7 @@
                       net::CertificateList* selected_certs,
                       const base::Closure& callback) override {
     // Don't destroy |loader_| while it's on the stack.
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&LoaderDestroyingCertStore::DoCallback,
                               base::Unretained(loader_), callback));
   }
@@ -135,7 +137,7 @@
     scoped_refptr<net::SSLCertRequestInfo> cert_request_info(
         new net::SSLCertRequestInfo);
     cert_request_info->cert_authorities = test_authorities();
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&MockClientCertURLRequestJob::NotifyCertificateRequested,
                    this, cert_request_info));
@@ -407,7 +409,7 @@
 void CreateTemporaryError(
     base::File::Error error,
     const CreateTemporaryFileStreamCallback& callback) {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(callback, error, base::Passed(scoped_ptr<net::FileStream>()),
                  scoped_refptr<ShareableFileReference>()));
@@ -779,7 +781,7 @@
     // Create mock file streams and a ShareableFileReference.
     scoped_ptr<net::testing::MockFileStream> file_stream(
         new net::testing::MockFileStream(file.Pass(),
-                                         base::MessageLoopProxy::current()));
+                                         base::ThreadTaskRunnerHandle::Get()));
     file_stream_ = file_stream.get();
     deletable_file_ = ShareableFileReference::GetOrCreate(
         temp_path_,
@@ -802,10 +804,9 @@
   void PostCallback(
       scoped_ptr<net::FileStream> file_stream,
       const CreateTemporaryFileStreamCallback& callback) {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(callback, base::File::FILE_OK,
-                   base::Passed(&file_stream), deletable_file_));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(callback, base::File::FILE_OK,
+                              base::Passed(&file_stream), deletable_file_));
   }
 
   base::FilePath temp_path_;
diff --git a/content/browser/loader/upload_data_stream_builder_unittest.cc b/content/browser/loader/upload_data_stream_builder_unittest.cc
index 57161eaf..174a89b 100644
--- a/content/browser/loader/upload_data_stream_builder_unittest.cc
+++ b/content/browser/loader/upload_data_stream_builder_unittest.cc
@@ -9,9 +9,8 @@
 
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "content/common/resource_request_body.h"
 #include "net/base/io_buffer.h"
@@ -78,7 +77,8 @@
   request_body->set_identifier(kIdentifier);
 
   scoped_ptr<net::UploadDataStream> upload(UploadDataStreamBuilder::Build(
-      request_body.get(), NULL, NULL, base::MessageLoopProxy::current().get()));
+      request_body.get(), NULL, NULL,
+      base::ThreadTaskRunnerHandle::Get().get()));
 
   EXPECT_EQ(kIdentifier, upload->identifier());
   ASSERT_TRUE(upload->GetElementReaders());
@@ -146,12 +146,9 @@
         upload_element2.length(),
         upload_element2.expected_modification_time());
 
-    scoped_ptr<net::UploadDataStream> upload(
-        UploadDataStreamBuilder::Build(
-            request_body.get(),
-            &blob_storage_context,
-            NULL,
-            base::MessageLoopProxy::current().get()));
+    scoped_ptr<net::UploadDataStream> upload(UploadDataStreamBuilder::Build(
+        request_body.get(), &blob_storage_context, NULL,
+        base::ThreadTaskRunnerHandle::Get().get()));
 
     ASSERT_TRUE(upload->GetElementReaders());
     ASSERT_EQ(2U, upload->GetElementReaders()->size());
@@ -165,10 +162,8 @@
     request_body->AppendBlob(blob_id0);
 
     upload = UploadDataStreamBuilder::Build(
-        request_body.get(),
-        &blob_storage_context,
-        NULL,
-        base::MessageLoopProxy::current().get());
+        request_body.get(), &blob_storage_context, NULL,
+        base::ThreadTaskRunnerHandle::Get().get());
     ASSERT_TRUE(upload->GetElementReaders());
     ASSERT_EQ(0U, upload->GetElementReaders()->size());
 
@@ -177,10 +172,8 @@
     request_body->AppendBlob(blob_id1);
 
     upload = UploadDataStreamBuilder::Build(
-        request_body.get(),
-        &blob_storage_context,
-        NULL,
-        base::MessageLoopProxy::current().get());
+        request_body.get(), &blob_storage_context, NULL,
+        base::ThreadTaskRunnerHandle::Get().get());
     ASSERT_TRUE(upload->GetElementReaders());
     ASSERT_EQ(2U, upload->GetElementReaders()->size());
     EXPECT_TRUE(AreElementsEqual(
@@ -201,10 +194,8 @@
         upload_element2.expected_modification_time());
 
     upload = UploadDataStreamBuilder::Build(
-        request_body.get(),
-        &blob_storage_context,
-        NULL,
-        base::MessageLoopProxy::current().get());
+        request_body.get(), &blob_storage_context, NULL,
+        base::ThreadTaskRunnerHandle::Get().get());
     ASSERT_TRUE(upload->GetElementReaders());
     ASSERT_EQ(4U, upload->GetElementReaders()->size());
     EXPECT_TRUE(AreElementsEqual(
@@ -228,11 +219,9 @@
         upload_element2.expected_modification_time());
     request_body->AppendBlob(blob_id1);
 
-    upload =
-        UploadDataStreamBuilder::Build(request_body.get(),
-                                       &blob_storage_context,
-                                       NULL,
-                                       base::MessageLoopProxy::current().get());
+    upload = UploadDataStreamBuilder::Build(
+        request_body.get(), &blob_storage_context, NULL,
+        base::ThreadTaskRunnerHandle::Get().get());
     ASSERT_TRUE(upload->GetElementReaders());
     ASSERT_EQ(4U, upload->GetElementReaders()->size());
     EXPECT_TRUE(AreElementsEqual(
@@ -257,10 +246,8 @@
         upload_element2.expected_modification_time());
 
     upload = UploadDataStreamBuilder::Build(
-        request_body.get(),
-        &blob_storage_context,
-        NULL,
-        base::MessageLoopProxy::current().get());
+        request_body.get(), &blob_storage_context, NULL,
+        base::ThreadTaskRunnerHandle::Get().get());
     ASSERT_TRUE(upload->GetElementReaders());
     ASSERT_EQ(4U, upload->GetElementReaders()->size());
     EXPECT_TRUE(AreElementsEqual(
@@ -287,10 +274,8 @@
         upload_element2.expected_modification_time());
 
     upload = UploadDataStreamBuilder::Build(
-        request_body.get(),
-        &blob_storage_context,
-        NULL,
-        base::MessageLoopProxy::current().get());
+        request_body.get(), &blob_storage_context, NULL,
+        base::ThreadTaskRunnerHandle::Get().get());
     ASSERT_TRUE(upload->GetElementReaders());
     ASSERT_EQ(8U, upload->GetElementReaders()->size());
     EXPECT_TRUE(AreElementsEqual(
@@ -341,7 +326,7 @@
     scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
     scoped_ptr<net::UploadDataStream> upload(UploadDataStreamBuilder::Build(
         request_body.get(), &blob_storage_context, NULL,
-        base::MessageLoopProxy::current().get()));
+        base::ThreadTaskRunnerHandle::Get().get()));
 
     request_body = new ResourceRequestBody();
     request_body->AppendBlob(blob_id);
@@ -350,7 +335,7 @@
 
     upload = UploadDataStreamBuilder::Build(
         request_body.get(), &blob_storage_context, NULL,
-        base::MessageLoopProxy::current().get());
+        base::ThreadTaskRunnerHandle::Get().get());
     ASSERT_TRUE(upload->GetElementReaders());
     const auto& readers = *upload->GetElementReaders();
     ASSERT_EQ(3U, readers.size());
diff --git a/content/browser/media/capture/content_video_capture_device_core.cc b/content/browser/media/capture/content_video_capture_device_core.cc
index 051aec1..edfe2e5 100644
--- a/content/browser/media/capture/content_video_capture_device_core.cc
+++ b/content/browser/media/capture/content_video_capture_device_core.cc
@@ -11,7 +11,6 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/histogram.h"
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string_number_conversions.h"
@@ -22,7 +21,6 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "content/public/browser/browser_thread.h"
-#include "media/base/bind_to_current_loop.h"
 #include "media/base/video_capture_types.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_frame_metadata.h"
@@ -189,10 +187,34 @@
         media::VideoFrameMetadata::CAPTURE_END_TIME, base::TimeTicks::Now());
     frame->metadata()->SetTimeDelta(media::VideoFrameMetadata::FRAME_DURATION,
                                     estimated_frame_duration);
+
+    frame->AddDestructionObserver(base::Bind(
+        &ThreadSafeCaptureOracle::DidConsumeFrame,
+        this,
+        frame_number,
+        frame->metadata()));
+
     client_->OnIncomingCapturedVideoFrame(buffer.Pass(), frame, timestamp);
   }
 }
 
+void ThreadSafeCaptureOracle::DidConsumeFrame(
+    int frame_number,
+    const media::VideoFrameMetadata* metadata) {
+  // Note: This function may be called on any thread by the VideoFrame
+  // destructor.  |metadata| is still valid for read-access at this point.
+  double utilization = -1.0;
+  if (metadata->GetDouble(media::VideoFrameMetadata::RESOURCE_UTILIZATION,
+                          &utilization) &&
+      utilization >= 0.0) {
+    VLOG(2) << "Consumer resource utilization for frame " << frame_number
+            << ": " << utilization;
+  }
+
+  // TODO(miu): Use |utilization| to drive automatic video resolution changes.
+  // http://crbug.com/156767.
+}
+
 void ContentVideoCaptureDeviceCore::AllocateAndStart(
     const media::VideoCaptureParams& params,
     scoped_ptr<media::VideoCaptureDevice::Client> client) {
diff --git a/content/browser/media/capture/content_video_capture_device_core.h b/content/browser/media/capture/content_video_capture_device_core.h
index 50600cf4..5a928a50 100644
--- a/content/browser/media/capture/content_video_capture_device_core.h
+++ b/content/browser/media/capture/content_video_capture_device_core.h
@@ -85,6 +85,11 @@
       base::TimeTicks timestamp,
       bool success);
 
+  // Callback invoked once all consumers have finished with a delivered video
+  // frame.  Consumer feedback signals are scanned from the frame's |metadata|.
+  void DidConsumeFrame(int frame_number,
+                       const media::VideoFrameMetadata* metadata);
+
   // Protects everything below it.
   mutable base::Lock lock_;
 
diff --git a/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc b/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc
index 0eebd7a..c7c9c84 100644
--- a/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc
+++ b/content/browser/media/capture/web_contents_audio_input_stream_unittest.cc
@@ -8,7 +8,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
@@ -201,8 +201,7 @@
   }
 
   void Open() {
-    mock_vais_ =
-        new MockVirtualAudioInputStream(audio_thread_.message_loop_proxy());
+    mock_vais_ = new MockVirtualAudioInputStream(audio_thread_.task_runner());
     EXPECT_CALL(*mock_vais_, Open());
     EXPECT_CALL(*mock_vais_, Close());  // At Close() time.
 
@@ -341,7 +340,7 @@
   }
 
   void RunOnAudioThread(const base::Closure& closure) {
-    audio_thread_.message_loop()->PostTask(FROM_HERE, closure);
+    audio_thread_.task_runner()->PostTask(FROM_HERE, closure);
   }
 
   // Block the calling thread until OnData() callbacks are being made.
diff --git a/content/browser/media/capture/web_contents_video_capture_device.cc b/content/browser/media/capture/web_contents_video_capture_device.cc
index def9f9a..dca65d3 100644
--- a/content/browser/media/capture/web_contents_video_capture_device.cc
+++ b/content/browser/media/capture/web_contents_video_capture_device.cc
@@ -53,12 +53,13 @@
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/histogram.h"
 #include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
@@ -633,9 +634,9 @@
     UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time);
     TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture", "Capture", target.get(),
                                  "Render");
-    render_thread_->message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
-        &RenderVideoFrame, bitmap, target,
-        base::Bind(deliver_frame_cb, start_time)));
+    render_thread_->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&RenderVideoFrame, bitmap, target,
+                              base::Bind(deliver_frame_cb, start_time)));
   } else {
     // Capture can fail due to transient issues, so just skip this frame.
     DVLOG(1) << "CopyFromBackingStore failed; skipping frame.";
diff --git a/content/browser/media/media_internals.cc b/content/browser/media/media_internals.cc
index f0b071a4..7f4d62e 100644
--- a/content/browser/media/media_internals.cc
+++ b/content/browser/media/media_internals.cc
@@ -457,7 +457,9 @@
 }
 
 MediaInternals::MediaInternals()
-    : owner_ids_(), uma_handler_(new MediaInternalsUMAHandler()) {
+    : can_update_(false),
+      owner_ids_(),
+      uma_handler_(new MediaInternalsUMAHandler()) {
 }
 
 MediaInternals::~MediaInternals() {}
@@ -493,25 +495,36 @@
       dict.Set("params", event->params.DeepCopy());
     }
 
-    SendUpdate(SerializeUpdate("media.onMediaEvent", &dict));
+    if (CanUpdate())
+      SendUpdate(SerializeUpdate("media.onMediaEvent", &dict));
     uma_handler_->SavePlayerState(*event, render_process_id);
   }
 }
 
 void MediaInternals::AddUpdateCallback(const UpdateCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   update_callbacks_.push_back(callback);
+
+  base::AutoLock auto_lock(lock_);
+  can_update_ = true;
 }
 
 void MediaInternals::RemoveUpdateCallback(const UpdateCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
   for (size_t i = 0; i < update_callbacks_.size(); ++i) {
     if (update_callbacks_[i].Equals(callback)) {
       update_callbacks_.erase(update_callbacks_.begin() + i);
-      return;
+      break;
     }
   }
-  NOTREACHED();
+
+  base::AutoLock auto_lock(lock_);
+  can_update_ = !update_callbacks_.empty();
+}
+
+bool MediaInternals::CanUpdate() {
+  base::AutoLock auto_lock(lock_);
+  return can_update_;
 }
 
 void MediaInternals::SendAudioStreamData() {
@@ -526,6 +539,10 @@
 
 void MediaInternals::SendVideoCaptureDeviceCapabilities() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  if (!CanUpdate())
+    return;
+
   SendUpdate(SerializeUpdate("media.onReceiveVideoCaptureCapabilities",
                              &video_capture_capabilities_cached_data_));
 }
@@ -553,8 +570,7 @@
     video_capture_capabilities_cached_data_.Append(device_dict);
   }
 
-  if (update_callbacks_.size() > 0)
-    SendVideoCaptureDeviceCapabilities();
+  SendVideoCaptureDeviceCapabilities();
 }
 
 scoped_ptr<media::AudioLog> MediaInternals::CreateAudioLog(
@@ -574,11 +590,9 @@
 }
 
 void MediaInternals::SendUpdate(const base::string16& update) {
-  // SendUpdate() may be called from any thread, but must run on the IO thread.
-  // TODO(dalecurtis): This is pretty silly since the update callbacks simply
-  // forward the calls to the UI thread.  We should avoid the extra hop.
-  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
-    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
+  // SendUpdate() may be called from any thread, but must run on the UI thread.
+  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
         &MediaInternals::SendUpdate, base::Unretained(this), update));
     return;
   }
@@ -591,6 +605,9 @@
                                         const std::string& cache_key,
                                         const std::string& function,
                                         const base::DictionaryValue* value) {
+  if (!CanUpdate())
+    return;
+
   {
     base::AutoLock auto_lock(lock_);
     const bool has_entry = audio_streams_cached_data_.HasKey(cache_key);
diff --git a/content/browser/media/media_internals.h b/content/browser/media/media_internals.h
index 657fea4..72efdd6b 100644
--- a/content/browser/media/media_internals.h
+++ b/content/browser/media/media_internals.h
@@ -41,10 +41,15 @@
   void OnMediaEvents(int render_process_id,
                      const std::vector<media::MediaLogEvent>& events);
 
-  // Add/remove update callbacks (see above).  Must be called on the IO thread.
+  // Add/remove update callbacks (see above). Must be called on the UI thread.
+  // The callbacks must also be fired on UI thread.
   void AddUpdateCallback(const UpdateCallback& callback);
   void RemoveUpdateCallback(const UpdateCallback& callback);
 
+  // Whether there are any update callbacks available. Can be called on any
+  // thread.
+  bool CanUpdate();
+
   // Sends all audio cached data to each registered UpdateCallback.
   void SendAudioStreamData();
 
@@ -95,12 +100,15 @@
                           const std::string& function,
                           const base::DictionaryValue* value);
 
-  // Must only be accessed on the IO thread.
+  // Must only be accessed on the UI thread.
   std::vector<UpdateCallback> update_callbacks_;
+
+  // Must only be accessed on the IO thread.
   base::ListValue video_capture_capabilities_cached_data_;
 
   // All variables below must be accessed under |lock_|.
   base::Lock lock_;
+  bool can_update_;
   base::DictionaryValue audio_streams_cached_data_;
   int owner_ids_[AUDIO_COMPONENT_MAX];
   scoped_ptr<MediaInternalsUMAHandler> uma_handler_;
diff --git a/content/browser/media/media_internals_proxy.cc b/content/browser/media/media_internals_proxy.cc
index 05f4dd82..771d5f7 100644
--- a/content/browser/media/media_internals_proxy.cc
+++ b/content/browser/media/media_internals_proxy.cc
@@ -5,7 +5,9 @@
 #include "content/browser/media/media_internals_proxy.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/media/media_internals_handler.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/notification_service.h"
@@ -42,7 +44,11 @@
 
 void MediaInternalsProxy::Attach(MediaInternalsMessageHandler* handler) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
   handler_ = handler;
+  update_callback_ = base::Bind(&MediaInternalsProxy::UpdateUIOnUIThread, this);
+  MediaInternals::GetInstance()->AddUpdateCallback(update_callback_);
+
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
       base::Bind(&MediaInternalsProxy::ObserveMediaInternalsOnIOThread, this));
@@ -50,7 +56,10 @@
 
 void MediaInternalsProxy::Detach() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
   handler_ = NULL;
+  MediaInternals::GetInstance()->RemoveUpdateCallback(update_callback_);
+
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
       base::Bind(
@@ -69,13 +78,6 @@
   CallJavaScriptFunctionOnUIThread("media.onReceiveConstants", GetConstants());
 }
 
-void MediaInternalsProxy::OnUpdate(const base::string16& update) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&MediaInternalsProxy::UpdateUIOnUIThread, this, update));
-}
-
 void MediaInternalsProxy::OnAddEntry(const net::NetLog::Entry& entry) {
   bool is_event_interesting = false;
   for (size_t i = 0; i < arraysize(kNetEventTypeFilter); i++) {
@@ -117,9 +119,6 @@
 
 void MediaInternalsProxy::ObserveMediaInternalsOnIOThread() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  update_callback_ = base::Bind(&MediaInternalsProxy::OnUpdate,
-                                base::Unretained(this));
-  MediaInternals::GetInstance()->AddUpdateCallback(update_callback_);
   if (GetContentClient()->browser()->GetNetLog()) {
     net::NetLog* net_log = GetContentClient()->browser()->GetNetLog();
     net_log->DeprecatedAddObserver(
@@ -129,7 +128,6 @@
 
 void MediaInternalsProxy::StopObservingMediaInternalsOnIOThread() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  MediaInternals::GetInstance()->RemoveUpdateCallback(update_callback_);
   if (GetContentClient()->browser()->GetNetLog()) {
     net::NetLog* net_log = GetContentClient()->browser()->GetNetLog();
     net_log->DeprecatedRemoveObserver(this);
@@ -156,7 +154,7 @@
   // if an update is not already pending.
   if (!pending_net_updates_) {
     pending_net_updates_.reset(new base::ListValue());
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::Bind(&MediaInternalsProxy::SendNetEventsOnUIThread, this),
         base::TimeDelta::FromMilliseconds(
diff --git a/content/browser/media/media_internals_proxy.h b/content/browser/media/media_internals_proxy.h
index af6740c..f12e24e 100644
--- a/content/browser/media/media_internals_proxy.h
+++ b/content/browser/media/media_internals_proxy.h
@@ -48,9 +48,6 @@
   // Have MediaInternals send all the data it has.
   void GetEverything();
 
-  // MediaInternals callback. Called on the IO thread.
-  void OnUpdate(const base::string16& update);
-
   // net::NetLog::ThreadSafeObserver implementation. Callable from any thread:
   void OnAddEntry(const net::NetLog::Entry& entry) override;
 
@@ -65,6 +62,8 @@
   void ObserveMediaInternalsOnIOThread();
   void StopObservingMediaInternalsOnIOThread();
   void GetEverythingOnIOThread();
+
+  // Callback for MediaInternals to update. Must be called on UI thread.
   void UpdateUIOnUIThread(const base::string16& update);
 
   // Put |entry| on a list of events to be sent to the page.
diff --git a/content/browser/media/webrtc_browsertest.cc b/content/browser/media/webrtc_browsertest.cc
index 36f7a408..ecb8700 100644
--- a/content/browser/media/webrtc_browsertest.cc
+++ b/content/browser/media/webrtc_browsertest.cc
@@ -4,7 +4,6 @@
 
 #include "base/command_line.h"
 #include "base/files/file_util.h"
-#include "base/strings/stringprintf.h"
 #include "base/threading/platform_thread.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/common/content_switches.h"
@@ -16,18 +15,6 @@
 #include "media/base/media_switches.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
-namespace {
-
-#if defined (OS_ANDROID) || defined(THREAD_SANITIZER)
-// Just do the bare minimum of audio checking on Android and under TSAN since
-// it's a bit sensitive to device performance.
-const char kUseLenientAudioChecking[] = "true";
-#else
-const char kUseLenientAudioChecking[] = "false";
-#endif
-
-}  // namespace
-
 namespace content {
 
 #if defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
@@ -196,10 +183,8 @@
 #endif
 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
                        MAYBE_CanMakeVideoCallAndThenRenegotiateToAudio) {
-  MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
-      "callAndRenegotiateToAudio("
-      "    %s, {audio: true, video:true}, {audio: true});",
-      kUseLenientAudioChecking));
+  MakeAudioDetectingPeerConnectionCall(
+      "callAndRenegotiateToAudio({audio: true, video:true}, {audio: true});");
 }
 
 // This test makes a call between pc1 and pc2 where a video only stream is sent
@@ -363,51 +348,44 @@
 
 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
                        EstablishAudioVideoCallAndEnsureAudioIsPlaying) {
-  MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
-      "callAndEnsureAudioIsPlaying(%s, {audio:true, video:true});",
-      kUseLenientAudioChecking));
+  MakeAudioDetectingPeerConnectionCall(
+      "callAndEnsureAudioIsPlaying({audio:true, video:true});");
 }
 
 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
                        EstablishAudioOnlyCallAndEnsureAudioIsPlaying) {
-  MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
-      "callAndEnsureAudioIsPlaying(%s, {audio:true});",
-      kUseLenientAudioChecking));
+  MakeAudioDetectingPeerConnectionCall(
+      "callAndEnsureAudioIsPlaying({audio:true});");
 }
 
 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
                        EstablishIsac16KCallAndEnsureAudioIsPlaying) {
-  MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
-      "callWithIsac16KAndEnsureAudioIsPlaying(%s, {audio:true});",
-      kUseLenientAudioChecking));
+  MakeAudioDetectingPeerConnectionCall(
+      "callWithIsac16KAndEnsureAudioIsPlaying({audio:true});");
 }
 
 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
                        EstablishAudioVideoCallAndVerifyRemoteMutingWorks) {
-  MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
-      "callAndEnsureRemoteAudioTrackMutingWorks(%s);",
-      kUseLenientAudioChecking));
+  MakeAudioDetectingPeerConnectionCall(
+      "callAndEnsureRemoteAudioTrackMutingWorks();");
 }
 
 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
                        EstablishAudioVideoCallAndVerifyLocalMutingWorks) {
-  MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
-      "callAndEnsureLocalAudioTrackMutingWorks(%s);",
-      kUseLenientAudioChecking));
+  MakeAudioDetectingPeerConnectionCall(
+      "callAndEnsureLocalAudioTrackMutingWorks();");
 }
 
 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
                        EnsureLocalVideoMuteDoesntMuteAudio) {
-  MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
-      "callAndEnsureLocalVideoMutingDoesntMuteAudio(%s);",
-      kUseLenientAudioChecking));
+  MakeAudioDetectingPeerConnectionCall(
+      "callAndEnsureLocalVideoMutingDoesntMuteAudio();");
 }
 
 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
                        EnsureRemoteVideoMuteDoesntMuteAudio) {
-  MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
-      "callAndEnsureRemoteVideoMutingDoesntMuteAudio(%s);",
-      kUseLenientAudioChecking));
+  MakeAudioDetectingPeerConnectionCall(
+      "callAndEnsureRemoteVideoMutingDoesntMuteAudio();");
 }
 
 // Flaky on TSAN v2: http://crbug.com/373637
@@ -420,8 +398,8 @@
 #endif
 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest,
                        MAYBE_EstablishAudioVideoCallAndVerifyUnmutingWorks) {
-  MakeAudioDetectingPeerConnectionCall(base::StringPrintf(
-      "callAndEnsureAudioTrackUnmutingWorks(%s);", kUseLenientAudioChecking));
+  MakeAudioDetectingPeerConnectionCall(
+      "callAndEnsureAudioTrackUnmutingWorks();");
 }
 
 IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, CallAndVerifyVideoMutingWorks) {
diff --git a/content/browser/mojo/mojo_app_connection_impl.cc b/content/browser/mojo/mojo_app_connection_impl.cc
new file mode 100644
index 0000000..d643bbf
--- /dev/null
+++ b/content/browser/mojo/mojo_app_connection_impl.cc
@@ -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.
+
+#include "content/browser/mojo/mojo_app_connection_impl.h"
+
+#include "content/browser/mojo/mojo_shell_context.h"
+
+namespace content {
+
+scoped_ptr<MojoAppConnection> MojoAppConnection::Create(const GURL& url) {
+  return scoped_ptr<MojoAppConnection>(new MojoAppConnectionImpl(url));
+}
+
+MojoAppConnectionImpl::MojoAppConnectionImpl(const GURL& url) {
+  MojoShellContext::ConnectToApplication(url, mojo::GetProxy(&services_));
+}
+
+MojoAppConnectionImpl::~MojoAppConnectionImpl() {
+}
+
+void MojoAppConnectionImpl::ConnectToService(
+    const std::string& service_name,
+    mojo::ScopedMessagePipeHandle handle) {
+  services_->ConnectToService(service_name, handle.Pass());
+}
+
+}  // namespace content
diff --git a/content/browser/mojo/mojo_app_connection_impl.h b/content/browser/mojo/mojo_app_connection_impl.h
new file mode 100644
index 0000000..4628acc
--- /dev/null
+++ b/content/browser/mojo/mojo_app_connection_impl.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 CONTENT_BROWSER_MOJO_MOJO_APP_CONNECTION_IMPL_H_
+#define CONTENT_BROWSER_MOJO_MOJO_APP_CONNECTION_IMPL_H_
+
+#include "base/macros.h"
+#include "content/public/browser/mojo_app_connection.h"
+#include "mojo/application/public/interfaces/service_provider.mojom.h"
+
+class GURL;
+
+namespace content {
+
+// Implementation of the app connection mechanism provided to browser code.
+class MojoAppConnectionImpl : public MojoAppConnection {
+ public:
+  explicit MojoAppConnectionImpl(const GURL& url);
+  ~MojoAppConnectionImpl() override;
+
+ private:
+  // MojoAppConnection:
+  void ConnectToService(const std::string& service_name,
+                        mojo::ScopedMessagePipeHandle handle) override;
+
+  mojo::ServiceProviderPtr services_;
+
+  DISALLOW_COPY_AND_ASSIGN(MojoAppConnectionImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_MOJO_MOJO_APP_CONNECTION_IMPL_H_
diff --git a/content/browser/mojo/mojo_shell_context.cc b/content/browser/mojo/mojo_shell_context.cc
new file mode 100644
index 0000000..49e66a9
--- /dev/null
+++ b/content/browser/mojo/mojo_shell_context.cc
@@ -0,0 +1,178 @@
+// 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 "content/browser/mojo/mojo_shell_context.h"
+
+#include "base/lazy_instance.h"
+#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
+#include "content/common/process_control.mojom.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/utility_process_host.h"
+#include "content/public/browser/utility_process_host_client.h"
+#include "content/public/common/content_client.h"
+#include "content/public/common/service_registry.h"
+#include "mojo/application/public/cpp/application_delegate.h"
+#include "mojo/common/url_type_converters.h"
+#include "mojo/services/network/public/interfaces/url_loader.mojom.h"
+#include "mojo/shell/application_loader.h"
+#include "mojo/shell/static_application_loader.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/string.h"
+
+namespace content {
+
+namespace {
+
+// Virtual app URL to use as the requestor identity when connecting from browser
+// code to a Mojo app via the shell proxy.
+const char kBrowserAppUrl[] = "system:content_browser";
+
+// An extra set of apps to register on initialization, if set by a test.
+const MojoShellContext::StaticApplicationMap* g_applications_for_test;
+
+void StartProcessOnIOThread(mojo::InterfaceRequest<ProcessControl> request) {
+  UtilityProcessHost* process_host =
+      UtilityProcessHost::Create(nullptr, nullptr);
+  // TODO(rockot): Make it possible for the embedder to associate app URLs with
+  // app names so we can have more meaningful process names here.
+  process_host->SetName(base::UTF8ToUTF16("Mojo Application"));
+  process_host->StartMojoMode();
+  ServiceRegistry* services = process_host->GetServiceRegistry();
+  services->ConnectToRemoteService(request.Pass());
+}
+
+void OnApplicationLoaded(const GURL& url, bool success) {
+  if (!success)
+    LOG(ERROR) << "Failed to launch Mojo application for " << url.spec();
+}
+
+// The default loader to use for all applications. This launches a utility
+// process and forwards the Load request the ProcessControl service there.
+class UtilityProcessLoader : public mojo::shell::ApplicationLoader {
+ public:
+  UtilityProcessLoader() {}
+  ~UtilityProcessLoader() override {}
+
+ private:
+  // mojo::shell::ApplicationLoader:
+  void Load(
+      const GURL& url,
+      mojo::InterfaceRequest<mojo::Application> application_request) override {
+    ProcessControlPtr process_control;
+    auto process_request = mojo::GetProxy(&process_control);
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::Bind(&StartProcessOnIOThread, base::Passed(&process_request)));
+    process_control->LoadApplication(url.spec(), application_request.Pass(),
+                                     base::Bind(&OnApplicationLoaded, url));
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(UtilityProcessLoader);
+};
+
+}  // namespace
+
+// Thread-safe proxy providing access to the shell context from any thread.
+class MojoShellContext::Proxy {
+ public:
+  Proxy(MojoShellContext* shell_context)
+      : shell_context_(shell_context),
+        task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
+
+  ~Proxy() {}
+
+  void ConnectToApplication(
+      const GURL& url,
+      mojo::InterfaceRequest<mojo::ServiceProvider> request) {
+    if (task_runner_ == base::ThreadTaskRunnerHandle::Get()) {
+      if (shell_context_)
+        shell_context_->ConnectToApplicationOnOwnThread(url, request.Pass());
+    } else {
+      // |shell_context_| outlives the main MessageLoop, so it's safe for it to
+      // be unretained here.
+      task_runner_->PostTask(
+          FROM_HERE,
+          base::Bind(&MojoShellContext::ConnectToApplicationOnOwnThread,
+                     base::Unretained(shell_context_), url,
+                     base::Passed(&request)));
+    }
+  }
+
+ private:
+  MojoShellContext* shell_context_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(Proxy);
+};
+
+// static
+base::LazyInstance<scoped_ptr<MojoShellContext::Proxy>>
+    MojoShellContext::proxy_ = LAZY_INSTANCE_INITIALIZER;
+
+void MojoShellContext::SetApplicationsForTest(
+    const StaticApplicationMap* apps) {
+  g_applications_for_test = apps;
+}
+
+MojoShellContext::MojoShellContext()
+    : application_manager_(new mojo::shell::ApplicationManager(this)) {
+  proxy_.Get().reset(new Proxy(this));
+  application_manager_->set_default_loader(
+      scoped_ptr<mojo::shell::ApplicationLoader>(new UtilityProcessLoader));
+
+  StaticApplicationMap apps;
+  GetContentClient()->browser()->RegisterMojoApplications(&apps);
+  if (g_applications_for_test) {
+    // Add testing apps to the map, potentially overwriting whatever the
+    // browser client registered.
+    for (const auto& entry : *g_applications_for_test)
+      apps[entry.first] = entry.second;
+  }
+  for (const auto& entry : apps) {
+    application_manager_->SetLoaderForURL(
+        scoped_ptr<mojo::shell::ApplicationLoader>(
+            new mojo::shell::StaticApplicationLoader(entry.second)),
+        entry.first);
+  }
+}
+
+MojoShellContext::~MojoShellContext() {
+}
+
+// static
+void MojoShellContext::ConnectToApplication(
+    const GURL& url,
+    mojo::InterfaceRequest<mojo::ServiceProvider> request) {
+  proxy_.Get()->ConnectToApplication(url, request.Pass());
+}
+
+void MojoShellContext::ConnectToApplicationOnOwnThread(
+    const GURL& url,
+    mojo::InterfaceRequest<mojo::ServiceProvider> request) {
+  mojo::URLRequestPtr url_request = mojo::URLRequest::New();
+  url_request->url = mojo::String::From(url);
+  application_manager_->ConnectToApplication(
+      url_request.Pass(), GURL(kBrowserAppUrl), request.Pass(),
+      mojo::ServiceProviderPtr(), base::Bind(&base::DoNothing));
+}
+
+GURL MojoShellContext::ResolveMappings(const GURL& url) {
+  return url;
+}
+
+GURL MojoShellContext::ResolveMojoURL(const GURL& url) {
+  return url;
+}
+
+bool MojoShellContext::CreateFetcher(
+    const GURL& url,
+    const mojo::shell::Fetcher::FetchCallback& loader_callback) {
+  return false;
+}
+
+}  // namespace content
diff --git a/content/browser/mojo/mojo_shell_context.h b/content/browser/mojo/mojo_shell_context.h
new file mode 100644
index 0000000..b0ac5b16
--- /dev/null
+++ b/content/browser/mojo/mojo_shell_context.h
@@ -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.
+
+#ifndef CONTENT_BROWSER_MOJO_MOJO_SHELL_CONTEXT_H_
+#define CONTENT_BROWSER_MOJO_MOJO_SHELL_CONTEXT_H_
+
+#include <map>
+
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
+#include "base/lazy_instance.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "mojo/shell/application_manager.h"
+
+class GURL;
+
+namespace mojo {
+class ApplicationDelegate;
+}
+
+namespace content {
+
+// MojoShellContext hosts the browser's ApplicationManager, coordinating
+// app registration and interconnection.
+class CONTENT_EXPORT MojoShellContext
+    : public NON_EXPORTED_BASE(mojo::shell::ApplicationManager::Delegate) {
+ public:
+  using StaticApplicationMap =
+      std::map<GURL, base::Callback<scoped_ptr<mojo::ApplicationDelegate>()>>;
+
+  MojoShellContext();
+  ~MojoShellContext() override;
+
+  // Connects an application at |url| and gets a handle to its exposed services.
+  // This is only intended for use in browser code that's not part of some Mojo
+  // application. May be called from any thread.
+  static void ConnectToApplication(
+      const GURL& url,
+      mojo::InterfaceRequest<mojo::ServiceProvider> request);
+
+  static void SetApplicationsForTest(const StaticApplicationMap* apps);
+
+ private:
+  class Proxy;
+  friend class Proxy;
+
+  void ConnectToApplicationOnOwnThread(
+      const GURL& url,
+      mojo::InterfaceRequest<mojo::ServiceProvider> request);
+
+  // mojo::shell::ApplicationManager::Delegate:
+  GURL ResolveMappings(const GURL& url) override;
+  GURL ResolveMojoURL(const GURL& url) override;
+  bool CreateFetcher(
+      const GURL& url,
+      const mojo::shell::Fetcher::FetchCallback& loader_callback) override;
+
+  static base::LazyInstance<scoped_ptr<Proxy>> proxy_;
+
+  scoped_ptr<mojo::shell::ApplicationManager> application_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(MojoShellContext);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_MOJO_MOJO_SHELL_CONTEXT_H_
diff --git a/content/browser/mojo_shell_browsertest.cc b/content/browser/mojo_shell_browsertest.cc
new file mode 100644
index 0000000..3dcde732
--- /dev/null
+++ b/content/browser/mojo_shell_browsertest.cc
@@ -0,0 +1,60 @@
+// 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/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "content/browser/mojo/mojo_shell_context.h"
+#include "content/public/browser/mojo_app_connection.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/test_mojo_app.h"
+#include "content/public/test/test_mojo_service.mojom.h"
+#include "url/gurl.h"
+
+namespace content {
+
+const char kInProcessTestMojoAppUrl[] = "system:content_in_process_test_app";
+
+class MojoShellTest : public ContentBrowserTest {
+ public:
+  MojoShellTest() {
+    test_apps_[GURL(kInProcessTestMojoAppUrl)] = base::Bind(&CreateTestApp);
+    MojoShellContext::SetApplicationsForTest(&test_apps_);
+  }
+
+ private:
+  static scoped_ptr<mojo::ApplicationDelegate> CreateTestApp() {
+    return scoped_ptr<mojo::ApplicationDelegate>(new TestMojoApp);
+  }
+
+  MojoShellContext::StaticApplicationMap test_apps_;
+
+  DISALLOW_COPY_AND_ASSIGN(MojoShellTest);
+};
+
+IN_PROC_BROWSER_TEST_F(MojoShellTest, TestBrowserConnection) {
+  auto test_app = MojoAppConnection::Create(GURL(kInProcessTestMojoAppUrl));
+  TestMojoServicePtr test_service;
+  test_app->ConnectToService(&test_service);
+
+  base::RunLoop run_loop;
+  test_service->DoSomething(run_loop.QuitClosure());
+  run_loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(MojoShellTest, TestUtilityConnection) {
+  // With no loader registered at this URL, the shell should spawn a utility
+  // process and connect us to it. content_shell's utility process always hosts
+  // a TestMojoApp at |kTestMojoAppUrl|.
+  auto test_app = MojoAppConnection::Create(GURL(kTestMojoAppUrl));
+  TestMojoServicePtr test_service;
+  test_app->ConnectToService(&test_service);
+
+  base::RunLoop run_loop;
+  test_service->DoSomething(run_loop.QuitClosure());
+  run_loop.Run();
+}
+
+}  // namespace content
diff --git a/content/browser/net/view_http_cache_job_factory.cc b/content/browser/net/view_http_cache_job_factory.cc
index e80cac72..6b46b618 100644
--- a/content/browser/net/view_http_cache_job_factory.cc
+++ b/content/browser/net/view_http_cache_job_factory.cc
@@ -8,9 +8,11 @@
 #include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/compiler_specific.h"
+#include "base/location.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/common/url_constants.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_errors.h"
@@ -96,7 +98,7 @@
 };
 
 void ViewHttpCacheJob::Start() {
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&ViewHttpCacheJob::StartAsync, weak_factory_.GetWeakPtr()));
 }
diff --git a/content/browser/notifications/platform_notification_context_unittest.cc b/content/browser/notifications/platform_notification_context_unittest.cc
index 30ab46a..4560f7d 100644
--- a/content/browser/notifications/platform_notification_context_unittest.cc
+++ b/content/browser/notifications/platform_notification_context_unittest.cc
@@ -6,6 +6,7 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/notifications/platform_notification_context_impl.h"
 #include "content/browser/service_worker/embedded_worker_test_helper.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
@@ -99,7 +100,7 @@
   // Overrides the task runner in |context| with the current message loop
   // proxy, to reduce the number of threads involved in the tests.
   void OverrideTaskRunnerForTesting(PlatformNotificationContextImpl* context) {
-    context->SetTaskRunnerForTesting(base::MessageLoopProxy::current());
+    context->SetTaskRunnerForTesting(base::ThreadTaskRunnerHandle::Get());
   }
 
   // Returns the testing browsing context that can be used for this test.
diff --git a/content/browser/permissions/permission_service_context.cc b/content/browser/permissions/permission_service_context.cc
index 4a26909..be035809 100644
--- a/content/browser/permissions/permission_service_context.cc
+++ b/content/browser/permissions/permission_service_context.cc
@@ -46,6 +46,12 @@
   CancelPendingOperations(render_frame_host);
 }
 
+void PermissionServiceContext::RenderFrameHostChanged(
+    RenderFrameHost* old_host,
+    RenderFrameHost* new_host) {
+  CancelPendingOperations(old_host);
+}
+
 void PermissionServiceContext::DidNavigateAnyFrame(
     RenderFrameHost* render_frame_host,
     const LoadCommittedDetails& details,
@@ -58,6 +64,7 @@
 
 void PermissionServiceContext::CancelPendingOperations(
     RenderFrameHost* render_frame_host) const {
+  DCHECK(render_frame_host_);
   if (render_frame_host != render_frame_host_)
     return;
 
diff --git a/content/browser/permissions/permission_service_context.h b/content/browser/permissions/permission_service_context.h
index f133a52..e07366d 100644
--- a/content/browser/permissions/permission_service_context.h
+++ b/content/browser/permissions/permission_service_context.h
@@ -41,6 +41,8 @@
  private:
   // WebContentsObserver
   void RenderFrameDeleted(RenderFrameHost* render_frame_host) override;
+  void RenderFrameHostChanged(RenderFrameHost* old_host,
+                              RenderFrameHost* new_host) override;
   void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
                            const LoadCommittedDetails& details,
                            const FrameNavigateParams& params) override;
diff --git a/content/browser/plugin_loader_posix.cc b/content/browser/plugin_loader_posix.cc
index b8750ed9..bfc9032 100644
--- a/content/browser/plugin_loader_posix.cc
+++ b/content/browser/plugin_loader_posix.cc
@@ -5,9 +5,10 @@
 #include "content/browser/plugin_loader_posix.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/utility_process_host_impl.h"
 #include "content/common/child_process_host_impl.h"
 #include "content/common/plugin_list.h"
@@ -29,8 +30,8 @@
   std::vector<WebPluginInfo> cached_plugins;
   if (PluginList::Singleton()->GetPluginsNoRefresh(&cached_plugins)) {
     // Can't assume the caller is reentrant.
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-        base::Bind(callback, cached_plugins));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(callback, cached_plugins));
     return;
   }
 
@@ -226,7 +227,7 @@
   PluginList::Singleton()->SetPlugins(loaded_plugins_);
 
   for (auto& callback : callbacks_) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, loaded_plugins_));
   }
   callbacks_.clear();
diff --git a/content/browser/plugin_loader_posix.h b/content/browser/plugin_loader_posix.h
index 3a50bcd..2db1634 100644
--- a/content/browser/plugin_loader_posix.h
+++ b/content/browser/plugin_loader_posix.h
@@ -16,10 +16,6 @@
 #include "content/public/common/webplugininfo.h"
 #include "ipc/ipc_sender.h"
 
-namespace base {
-class MessageLoopProxy;
-}
-
 namespace content {
 class UtilityProcessHost;
 
diff --git a/content/browser/plugin_service_impl.cc b/content/browser/plugin_service_impl.cc
index ed7f64c..678171c7 100644
--- a/content/browser/plugin_service_impl.cc
+++ b/content/browser/plugin_service_impl.cc
@@ -8,9 +8,9 @@
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
@@ -125,10 +125,10 @@
 }
 #endif
 
-void ForwardCallback(base::MessageLoopProxy* target_loop,
+void ForwardCallback(base::SingleThreadTaskRunner* target_task_runner,
                      const PluginService::GetPluginsCallback& callback,
                      const std::vector<WebPluginInfo>& plugins) {
-  target_loop->PostTask(FROM_HERE, base::Bind(callback, plugins));
+  target_task_runner->PostTask(FROM_HERE, base::Bind(callback, plugins));
 }
 
 }  // namespace
@@ -589,45 +589,43 @@
 }
 
 void PluginServiceImpl::GetPlugins(const GetPluginsCallback& callback) {
-  scoped_refptr<base::MessageLoopProxy> target_loop(
-      base::MessageLoop::current()->message_loop_proxy());
+  scoped_refptr<base::SingleThreadTaskRunner> target_task_runner(
+      base::ThreadTaskRunnerHandle::Get());
 
   if (LoadPluginListInProcess()) {
-    BrowserThread::GetBlockingPool()->
-        PostSequencedWorkerTaskWithShutdownBehavior(
-            plugin_list_token_,
-            FROM_HERE,
+    BrowserThread::GetBlockingPool()
+        ->PostSequencedWorkerTaskWithShutdownBehavior(
+            plugin_list_token_, FROM_HERE,
             base::Bind(&PluginServiceImpl::GetPluginsInternal,
-                       base::Unretained(this),
-                       target_loop, callback),
-        base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+                       base::Unretained(this), target_task_runner, callback),
+            base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
     return;
   }
 #if defined(OS_POSIX)
-  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
       base::Bind(&PluginServiceImpl::GetPluginsOnIOThread,
-                 base::Unretained(this), target_loop, callback));
+                 base::Unretained(this), target_task_runner, callback));
 #else
   NOTREACHED();
 #endif
 }
 
 void PluginServiceImpl::GetPluginsInternal(
-     base::MessageLoopProxy* target_loop,
-     const PluginService::GetPluginsCallback& callback) {
+    base::SingleThreadTaskRunner* target_task_runner,
+    const PluginService::GetPluginsCallback& callback) {
   DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread(
       plugin_list_token_));
 
   std::vector<WebPluginInfo> plugins;
   PluginList::Singleton()->GetPlugins(&plugins, NPAPIPluginsSupported());
 
-  target_loop->PostTask(FROM_HERE,
-      base::Bind(callback, plugins));
+  target_task_runner->PostTask(FROM_HERE, base::Bind(callback, plugins));
 }
 
 #if defined(OS_POSIX)
 void PluginServiceImpl::GetPluginsOnIOThread(
-    base::MessageLoopProxy* target_loop,
+    base::SingleThreadTaskRunner* target_task_runner,
     const GetPluginsCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
@@ -637,8 +635,8 @@
   if (!plugin_loader_.get())
     plugin_loader_ = new PluginLoaderPosix;
 
-  plugin_loader_->GetPlugins(
-      base::Bind(&ForwardCallback, make_scoped_refptr(target_loop), callback));
+  plugin_loader_->GetPlugins(base::Bind(
+      &ForwardCallback, make_scoped_refptr(target_task_runner), callback));
 }
 #endif
 
diff --git a/content/browser/plugin_service_impl.h b/content/browser/plugin_service_impl.h
index 2e107a6d..19fefba6 100644
--- a/content/browser/plugin_service_impl.h
+++ b/content/browser/plugin_service_impl.h
@@ -42,7 +42,7 @@
 #endif
 
 namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
 }
 
 namespace content {
@@ -181,13 +181,12 @@
   void RegisterPepperPlugins();
 
   // Run on the blocking pool to load the plugins synchronously.
-  void GetPluginsInternal(base::MessageLoopProxy* target_loop,
+  void GetPluginsInternal(base::SingleThreadTaskRunner* target_task_runner,
                           const GetPluginsCallback& callback);
 
 #if defined(OS_POSIX)
-  void GetPluginsOnIOThread(
-      base::MessageLoopProxy* target_loop,
-      const GetPluginsCallback& callback);
+  void GetPluginsOnIOThread(base::SingleThreadTaskRunner* target_task_runner,
+                            const GetPluginsCallback& callback);
 #endif
 
   // Binding directly to GetAllowedPluginForOpenChannelToPlugin() isn't possible
diff --git a/content/browser/plugin_service_impl_browsertest.cc b/content/browser/plugin_service_impl_browsertest.cc
index e60516e6..9c1e9f1 100644
--- a/content/browser/plugin_service_impl_browsertest.cc
+++ b/content/browser/plugin_service_impl_browsertest.cc
@@ -7,7 +7,10 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/path_service.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/plugin_service_filter.h"
 #include "content/public/browser/resource_context.h"
@@ -261,12 +264,10 @@
     set_host(host);
     // This gets called right before we request the plugin<=>renderer channel,
     // so we have to post a task to cancel it.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&PluginProcessHost::CancelPendingRequest,
-                   base::Unretained(host),
-                   this));
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&PluginProcessHost::CancelPendingRequest,
+                              base::Unretained(host), this));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(&QuitUIMessageLoopFromIOThread));
   }
 
diff --git a/content/browser/power_profiler/power_profiler_service_unittest.cc b/content/browser/power_profiler/power_profiler_service_unittest.cc
index 3386b6f..96e96d1 100644
--- a/content/browser/power_profiler/power_profiler_service_unittest.cc
+++ b/content/browser/power_profiler/power_profiler_service_unittest.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/power_profiler/power_profiler_service.h"
@@ -90,8 +89,7 @@
     service_.reset(new PowerProfilerService(
         make_scoped_ptr<PowerDataProvider>(
             new TestPowerDataProvider(kNumEvents)),
-        message_loop_.message_loop_proxy(),
-        base::TimeDelta::FromMilliseconds(1)));
+        message_loop_.task_runner(), base::TimeDelta::FromMilliseconds(1)));
     EXPECT_TRUE(service_->IsAvailable());
   }
 
diff --git a/content/browser/power_save_blocker_x11.cc b/content/browser/power_save_blocker_x11.cc
index bc20e02..4ffe2e6b 100644
--- a/content/browser/power_save_blocker_x11.cc
+++ b/content/browser/power_save_blocker_x11.cc
@@ -21,7 +21,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/nix/xdg_util.h"
 #include "base/synchronization/lock.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/content/browser/presentation/presentation_service_impl_unittest.cc b/content/browser/presentation/presentation_service_impl_unittest.cc
index 677418f..81a2dba 100644
--- a/content/browser/presentation/presentation_service_impl_unittest.cc
+++ b/content/browser/presentation/presentation_service_impl_unittest.cc
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/presentation/presentation_service_impl.h"
 #include "content/public/browser/presentation_service_delegate.h"
 #include "content/public/browser/presentation_session.h"
@@ -174,7 +176,7 @@
 
   void RunLoopFor(base::TimeDelta duration) {
     base::RunLoop run_loop;
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, run_loop.QuitClosure(), duration);
     run_loop.Run();
   }
diff --git a/content/browser/quota/mock_quota_manager.cc b/content/browser/quota/mock_quota_manager.cc
index 4884d0d7..47bc304 100644
--- a/content/browser/quota/mock_quota_manager.cc
+++ b/content/browser/quota/mock_quota_manager.cc
@@ -4,10 +4,11 @@
 
 #include "content/browser/quota/mock_quota_manager.h"
 
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "url/gurl.h"
 
 using storage::kQuotaStatusOk;
@@ -93,13 +94,10 @@
       origins_to_return->insert(current->origin);
   }
 
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&MockQuotaManager::DidGetModifiedSince,
-                 weak_factory_.GetWeakPtr(),
-                 callback,
-                 base::Owned(origins_to_return),
-                 type));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&MockQuotaManager::DidGetModifiedSince,
+                            weak_factory_.GetWeakPtr(), callback,
+                            base::Owned(origins_to_return), type));
 }
 
 void MockQuotaManager::DeleteOriginData(
@@ -119,12 +117,10 @@
     }
   }
 
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&MockQuotaManager::DidDeleteOriginData,
-                 weak_factory_.GetWeakPtr(),
-                 callback,
-                 kQuotaStatusOk));
+                 weak_factory_.GetWeakPtr(), callback, kQuotaStatusOk));
 }
 
 MockQuotaManager::~MockQuotaManager() {}
diff --git a/content/browser/quota/mock_quota_manager_unittest.cc b/content/browser/quota/mock_quota_manager_unittest.cc
index 706ca821..e5e170cb 100644
--- a/content/browser/quota/mock_quota_manager_unittest.cc
+++ b/content/browser/quota/mock_quota_manager_unittest.cc
@@ -8,8 +8,8 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/quota/mock_quota_manager.h"
 #include "content/public/test/mock_special_storage_policy.h"
 #include "content/public/test/mock_storage_client.h"
@@ -45,10 +45,9 @@
   void SetUp() override {
     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
     policy_ = new MockSpecialStoragePolicy;
-    manager_ = new MockQuotaManager(false /* is_incognito */,
-                                    data_dir_.path(),
-                                    base::MessageLoopProxy::current().get(),
-                                    base::MessageLoopProxy::current().get(),
+    manager_ = new MockQuotaManager(false /* is_incognito */, data_dir_.path(),
+                                    base::ThreadTaskRunnerHandle::Get().get(),
+                                    base::ThreadTaskRunnerHandle::Get().get(),
                                     policy_.get());
   }
 
diff --git a/content/browser/quota/quota_backend_impl_unittest.cc b/content/browser/quota/quota_backend_impl_unittest.cc
index 2cf9f17..6139e8a 100644
--- a/content/browser/quota/quota_backend_impl_unittest.cc
+++ b/content/browser/quota/quota_backend_impl_unittest.cc
@@ -7,7 +7,7 @@
 #include <string>
 
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "storage/browser/fileapi/file_system_usage_cache.h"
 #include "storage/browser/fileapi/obfuscated_file_util.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
@@ -129,7 +129,7 @@
   }
 
   base::SequencedTaskRunner* file_task_runner() {
-    return base::MessageLoopProxy::current().get();
+    return base::ThreadTaskRunnerHandle::Get().get();
   }
 
   base::FilePath GetUsageCachePath(const GURL& origin,
diff --git a/content/browser/quota/quota_manager_unittest.cc b/content/browser/quota/quota_manager_unittest.cc
index 1337bc3..39c2315 100644
--- a/content/browser/quota/quota_manager_unittest.cc
+++ b/content/browser/quota/quota_manager_unittest.cc
@@ -12,10 +12,10 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "base/sys_info.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "content/public/test/mock_special_storage_policy.h"
 #include "content/public/test/mock_storage_client.h"
@@ -25,7 +25,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
-using base::MessageLoopProxy;
 using storage::kQuotaErrorAbort;
 using storage::kQuotaErrorInvalidModification;
 using storage::kQuotaErrorNotSupported;
@@ -92,10 +91,9 @@
 
  protected:
   void ResetQuotaManager(bool is_incognito) {
-    quota_manager_ = new QuotaManager(is_incognito,
-                                      data_dir_.path(),
-                                      MessageLoopProxy::current().get(),
-                                      MessageLoopProxy::current().get(),
+    quota_manager_ = new QuotaManager(is_incognito, data_dir_.path(),
+                                      base::ThreadTaskRunnerHandle::Get().get(),
+                                      base::ThreadTaskRunnerHandle::Get().get(),
                                       mock_special_storage_policy_.get());
     // Don't (automatically) start the eviction for testing.
     quota_manager_->eviction_disabled_ = true;
diff --git a/content/browser/quota/quota_reservation_manager_unittest.cc b/content/browser/quota/quota_reservation_manager_unittest.cc
index 61de3d5..05fff80b 100644
--- a/content/browser/quota/quota_reservation_manager_unittest.cc
+++ b/content/browser/quota/quota_reservation_manager_unittest.cc
@@ -9,8 +9,10 @@
 #include "base/files/file.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "storage/browser/fileapi/quota/open_file_handle.h"
 #include "storage/browser/fileapi/quota/quota_reservation.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -56,7 +58,7 @@
     EXPECT_EQ(GURL(kOrigin), origin);
     EXPECT_EQ(kType, type);
     on_memory_usage_ += delta;
-    base::MessageLoopProxy::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(base::IgnoreResult(callback), base::File::FILE_OK, delta));
   }
diff --git a/content/browser/quota/quota_temporary_storage_evictor_unittest.cc b/content/browser/quota/quota_temporary_storage_evictor_unittest.cc
index 6c00c0f..ba414fc 100644
--- a/content/browser/quota/quota_temporary_storage_evictor_unittest.cc
+++ b/content/browser/quota/quota_temporary_storage_evictor_unittest.cc
@@ -10,7 +10,6 @@
 #include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
 #include "content/public/test/mock_storage_client.h"
 #include "storage/browser/quota/quota_manager.h"
diff --git a/content/browser/quota/storage_monitor_unittest.cc b/content/browser/quota/storage_monitor_unittest.cc
index 78599de7..0edd49eb 100644
--- a/content/browser/quota/storage_monitor_unittest.cc
+++ b/content/browser/quota/storage_monitor_unittest.cc
@@ -5,9 +5,8 @@
 #include <vector>
 
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/test/mock_special_storage_policy.h"
 #include "content/public/test/mock_storage_client.h"
 #include "net/base/net_util.h"
@@ -63,17 +62,15 @@
 class UsageMockQuotaManager : public QuotaManager {
  public:
   UsageMockQuotaManager(SpecialStoragePolicy* special_storage_policy)
-      : QuotaManager(
-            false,
-            base::FilePath(),
-            base::MessageLoopProxy::current().get(),
-            base::MessageLoopProxy::current().get(),
-            special_storage_policy),
+      : QuotaManager(false,
+                     base::FilePath(),
+                     base::ThreadTaskRunnerHandle::Get().get(),
+                     base::ThreadTaskRunnerHandle::Get().get(),
+                     special_storage_policy),
         callback_usage_(0),
         callback_quota_(0),
         callback_status_(kQuotaStatusOk),
-        initialized_(false) {
-  }
+        initialized_(false) {}
 
   void SetCallbackParams(int64 usage, int64 quota, QuotaStatusCode status) {
     initialized_ = true;
@@ -649,11 +646,8 @@
     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
     storage_policy_ = new MockSpecialStoragePolicy();
     quota_manager_ = new QuotaManager(
-        false,
-        data_dir_.path(),
-        base::MessageLoopProxy::current().get(),
-        base::MessageLoopProxy::current().get(),
-        storage_policy_.get());
+        false, data_dir_.path(), base::ThreadTaskRunnerHandle::Get().get(),
+        base::ThreadTaskRunnerHandle::Get().get(), storage_policy_.get());
 
     client_ = new MockStorageClient(quota_manager_->proxy(),
                                     NULL,
diff --git a/content/browser/quota/usage_tracker_unittest.cc b/content/browser/quota/usage_tracker_unittest.cc
index 786146a..3cfdf2cb 100644
--- a/content/browser/quota/usage_tracker_unittest.cc
+++ b/content/browser/quota/usage_tracker_unittest.cc
@@ -3,7 +3,10 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/test/mock_special_storage_policy.h"
 #include "net/base/net_util.h"
 #include "storage/browser/quota/usage_tracker.h"
@@ -56,8 +59,8 @@
                       const GetUsageCallback& callback) override {
     EXPECT_EQ(kStorageTypeTemporary, type);
     int64 usage = GetUsage(origin);
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::Bind(callback, usage));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(callback, usage));
   }
 
   void GetOriginsForType(StorageType type,
@@ -68,8 +71,8 @@
          itr != usage_map_.end(); ++itr) {
       origins.insert(itr->first);
     }
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::Bind(callback, origins));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(callback, origins));
   }
 
   void GetOriginsForHost(StorageType type,
@@ -82,8 +85,8 @@
       if (net::GetHostOrSpecFromURL(itr->first) == host)
         origins.insert(itr->first);
     }
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::Bind(callback, origins));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(callback, origins));
   }
 
   void DeleteOriginData(const GURL& origin,
@@ -91,7 +94,7 @@
                         const DeletionCallback& callback) override {
     EXPECT_EQ(kStorageTypeTemporary, type);
     usage_map_.erase(origin);
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, kQuotaStatusOk));
   }
 
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index ce153f53..4a12052 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -82,7 +82,7 @@
     capabilities_.adjust_deadline_for_parent = false;
     capabilities_.max_frames_pending = 2;
     compositor_impl_ = compositor_impl;
-    main_thread_ = base::MessageLoopProxy::current();
+    main_thread_ = base::ThreadTaskRunnerHandle::Get();
   }
 
   void SwapBuffers(cc::CompositorFrame* frame) override {
@@ -130,7 +130,7 @@
                                 gfx::SwapResult)>
       swap_buffers_completion_callback_;
 
-  scoped_refptr<base::MessageLoopProxy> main_thread_;
+  scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
   base::WeakPtr<CompositorImpl> compositor_impl_;
 };
 
@@ -307,7 +307,7 @@
   // Unretained because we cancel the task on shutdown.
   current_composite_task_.reset(new base::CancelableClosure(
       base::Bind(&CompositorImpl::Composite, base::Unretained(this), trigger)));
-  base::MessageLoop::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, current_composite_task_->callback(), delay);
 }
 
@@ -657,7 +657,7 @@
         real_output_surface.Pass(), manager, HostSharedBitmapManager::current(),
         BrowserGpuMemoryBufferManager::current(),
         host_->settings().renderer_settings,
-        base::MessageLoopProxy::current()));
+        base::ThreadTaskRunnerHandle::Get()));
     scoped_ptr<cc::SurfaceDisplayOutputSurface> surface_output_surface(
         new cc::SurfaceDisplayOutputSurface(
             manager, surface_id_allocator_.get(), context_provider));
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index 4bba37cb..9cd45df 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -85,6 +85,10 @@
   void DidCommitAndDrawFrame() override {}
   void DidCompleteSwapBuffers() override;
   void DidCompletePageScaleAnimation() override {}
+  void RecordFrameTimingEvents(
+      scoped_ptr<cc::FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<cc::FrameTimingTracker::MainFrameTimingSet> main_frame_events)
+      override {}
 
   // LayerTreeHostSingleThreadClient implementation.
   void ScheduleComposite() override;
diff --git a/content/browser/renderer_host/input/gesture_event_queue_unittest.cc b/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
index 3e57cd035..7e7a6ea 100644
--- a/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
+++ b/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
@@ -5,9 +5,12 @@
 #include <vector>
 
 #include "base/basictypes.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "content/browser/renderer_host/input/gesture_event_queue.h"
 #include "content/browser/renderer_host/input/touchpad_tap_suppression_controller.h"
@@ -1083,9 +1086,8 @@
   EXPECT_EQ(2U, GestureEventQueueSize());
   EXPECT_EQ(3U, GestureEventDebouncingQueueSize());
 
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
       TimeDelta::FromMilliseconds(5));
   base::MessageLoop::current()->Run();
 
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc
index 918c260..4f2e6bb 100644
--- a/content/browser/renderer_host/input/input_router_impl_unittest.cc
+++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -6,8 +6,11 @@
 
 #include "base/basictypes.h"
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/renderer_host/input/gesture_event_queue.h"
 #include "content/browser/renderer_host/input/input_router_client.h"
 #include "content/browser/renderer_host/input/input_router_impl.h"
@@ -326,7 +329,7 @@
   }
 
   static void RunTasksAndWait(base::TimeDelta delay) {
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, base::MessageLoop::QuitClosure(), delay);
     base::MessageLoop::current()->Run();
   }
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_android.cc b/content/browser/renderer_host/input/synthetic_gesture_target_android.cc
index a1e5dea6..836da7d 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_target_android.cc
+++ b/content/browser/renderer_host/input/synthetic_gesture_target_android.cc
@@ -6,7 +6,7 @@
 
 #include "content/browser/android/content_view_core_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
-#include "jni/TouchEventSynthesizer_jni.h"
+#include "jni/MotionEventSynthesizer_jni.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "ui/gfx/android/view_configuration.h"
 #include "ui/gfx/screen.h"
@@ -26,21 +26,29 @@
 SyntheticGestureTargetAndroid::~SyntheticGestureTargetAndroid() {
 }
 
-bool SyntheticGestureTargetAndroid::RegisterTouchEventSynthesizer(JNIEnv* env) {
+bool SyntheticGestureTargetAndroid::RegisterMotionEventSynthesizer(
+    JNIEnv* env) {
   return RegisterNativesImpl(env);
 }
 
 void SyntheticGestureTargetAndroid::TouchSetPointer(
     JNIEnv* env, int index, int x, int y, int id) {
   TRACE_EVENT0("input", "SyntheticGestureTargetAndroid::TouchSetPointer");
-  Java_TouchEventSynthesizer_setPointer(env, touch_event_synthesizer_.obj(),
+  Java_MotionEventSynthesizer_setPointer(env, touch_event_synthesizer_.obj(),
                                       index, x, y, id);
 }
 
+void SyntheticGestureTargetAndroid::TouchSetScrollDeltas(
+    JNIEnv* env, int x, int y, int dx, int dy) {
+  TRACE_EVENT0("input", "SyntheticGestureTargetAndroid::TouchSetPointer");
+  Java_MotionEventSynthesizer_setScrollDeltas(
+      env, touch_event_synthesizer_.obj(), x, y, dx, dy);
+}
+
 void SyntheticGestureTargetAndroid::TouchInject(
     JNIEnv* env, Action action, int pointer_count, int64 time_in_ms) {
   TRACE_EVENT0("input", "SyntheticGestureTargetAndroid::TouchInject");
-  Java_TouchEventSynthesizer_inject(env, touch_event_synthesizer_.obj(),
+  Java_MotionEventSynthesizer_inject(env, touch_event_synthesizer_.obj(),
                                     static_cast<int>(action), pointer_count,
                                     time_in_ms);
 }
@@ -79,7 +87,13 @@
 
 void SyntheticGestureTargetAndroid::DispatchWebMouseWheelEventToPlatform(
     const blink::WebMouseWheelEvent& web_wheel, const ui::LatencyInfo&) {
-  CHECK(false);
+  JNIEnv* env = base::android::AttachCurrentThread();
+  TouchSetScrollDeltas(env, web_wheel.x, web_wheel.y, web_wheel.deltaX,
+                       web_wheel.deltaY);
+  Java_MotionEventSynthesizer_inject(
+      env, touch_event_synthesizer_.obj(),
+      static_cast<int>(SyntheticGestureTargetAndroid::ActionScroll),
+      1, static_cast<int64>(web_wheel.timeStampSeconds * 1000.0));
 }
 
 void SyntheticGestureTargetAndroid::DispatchWebMouseEventToPlatform(
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_android.h b/content/browser/renderer_host/input/synthetic_gesture_target_android.h
index afd124e5..aa1236d 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_target_android.h
+++ b/content/browser/renderer_host/input/synthetic_gesture_target_android.h
@@ -20,7 +20,7 @@
       base::android::ScopedJavaLocalRef<jobject> touch_event_synthesizer);
   ~SyntheticGestureTargetAndroid() override;
 
-  static bool RegisterTouchEventSynthesizer(JNIEnv* env);
+  static bool RegisterMotionEventSynthesizer(JNIEnv* env);
 
   // SyntheticGestureTargetBase:
   void DispatchWebTouchEventToPlatform(
@@ -42,18 +42,22 @@
   float GetMinScalingSpanInDips() const override;
 
  private:
-  // Enum values below need to be kept in sync with TouchEventSynthesizer.java
+  // Enum values below need to be kept in sync with MotionEventSynthesizer.java.
   enum Action {
     ActionInvalid = -1,
     ActionStart = 0,
     ActionMove = 1,
     ActionCancel = 2,
-    ActionEnd = 3
+    ActionEnd = 3,
+    ActionScroll = 4
   };
 
   void TouchSetPointer(JNIEnv* env, int index, int x, int y, int id);
-  void TouchInject(
-      JNIEnv* env, Action action, int pointer_count, int64 time_in_ms);
+  void TouchSetScrollDeltas(JNIEnv* env, int x, int y, int dx, int dy);
+  void TouchInject(JNIEnv* env,
+                   Action action,
+                   int pointer_count,
+                   int64 time_in_ms);
 
   base::android::ScopedJavaGlobalRef<jobject> touch_event_synthesizer_;
 
diff --git a/content/browser/renderer_host/input/touch_event_queue_unittest.cc b/content/browser/renderer_host/input/touch_event_queue_unittest.cc
index 2467cde..f46fe50 100644
--- a/content/browser/renderer_host/input/touch_event_queue_unittest.cc
+++ b/content/browser/renderer_host/input/touch_event_queue_unittest.cc
@@ -3,9 +3,12 @@
 // found in the LICENSE file.
 
 #include "base/basictypes.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/renderer_host/input/timeout_monitor.h"
 #include "content/browser/renderer_host/input/touch_event_queue.h"
 #include "content/common/input/synthetic_web_input_event_builders.h"
@@ -282,7 +285,7 @@
   }
 
   static void RunTasksAndWait(base::TimeDelta delay) {
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, base::MessageLoop::QuitClosure(), delay);
     base::MessageLoop::current()->Run();
   }
diff --git a/content/browser/renderer_host/input/touch_input_browsertest.cc b/content/browser/renderer_host/input/touch_input_browsertest.cc
index b6d5f991..9c9bcefd 100644
--- a/content/browser/renderer_host/input/touch_input_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_input_browsertest.cc
@@ -4,7 +4,10 @@
 
 #include "base/auto_reset.h"
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/gpu/compositor_util.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
@@ -27,10 +30,8 @@
 
 void GiveItSomeTime() {
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      run_loop.QuitClosure(),
-      base::TimeDelta::FromMilliseconds(10));
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromMilliseconds(10));
   run_loop.Run();
 }
 
diff --git a/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc b/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
index f6a5fb2..498806b 100644
--- a/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
+++ b/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
@@ -5,9 +5,10 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
@@ -71,7 +72,7 @@
     manager_->UseFakeDevice();
     audio_input_listener_.reset(new MockAudioInputDeviceManagerListener());
     manager_->Register(audio_input_listener_.get(),
-                       message_loop_->message_loop_proxy().get());
+                       message_loop_->task_runner().get());
 
     // Gets the enumerated device list from the AudioInputDeviceManager.
     manager_->EnumerateDevices(MEDIA_DEVICE_AUDIO_CAPTURE);
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
index 848f78c4..19fb35e 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
@@ -2,14 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <string>
 #include <queue>
+#include <string>
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
 #include "content/browser/renderer_host/media/media_stream_dispatcher_host.h"
@@ -55,10 +57,10 @@
  public:
   MockMediaStreamDispatcherHost(
       const ResourceContext::SaltCallback salt_callback,
-      const scoped_refptr<base::MessageLoopProxy>& message_loop,
+      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
       MediaStreamManager* manager)
       : MediaStreamDispatcherHost(kProcessId, salt_callback, manager),
-        message_loop_(message_loop),
+        task_runner_(task_runner),
         current_ipc_(NULL) {}
 
   // A list of mock methods.
@@ -155,7 +157,7 @@
     // Notify that the event have occurred.
     base::Closure quit_closure = quit_closures_.front();
     quit_closures_.pop();
-    message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
+    task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
 
     label_ = label;
     audio_devices_ = audio_device_list;
@@ -169,7 +171,7 @@
     if (!quit_closures_.empty()) {
       base::Closure quit_closure = quit_closures_.front();
       quit_closures_.pop();
-      message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
+      task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
     }
 
     label_= "";
@@ -190,7 +192,7 @@
                               const StreamDeviceInfo& device) {
     base::Closure quit_closure = quit_closures_.front();
     quit_closures_.pop();
-    message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
+    task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
     label_ = label;
     opened_device_ = device;
   }
@@ -199,11 +201,11 @@
                            const StreamDeviceInfoArray& devices) {
     base::Closure quit_closure = quit_closures_.front();
     quit_closures_.pop();
-    message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
+    task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
     enumerated_devices_ = devices;
   }
 
-  scoped_refptr<base::MessageLoopProxy> message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   IPC::Message* current_ipc_;
   std::queue<base::Closure> quit_closures_;
 };
@@ -223,7 +225,7 @@
         thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
         origin_("https://test.com") {
     audio_manager_.reset(
-        new media::MockAudioManager(base::MessageLoopProxy::current()));
+        new media::MockAudioManager(base::ThreadTaskRunnerHandle::Get()));
     // Make sure we use fake devices to avoid long delays.
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kUseFakeDeviceForMediaStream);
@@ -237,7 +239,7 @@
 #if defined(OS_WIN)
     // Override the Video Capture Thread that MediaStreamManager constructs.
     media_stream_manager_->video_capture_manager()->set_device_task_runner(
-        base::MessageLoopProxy::current());
+        base::ThreadTaskRunnerHandle::Get());
 #endif
 
     MockResourceContext* mock_resource_context =
@@ -246,8 +248,7 @@
 
     host_ = new MockMediaStreamDispatcherHost(
         mock_resource_context->GetMediaDeviceIDSalt(),
-        base::MessageLoopProxy::current(),
-        media_stream_manager_.get());
+        base::ThreadTaskRunnerHandle::Get(), media_stream_manager_.get());
 
     // Use the fake content client and browser.
     content_client_.reset(new TestContentClient());
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 1ae9fe5..9c7ac2b 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -1670,8 +1670,7 @@
   // buggy third party Direct Show modules, http://crbug.com/428958.
   video_capture_thread_.init_com_with_mta(false);
   CHECK(video_capture_thread_.Start());
-  video_capture_manager_->Register(this,
-                                   video_capture_thread_.message_loop_proxy());
+  video_capture_manager_->Register(this, video_capture_thread_.task_runner());
 #else
   video_capture_manager_->Register(this, device_task_runner_);
 #endif
diff --git a/content/browser/renderer_host/media/media_stream_manager_unittest.cc b/content/browser/renderer_host/media/media_stream_manager_unittest.cc
index 51ab0a5..fc0028c 100644
--- a/content/browser/renderer_host/media/media_stream_manager_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_manager_unittest.cc
@@ -6,8 +6,10 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
@@ -77,7 +79,7 @@
  public:
   MediaStreamManagerTest()
       : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
-        message_loop_(base::MessageLoopProxy::current()) {
+        task_runner_(base::ThreadTaskRunnerHandle::Get()) {
     // Create our own MediaStreamManager. Use fake devices to run on the bots.
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kUseFakeDeviceForMediaStream);
@@ -93,7 +95,7 @@
                         const MediaStreamDevices& devices,
                         scoped_ptr<MediaStreamUIProxy> ui_proxy) {
     Response(index);
-    message_loop_->PostTask(FROM_HERE, run_loop_.QuitClosure());
+    task_runner_->PostTask(FROM_HERE, run_loop_.QuitClosure());
   }
 
  protected:
@@ -117,7 +119,7 @@
   scoped_ptr<media::AudioManager> audio_manager_;
   scoped_ptr<MediaStreamManager> media_stream_manager_;
   content::TestBrowserThreadBundle thread_bundle_;
-  scoped_refptr<base::MessageLoopProxy> message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   base::RunLoop run_loop_;
 
  private:
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc
index fd098e7..bd7b05b 100644
--- a/content/browser/renderer_host/media/video_capture_controller.cc
+++ b/content/browser/renderer_host/media/video_capture_controller.cc
@@ -28,6 +28,7 @@
 
 using media::VideoCaptureFormat;
 using media::VideoFrame;
+using media::VideoFrameMetadata;
 
 namespace content {
 
@@ -234,7 +235,8 @@
     VideoCaptureControllerID id,
     VideoCaptureControllerEventHandler* event_handler,
     int buffer_id,
-    uint32 sync_point) {
+    uint32 sync_point,
+    double consumer_resource_utilization) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   ControllerClient* client = FindClient(id, event_handler, controller_clients_);
@@ -247,7 +249,27 @@
     NOTREACHED();
     return;
   }
+
+  // Set the RESOURCE_UTILIZATION to the maximum of those provided by each
+  // consumer (via separate calls to this method that refer to the same
+  // VideoFrame).  The producer of this VideoFrame may check this value, after
+  // all consumer holds are relinquished, to make quality versus performance
+  // trade-off decisions.
   scoped_refptr<VideoFrame> frame = iter->second;
+  if (std::isfinite(consumer_resource_utilization) &&
+      consumer_resource_utilization >= 0.0) {
+    double resource_utilization = -1.0;
+    if (frame->metadata()->GetDouble(VideoFrameMetadata::RESOURCE_UTILIZATION,
+                                     &resource_utilization)) {
+      frame->metadata()->SetDouble(VideoFrameMetadata::RESOURCE_UTILIZATION,
+                                   std::max(consumer_resource_utilization,
+                                            resource_utilization));
+    } else {
+      frame->metadata()->SetDouble(VideoFrameMetadata::RESOURCE_UTILIZATION,
+                                   consumer_resource_utilization);
+    }
+  }
+
   client->active_buffers.erase(iter);
   buffer_pool_->RelinquishConsumerHold(buffer_id, 1);
 
diff --git a/content/browser/renderer_host/media/video_capture_controller.h b/content/browser/renderer_host/media/video_capture_controller.h
index 0dd8684..ee5f6f3 100644
--- a/content/browser/renderer_host/media/video_capture_controller.h
+++ b/content/browser/renderer_host/media/video_capture_controller.h
@@ -108,11 +108,13 @@
   // VideoCaptureControllerEventHandler::OnBufferReady. In the case that the
   // buffer was backed by a texture, |sync_point| will be waited on before
   // destroying or recycling the texture, to synchronize with texture users in
-  // the renderer process.
+  // the renderer process. If the consumer provided resource utilization
+  // feedback, this will be passed here (-1.0 indicates no feedback).
   void ReturnBuffer(VideoCaptureControllerID id,
                     VideoCaptureControllerEventHandler* event_handler,
                     int buffer_id,
-                    uint32 sync_point);
+                    uint32 sync_point,
+                    double consumer_resource_utilization);
 
   const media::VideoCaptureFormat& GetVideoCaptureFormat() const;
 
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 70cef13..4dbec58 100644
--- a/content/browser/renderer_host/media/video_capture_controller_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
@@ -8,10 +8,11 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
 #include "content/browser/renderer_host/media/media_stream_provider.h"
 #include "content/browser/renderer_host/media/video_capture_controller.h"
@@ -22,6 +23,7 @@
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "gpu/command_buffer/common/mailbox_holder.h"
 #include "media/base/video_capture_types.h"
+#include "media/base/video_frame_metadata.h"
 #include "media/base/video_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -42,7 +44,8 @@
  public:
   explicit MockVideoCaptureControllerEventHandler(
       VideoCaptureController* controller)
-      : controller_(controller) {}
+      : controller_(controller),
+        resource_utilization_(-1.0) {}
   ~MockVideoCaptureControllerEventHandler() override {}
 
   // These mock methods are delegated to by our fake implementation of
@@ -73,14 +76,15 @@
       const base::TimeTicks& timestamp,
       scoped_ptr<base::DictionaryValue> metadata) override {
     DoBufferReady(id, coded_size);
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&VideoCaptureController::ReturnBuffer,
                    base::Unretained(controller_),
                    id,
                    this,
                    buffer_id,
-                   0));
+                   0,
+                   resource_utilization_));
   }
   void OnMailboxBufferReady(
       VideoCaptureControllerID id,
@@ -90,24 +94,27 @@
       const base::TimeTicks& timestamp,
       scoped_ptr<base::DictionaryValue> metadata) override {
     DoMailboxBufferReady(id);
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&VideoCaptureController::ReturnBuffer,
                    base::Unretained(controller_),
                    id,
                    this,
                    buffer_id,
-                   mailbox_holder.sync_point));
+                   mailbox_holder.sync_point,
+                   resource_utilization_));
   }
   void OnEnded(VideoCaptureControllerID id) override {
     DoEnded(id);
     // OnEnded() must respond by (eventually) unregistering the client.
-    base::MessageLoop::current()->PostTask(FROM_HERE,
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
         base::Bind(base::IgnoreResult(&VideoCaptureController::RemoveClient),
                    base::Unretained(controller_), id, this));
   }
 
   VideoCaptureController* controller_;
+  double resource_utilization_;
 };
 
 // Test class.
@@ -342,12 +349,23 @@
   }
   scoped_refptr<media::VideoFrame> video_frame =
       WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer->data()));
+  ASSERT_FALSE(video_frame->metadata()->HasKey(
+      media::VideoFrameMetadata::RESOURCE_UTILIZATION));
+  client_a_->resource_utilization_ = 0.5;
+  client_b_->resource_utilization_ = -1.0;
   device_->OnIncomingCapturedVideoFrame(buffer.Pass(), video_frame,
                                         base::TimeTicks());
 
   base::RunLoop().RunUntilIdle();
   Mock::VerifyAndClearExpectations(client_a_.get());
   Mock::VerifyAndClearExpectations(client_b_.get());
+  // Expect VideoCaptureController set the metadata in |video_frame| to hold a
+  // resource utilization of 0.5 (the largest of all reported values).
+  double resource_utilization_in_metadata = -1.0;
+  ASSERT_TRUE(video_frame->metadata()->GetDouble(
+      media::VideoFrameMetadata::RESOURCE_UTILIZATION,
+      &resource_utilization_in_metadata));
+  ASSERT_EQ(0.5, resource_utilization_in_metadata);
 
   // Second buffer which ought to use the same shared memory buffer. In this
   // case pretend that the Buffer pointer is held by the device for a long
@@ -359,6 +377,10 @@
   memset(buffer2->data(), buffer_no++, buffer2->size());
   video_frame =
       WrapI420Buffer(capture_resolution, static_cast<uint8*>(buffer2->data()));
+  ASSERT_FALSE(video_frame->metadata()->HasKey(
+      media::VideoFrameMetadata::RESOURCE_UTILIZATION));
+  client_a_->resource_utilization_ = 0.5;
+  client_b_->resource_utilization_ = 3.14;
   device_->OnIncomingCapturedVideoFrame(buffer2.Pass(), video_frame,
                                         base::TimeTicks());
 
@@ -369,6 +391,13 @@
   base::RunLoop().RunUntilIdle();
   Mock::VerifyAndClearExpectations(client_a_.get());
   Mock::VerifyAndClearExpectations(client_b_.get());
+  // Expect VideoCaptureController set the metadata in |video_frame| to hold a
+  // resource utilization of 3.14 (the largest of all reported values).
+  resource_utilization_in_metadata = -1.0;
+  ASSERT_TRUE(video_frame->metadata()->GetDouble(
+      media::VideoFrameMetadata::RESOURCE_UTILIZATION,
+      &resource_utilization_in_metadata));
+  ASSERT_EQ(3.14, resource_utilization_in_metadata);
 
   // Add a fourth client now that some buffers have come through.
   controller_->AddClient(client_b_route_2,
diff --git a/content/browser/renderer_host/media/video_capture_host.cc b/content/browser/renderer_host/media/video_capture_host.cc
index a546bbd..b44e132 100644
--- a/content/browser/renderer_host/media/video_capture_host.cc
+++ b/content/browser/renderer_host/media/video_capture_host.cc
@@ -159,7 +159,8 @@
     IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Pause, OnPauseCapture)
     IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Resume, OnResumeCapture)
     IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Stop, OnStopCapture)
-    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_BufferReady, OnReceiveEmptyBuffer)
+    IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_BufferReady,
+                        OnRendererFinishedWithBuffer)
     IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_GetDeviceSupportedFormats,
                         OnGetDeviceSupportedFormats)
     IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_GetDeviceFormatsInUse,
@@ -272,17 +273,24 @@
   }
 }
 
-void VideoCaptureHost::OnReceiveEmptyBuffer(int device_id,
-                                            int buffer_id,
-                                            uint32 sync_point) {
+void VideoCaptureHost::OnRendererFinishedWithBuffer(
+    int device_id,
+    int buffer_id,
+    uint32 sync_point,
+    double consumer_resource_utilization) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   VideoCaptureControllerID controller_id(device_id);
   EntryMap::iterator it = entries_.find(controller_id);
   if (it != entries_.end()) {
     const base::WeakPtr<VideoCaptureController>& controller = it->second;
-    if (controller)
-      controller->ReturnBuffer(controller_id, this, buffer_id, sync_point);
+    if (controller) {
+      controller->ReturnBuffer(controller_id,
+                               this,
+                               buffer_id,
+                               sync_point,
+                               consumer_resource_utilization);
+    }
   }
 }
 
diff --git a/content/browser/renderer_host/media/video_capture_host.h b/content/browser/renderer_host/media/video_capture_host.h
index eb845dc..52d7792 100644
--- a/content/browser/renderer_host/media/video_capture_host.h
+++ b/content/browser/renderer_host/media/video_capture_host.h
@@ -131,9 +131,12 @@
                        media::VideoCaptureSessionId session_id,
                        const media::VideoCaptureParams& params);
 
-  // IPC message: Receive an empty buffer from renderer. Send it to device
-  // referenced by |device_id|.
-  void OnReceiveEmptyBuffer(int device_id, int buffer_id, uint32 sync_point);
+  // IPC message: Called when a renderer is finished using a buffer. Notifies
+  // the controller.
+  void OnRendererFinishedWithBuffer(int device_id,
+                                    int buffer_id,
+                                    uint32 sync_point,
+                                    double consumer_resource_utilization);
 
   // IPC message: Get supported formats referenced by |capture_session_id|.
   // |device_id| is needed for message back-routing purposes.
diff --git a/content/browser/renderer_host/media/video_capture_host_unittest.cc b/content/browser/renderer_host/media/video_capture_host_unittest.cc
index 763ed1f..45629e9 100644
--- a/content/browser/renderer_host/media/video_capture_host_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_host_unittest.cc
@@ -9,11 +9,13 @@
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_file.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/browser/renderer_host/media/media_stream_requester.h"
@@ -163,7 +165,7 @@
   void ReturnReceivedDibs(int device_id)  {
     int handle = GetReceivedDib();
     while (handle) {
-      this->OnReceiveEmptyBuffer(device_id, handle, 0);
+      this->OnRendererFinishedWithBuffer(device_id, handle, 0, -1.0);
       handle = GetReceivedDib();
     }
   }
@@ -245,8 +247,8 @@
     OnBufferFilled(params.device_id, params.buffer_id, params.coded_size,
                    params.visible_rect, params.timestamp, params.metadata);
     if (return_buffers_) {
-      VideoCaptureHost::OnReceiveEmptyBuffer(
-          params.device_id, params.buffer_id, 0);
+      VideoCaptureHost::OnRendererFinishedWithBuffer(
+          params.device_id, params.buffer_id, 0, -1.0);
     }
   }
 
@@ -256,8 +258,8 @@
                           params.mailbox_holder, params.packed_frame_size,
                           params.timestamp, params.metadata);
     if (return_buffers_) {
-      VideoCaptureHost::OnReceiveEmptyBuffer(
-          params.device_id, params.buffer_id, 0);
+      VideoCaptureHost::OnRendererFinishedWithBuffer(
+          params.device_id, params.buffer_id, 0, -1.0);
     }
   }
 
@@ -272,8 +274,8 @@
   DumpVideo dumper_;
 };
 
-ACTION_P2(ExitMessageLoop, message_loop, quit_closure) {
-  message_loop->PostTask(FROM_HERE, quit_closure);
+ACTION_P2(ExitMessageLoop, task_runner, quit_closure) {
+  task_runner->PostTask(FROM_HERE, quit_closure);
 }
 
 // This is an integration test of VideoCaptureHost in conjunction with
@@ -283,7 +285,7 @@
  public:
   VideoCaptureHostTest()
       : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
-        message_loop_(base::MessageLoopProxy::current()),
+        task_runner_(base::ThreadTaskRunnerHandle::Get()),
         opened_session_id_(kInvalidMediaCaptureSessionId) {}
 
   void SetUp() override {
@@ -349,13 +351,11 @@
           page_request_id,
           MEDIA_DEVICE_VIDEO_CAPTURE,
           security_origin);
-      EXPECT_CALL(stream_requester_, DevicesEnumerated(render_frame_id,
-                                                       page_request_id,
-                                                       label,
-                                                       _))
-          .Times(1).WillOnce(
-              DoAll(ExitMessageLoop(message_loop_, run_loop.QuitClosure()),
-                    SaveArg<3>(&devices)));
+      EXPECT_CALL(stream_requester_,
+                  DevicesEnumerated(render_frame_id, page_request_id, label, _))
+          .Times(1)
+          .WillOnce(DoAll(ExitMessageLoop(task_runner_, run_loop.QuitClosure()),
+                          SaveArg<3>(&devices)));
       run_loop.Run();
       Mock::VerifyAndClearExpectations(&stream_requester_);
       media_stream_manager_->CancelRequest(label);
@@ -376,14 +376,12 @@
           devices[0].device.id,
           MEDIA_DEVICE_VIDEO_CAPTURE,
           security_origin);
-      EXPECT_CALL(stream_requester_, DeviceOpened(render_frame_id,
-                                                  page_request_id,
-                                                  _,
-                                                  _))
-          .Times(1).WillOnce(
-              DoAll(ExitMessageLoop(message_loop_, run_loop.QuitClosure()),
-                    SaveArg<2>(&opened_device_label_),
-                    SaveArg<3>(&opened_device)));
+      EXPECT_CALL(stream_requester_,
+                  DeviceOpened(render_frame_id, page_request_id, _, _))
+          .Times(1)
+          .WillOnce(DoAll(ExitMessageLoop(task_runner_, run_loop.QuitClosure()),
+                          SaveArg<2>(&opened_device_label_),
+                          SaveArg<3>(&opened_device)));
       run_loop.Run();
       Mock::VerifyAndClearExpectations(&stream_requester_);
       ASSERT_NE(StreamDeviceInfo::kNoId, opened_device.session_id);
@@ -408,7 +406,7 @@
     base::RunLoop run_loop;
     EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _, _))
         .Times(AnyNumber())
-        .WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()));
+        .WillOnce(ExitMessageLoop(task_runner_, run_loop.QuitClosure()));
 
     media::VideoCaptureParams params;
     params.requested_format = media::VideoCaptureFormat(
@@ -457,7 +455,7 @@
     base::RunLoop run_loop;
     EXPECT_CALL(*host_.get(),
                 OnStateChanged(kDeviceId, VIDEO_CAPTURE_STATE_STOPPED))
-        .WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()));
+        .WillOnce(ExitMessageLoop(task_runner_, run_loop.QuitClosure()));
 
     host_->OnStopCapture(kDeviceId);
     host_->SetReturnReceivedDibs(true);
@@ -474,7 +472,7 @@
     base::RunLoop run_loop;
     EXPECT_CALL(*host_.get(), OnBufferFilled(kDeviceId, _, _, _, _, _))
         .Times(AnyNumber())
-        .WillOnce(ExitMessageLoop(message_loop_, run_loop.QuitClosure()))
+        .WillOnce(ExitMessageLoop(task_runner_, run_loop.QuitClosure()))
         .RetiresOnSaturation();
     run_loop.Run();
   }
@@ -512,7 +510,7 @@
   content::TestBrowserThreadBundle thread_bundle_;
   content::TestBrowserContext browser_context_;
   content::TestContentBrowserClient browser_client_;
-  scoped_refptr<base::MessageLoopProxy> message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   int opened_session_id_;
   std::string opened_device_label_;
 
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc
index a213a564..2ee8396 100644
--- a/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/content/browser/renderer_host/media/video_capture_manager.cc
@@ -9,11 +9,13 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/task_runner_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "content/browser/media/capture/web_contents_video_capture_device.h"
 #include "content/browser/media/media_internals.h"
@@ -224,9 +226,9 @@
   // Notify our listener asynchronously; this ensures that we return
   // |capture_session_id| to the caller of this function before using that same
   // id in a listener event.
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-      base::Bind(&VideoCaptureManager::OnOpened, this,
-                 device_info.device.type, capture_session_id));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&VideoCaptureManager::OnOpened, this,
+                            device_info.device.type, capture_session_id));
   return capture_session_id;
 }
 
@@ -255,9 +257,9 @@
   }
 
   // Notify listeners asynchronously, and forget the session.
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-      base::Bind(&VideoCaptureManager::OnClosed, this, session_it->second.type,
-                 capture_session_id));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&VideoCaptureManager::OnClosed, this,
+                            session_it->second.type, capture_session_id));
   sessions_.erase(session_it);
 }
 
diff --git a/content/browser/renderer_host/media/video_capture_manager_unittest.cc b/content/browser/renderer_host/media/video_capture_manager_unittest.cc
index a8e45add..832b0dc 100644
--- a/content/browser/renderer_host/media/video_capture_manager_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_manager_unittest.cc
@@ -9,7 +9,6 @@
 #include "base/bind.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/renderer_host/media/media_stream_provider.h"
@@ -88,7 +87,7 @@
             vcm_->video_capture_device_factory());
     const int32 kNumberOfFakeDevices = 2;
     video_capture_device_factory_->set_number_of_devices(kNumberOfFakeDevices);
-    vcm_->Register(listener_.get(), message_loop_->message_loop_proxy().get());
+    vcm_->Register(listener_.get(), message_loop_->task_runner().get());
     frame_observer_.reset(new MockFrameObserver());
   }
 
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp.cc b/content/browser/renderer_host/p2p/socket_host_tcp.cc
index a92e3e52..dd49bff 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp.cc
+++ b/content/browser/renderer_host/p2p/socket_host_tcp.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/renderer_host/p2p/socket_host_tcp.h"
 
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/sys_byteorder.h"
 #include "content/common/p2p_messages.h"
 #include "ipc/ipc_sender.h"
@@ -117,10 +119,9 @@
     // the connect always happens asynchronously.
     base::MessageLoop* message_loop = base::MessageLoop::current();
     CHECK(message_loop);
-    message_loop->PostTask(
-        FROM_HERE,
-        base::Bind(&P2PSocketHostTcpBase::OnConnected,
-                   base::Unretained(this), status));
+    message_loop->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&P2PSocketHostTcpBase::OnConnected,
+                              base::Unretained(this), status));
   }
 
   return state_ != STATE_ERROR;
diff --git a/content/browser/renderer_host/pepper/quota_reservation_unittest.cc b/content/browser/renderer_host/pepper/quota_reservation_unittest.cc
index 6eb6f13..5d7445b4 100644
--- a/content/browser/renderer_host/pepper/quota_reservation_unittest.cc
+++ b/content/browser/renderer_host/pepper/quota_reservation_unittest.cc
@@ -9,8 +9,10 @@
 #include "base/files/file.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "storage/browser/fileapi/quota/quota_reservation.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -40,7 +42,7 @@
       storage::FileSystemType type,
       int64 delta,
       const QuotaReservationManager::ReserveQuotaCallback& callback) override {
-    base::MessageLoopProxy::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(base::IgnoreResult(callback), base::File::FILE_OK, delta));
   }
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 38cc0ab..d4da1d4 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -19,12 +19,14 @@
 #include "base/debug/dump_without_crashing.h"
 #include "base/files/file.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
 #include "base/process/process_handle.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -1688,15 +1690,16 @@
     // Remove ourself from the list of renderer processes so that we can't be
     // reused in between now and when the Delete task runs.
     UnregisterHost(GetID());
-  }
 
 #if defined(OS_MACOSX) && !defined(OS_IOS)
-  if (!io_surface_manager_token_.IsZero()) {
-    BrowserIOSurfaceManager::GetInstance()->InvalidateChildProcessToken(
-        io_surface_manager_token_);
-    io_surface_manager_token_.SetZero();
-  }
+    if (!io_surface_manager_token_.IsZero()) {
+      BrowserIOSurfaceManager::GetInstance()->InvalidateChildProcessToken(
+          io_surface_manager_token_);
+      io_surface_manager_token_.SetZero();
+    }
 #endif
+
+  }
 }
 
 void RenderProcessHostImpl::AddPendingView() {
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 4e81849..3495a15 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -278,6 +278,7 @@
     int opener_route_id,
     int proxy_route_id,
     int32 max_page_id,
+    const FrameReplicationState& replicated_frame_state,
     bool window_was_created_with_opener) {
   TRACE_EVENT0("renderer_host,navigation",
                "RenderViewHostImpl::CreateRenderView");
@@ -319,6 +320,7 @@
   // Ensure the RenderView sets its opener correctly.
   params.opener_route_id = opener_route_id;
   params.swapped_out = !is_active_;
+  params.replicated_frame_state = replicated_frame_state;
   params.proxy_routing_id = proxy_route_id;
   params.hidden = is_hidden();
   params.never_visible = delegate_->IsNeverVisible();
@@ -328,11 +330,6 @@
   params.min_size = min_size_for_auto_resize();
   params.max_size = max_size_for_auto_resize();
   GetResizeParams(&params.initial_size);
-  if (!is_active_) {
-    params.replicated_frame_state =
-        static_cast<RenderFrameHostImpl*>(GetMainFrame())->frame_tree_node()
-            ->current_replication_state();
-  }
 
   if (!Send(new ViewMsg_New(params)))
     return false;
@@ -353,10 +350,12 @@
   // Let our delegate know that we created a RenderView.
   delegate_->RenderViewCreated(this);
 
-  // Since this method creates the main RenderFrame in the renderer process,
+  // Since this method can create the main RenderFrame in the renderer process,
   // set the proper state on its corresponding RenderFrameHost.
-  RenderFrameHostImpl::FromID(GetProcess()->GetID(), main_frame_routing_id_)
-      ->SetRenderFrameCreated(true);
+  if (main_frame_routing_id_ != MSG_ROUTING_NONE) {
+    RenderFrameHostImpl::FromID(GetProcess()->GetID(), main_frame_routing_id_)
+        ->SetRenderFrameCreated(true);
+  }
 
   return true;
 }
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index f780ddd0..2ecc27ad 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -57,6 +57,7 @@
 class TestRenderViewHost;
 struct FileChooserFileInfo;
 struct FileChooserParams;
+struct FrameReplicationState;
 
 #if defined(COMPILER_MSVC)
 // RenderViewHostImpl is the bottom of a diamond-shaped hierarchy,
@@ -202,11 +203,13 @@
   // created with an opener. (The opener may have been closed since.)
   // The |proxy_route_id| is only used when creating a RenderView in swapped out
   // state.
-  virtual bool CreateRenderView(const base::string16& frame_name,
-                                int opener_route_id,
-                                int proxy_route_id,
-                                int32 max_page_id,
-                                bool window_was_created_with_opener);
+  virtual bool CreateRenderView(
+      const base::string16& frame_name,
+      int opener_route_id,
+      int proxy_route_id,
+      int32 max_page_id,
+      const FrameReplicationState& replicated_frame_state,
+      bool window_was_created_with_opener);
 
   base::TerminationStatus render_view_termination_status() const {
     return render_view_termination_status_;
@@ -300,6 +303,9 @@
   int main_frame_routing_id() const {
     return main_frame_routing_id_;
   }
+  void set_main_frame_routing_id(int routing_id) {
+    main_frame_routing_id_ = routing_id;
+  }
 
   void OnTextSurroundingSelectionResponse(const base::string16& content,
                                           size_t start_offset,
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index b987fbf3..74f7ff4 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -14,9 +14,10 @@
 #include "base/containers/hash_tables.h"
 #include "base/i18n/rtl.h"
 #include "base/lazy_instance.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/thread_task_runner_handle.h"
@@ -1534,10 +1535,9 @@
     bool post_callback = new_auto_size_.IsEmpty();
     new_auto_size_ = params.view_size;
     if (post_callback) {
-      base::MessageLoop::current()->PostTask(
-          FROM_HERE,
-          base::Bind(&RenderWidgetHostImpl::DelayedAutoResized,
-                     weak_factory_.GetWeakPtr()));
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE, base::Bind(&RenderWidgetHostImpl::DelayedAutoResized,
+                                weak_factory_.GetWeakPtr()));
     }
   }
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index b9fc03a..bb8be83 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -478,6 +478,10 @@
   gfx::NativeViewAccessible GetParentNativeViewAccessible();
 #endif
 
+  void set_renderer_initialized(bool renderer_initialized) {
+    renderer_initialized_ = renderer_initialized;
+  }
+
  protected:
   RenderWidgetHostImpl* AsRenderWidgetHostImpl() override;
 
@@ -553,10 +557,6 @@
     return --in_flight_event_count_;
   }
 
-  void set_renderer_initialized(bool renderer_initialized) {
-    renderer_initialized_ = renderer_initialized;
-  }
-
   bool renderer_initialized() const { return renderer_initialized_; }
 
   // The View associated with the RenderViewHost. The lifetime of this object
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index fc691c7..1787f66 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -5,8 +5,11 @@
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/shared_memory.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/timer/timer.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/gpu/compositor_util.h"
@@ -979,9 +982,8 @@
   host_->StartHangMonitorTimeout(TimeDelta::FromSeconds(30));
 
   // Wait long enough for first timeout and see if it fired.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
       TimeDelta::FromMilliseconds(10));
   base::MessageLoop::current()->Run();
   EXPECT_TRUE(host_->unresponsive_timer_fired());
@@ -999,9 +1001,8 @@
   host_->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(10));
 
   // Wait long enough for first timeout and see if it fired.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
       TimeDelta::FromMilliseconds(40));
   base::MessageLoop::current()->Run();
   EXPECT_TRUE(host_->unresponsive_timer_fired());
@@ -1018,9 +1019,8 @@
   host_->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(20));
 
   // Wait long enough for the second timeout and see if it fired.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
       TimeDelta::FromMilliseconds(25));
   base::MessageLoop::current()->Run();
   EXPECT_TRUE(host_->unresponsive_timer_fired());
@@ -1037,18 +1037,16 @@
 
   // The timeout should not fire.
   EXPECT_FALSE(host_->unresponsive_timer_fired());
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
       TimeDelta::FromMicroseconds(2));
   base::MessageLoop::current()->Run();
   EXPECT_FALSE(host_->unresponsive_timer_fired());
 
   // The timeout should never reactivate while hidden.
   SimulateMouseEvent(WebInputEvent::MouseMove, 10, 10, 0, false);
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
       TimeDelta::FromMicroseconds(2));
   base::MessageLoop::current()->Run();
   EXPECT_FALSE(host_->unresponsive_timer_fired());
@@ -1056,9 +1054,8 @@
   // Showing the widget should restore the timeout, as the events have
   // not yet been ack'ed.
   host_->WasShown(ui::LatencyInfo());
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
       TimeDelta::FromMicroseconds(2));
   base::MessageLoop::current()->Run();
   EXPECT_TRUE(host_->unresponsive_timer_fired());
@@ -1079,9 +1076,8 @@
                     INPUT_EVENT_ACK_STATE_CONSUMED);
 
   // Wait long enough for first timeout and see if it fired.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::MessageLoop::QuitClosure(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
       TimeDelta::FromMicroseconds(20));
   base::MessageLoop::current()->Run();
   EXPECT_TRUE(host_->unresponsive_timer_fired());
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 59f2b32fd..abdb9eb 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -211,6 +211,7 @@
           0,  // offscreen
           url, gpu_channel_host.get(), attrs, lose_context_when_out_of_memory,
           limits, nullptr));
+  context->SetContextType(BROWSER_OFFSCREEN_MAINTHREAD_CONTEXT);
   if (context->InitializeOnCurrentThread()) {
     context->traceBeginCHROMIUM(
         "gpu_toplevel",
@@ -753,10 +754,11 @@
       ui::CreateWebTouchEventFromMotionEvent(event, result.did_generate_scroll);
   host_->ForwardTouchEventWithLatencyInfo(web_event, ui::LatencyInfo());
 
-  // Send a proactive BeginFrame on the next vsync to reduce latency.
-  // This is good enough as long as the first touch event has Begin semantics
-  // and the actual scroll happens on the next vsync.
-  if (observing_root_window_)
+  // Send a proactive BeginFrame for this vsync to reduce scroll latency for
+  // scroll-inducing touch events. Note that Android's Choreographer ensures
+  // that BeginFrame requests made during ACTION_MOVE dispatch will be honored
+  // in the same vsync phase.
+  if (observing_root_window_&& result.did_generate_scroll)
     RequestVSyncUpdate(BEGIN_FRAME);
 
   return true;
@@ -956,7 +958,7 @@
 scoped_ptr<SyntheticGestureTarget>
 RenderWidgetHostViewAndroid::CreateSyntheticGestureTarget() {
   return scoped_ptr<SyntheticGestureTarget>(new SyntheticGestureTargetAndroid(
-      host_, content_view_core_->CreateTouchEventSynthesizer()));
+      host_, content_view_core_->CreateMotionEventSynthesizer()));
 }
 
 void RenderWidgetHostViewAndroid::SendDelegatedFrameAck(
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index a55c9b4d..b8b7f3e 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -2466,8 +2466,7 @@
 }
 
 bool RenderWidgetHostViewAura::NeedsInputGrab() {
-  return popup_type_ == blink::WebPopupTypeSelect ||
-         popup_type_ == blink::WebPopupTypePage;
+  return popup_type_ == blink::WebPopupTypePage;
 }
 
 bool RenderWidgetHostViewAura::NeedsMouseCapture() {
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index c7807067..5af7f4ca 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -906,7 +906,7 @@
       parent_view_->GetNativeView()->GetRootWindow(), gfx::Point(300, 300));
   generator.PressLeftButton();
 
-  view_->SetPopupType(blink::WebPopupTypeSelect);
+  view_->SetPopupType(blink::WebPopupTypePage);
   view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100));
   ASSERT_TRUE(view_->NeedsMouseCapture());
   aura::Window* window = view_->GetNativeView();
@@ -924,7 +924,7 @@
   parent_view_->Focus();
   EXPECT_TRUE(parent_view_->HasFocus());
 
-  view_->SetPopupType(blink::WebPopupTypeSelect);
+  view_->SetPopupType(blink::WebPopupTypePage);
   view_->InitAsPopup(parent_view_, gfx::Rect(10, 10, 100, 100));
 
   aura::Window* popup_window = view_->GetNativeView();
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
index f522ef0..8db91f36 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -497,6 +497,12 @@
 }
 
 void RenderWidgetHostViewBase::AccessibilityShowMenu(const gfx::Point& point) {
+  RenderWidgetHostImpl* impl = NULL;
+  if (GetRenderWidgetHost())
+    impl = RenderWidgetHostImpl::From(GetRenderWidgetHost());
+
+  if (impl)
+    impl->ShowContextMenuAtPoint(point);
 }
 
 gfx::Point RenderWidgetHostViewBase::AccessibilityOriginInScreen(
diff --git a/content/browser/renderer_host/render_widget_host_view_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
index 7e6794a2..464b915 100644
--- a/content/browser/renderer_host/render_widget_host_view_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
@@ -4,9 +4,11 @@
 
 #include "base/barrier_closure.h"
 #include "base/command_line.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/gpu/compositor_util.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/browser/renderer_host/dip_util.h"
@@ -129,15 +131,16 @@
   }
 
   // Callback when using frame subscriber API.
-  void FrameDelivered(const scoped_refptr<base::MessageLoopProxy>& loop,
-                      base::Closure quit_closure,
-                      base::TimeTicks timestamp,
-                      bool frame_captured) {
+  void FrameDelivered(
+      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+      base::Closure quit_closure,
+      base::TimeTicks timestamp,
+      bool frame_captured) {
     ++callback_invoke_count_;
     if (frame_captured)
       ++frames_captured_;
     if (!quit_closure.is_null())
-      loop->PostTask(FROM_HERE, quit_closure);
+      task_runner->PostTask(FROM_HERE, quit_closure);
   }
 
   // Copy one frame using the CopyFromBackingStore API.
@@ -182,9 +185,8 @@
   // call stack.
   static void GiveItSomeTime() {
     base::RunLoop run_loop;
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        run_loop.QuitClosure(),
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, run_loop.QuitClosure(),
         base::TimeDelta::FromMilliseconds(10));
     run_loop.Run();
   }
@@ -339,11 +341,10 @@
 
   base::RunLoop run_loop;
   scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber(
-      new FakeFrameSubscriber(
-          base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered,
-                     base::Unretained(this),
-                     base::MessageLoopProxy::current(),
-                     run_loop.QuitClosure())));
+      new FakeFrameSubscriber(base::Bind(
+          &RenderWidgetHostViewBrowserTest::FrameDelivered,
+          base::Unretained(this), base::ThreadTaskRunnerHandle::Get(),
+          run_loop.QuitClosure())));
   view->BeginFrameSubscription(subscriber.Pass());
   run_loop.Run();
   view->EndFrameSubscription();
@@ -373,12 +374,12 @@
   view->CopyFromCompositingSurfaceToVideoFrame(
       gfx::Rect(view->GetViewBounds().size()), first_output,
       base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered,
-                 base::Unretained(this), base::MessageLoopProxy::current(),
+                 base::Unretained(this), base::ThreadTaskRunnerHandle::Get(),
                  closure, base::TimeTicks::Now()));
   view->CopyFromCompositingSurfaceToVideoFrame(
       gfx::Rect(view->GetViewBounds().size()), second_output,
       base::Bind(&RenderWidgetHostViewBrowserTest::FrameDelivered,
-                 base::Unretained(this), base::MessageLoopProxy::current(),
+                 base::Unretained(this), base::ThreadTaskRunnerHandle::Get(),
                  closure, base::TimeTicks::Now()));
   run_loop.Run();
 
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index e1b5f43..d2137fb 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -323,7 +323,6 @@
   BrowserAccessibilityManager* CreateBrowserAccessibilityManager(
       BrowserAccessibilityDelegate* delegate) override;
   gfx::Point AccessibilityOriginInScreen(const gfx::Rect& bounds) override;
-  void AccessibilityShowMenu(const gfx::Point& point) override;
   bool PostProcessEventForPluginIme(
       const NativeWebKeyboardEvent& event) override;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index ebf4974..625f041 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -1663,23 +1663,6 @@
   return gfx::Point(originInScreen.x, originInScreen.y);
 }
 
-void RenderWidgetHostViewMac::AccessibilityShowMenu(const gfx::Point& point) {
-  NSPoint location = NSMakePoint(point.x(), point.y());
-  location = [[cocoa_view_ window] convertScreenToBase:location];
-  NSEvent* fakeRightClick = [NSEvent
-                          mouseEventWithType:NSRightMouseDown
-                                    location:location
-                               modifierFlags:0
-                                   timestamp:0
-                                windowNumber:[[cocoa_view_ window] windowNumber]
-                                     context:[NSGraphicsContext currentContext]
-                                 eventNumber:0
-                                  clickCount:1
-                                    pressure:0];
-
-  [cocoa_view_ mouseEvent:fakeRightClick];
-}
-
 void RenderWidgetHostViewMac::SetTextInputActive(bool active) {
   if (active) {
     if (text_input_type_ == ui::TEXT_INPUT_TYPE_PASSWORD)
diff --git a/content/browser/renderer_host/websocket_host.cc b/content/browser/renderer_host/websocket_host.cc
index cd8dd25a..801cee0 100644
--- a/content/browser/renderer_host/websocket_host.cc
+++ b/content/browser/renderer_host/websocket_host.cc
@@ -5,8 +5,11 @@
 #include "content/browser/renderer_host/websocket_host.h"
 
 #include "base/basictypes.h"
+#include "base/location.h"
 #include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/renderer_host/websocket_dispatcher_host.h"
 #include "content/browser/ssl/ssl_error_handler.h"
 #include "content/browser/ssl/ssl_manager.h"
@@ -355,14 +358,10 @@
 
   DCHECK(!channel_);
   if (delay_ > base::TimeDelta()) {
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
-        base::Bind(&WebSocketHost::AddChannel,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   socket_url,
-                   requested_protocols,
-                   origin,
-                   render_frame_id),
+        base::Bind(&WebSocketHost::AddChannel, weak_ptr_factory_.GetWeakPtr(),
+                   socket_url, requested_protocols, origin, render_frame_id),
         delay_);
   } else {
     AddChannel(socket_url, requested_protocols, origin, render_frame_id);
@@ -394,11 +393,10 @@
     // We post OnFlowControl() here using |weak_ptr_factory_| instead of
     // calling SendFlowControl directly, because |this| may have been deleted
     // after channel_->SendAddChannelRequest().
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&WebSocketHost::OnFlowControl,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   pending_flow_control_quota_));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&WebSocketHost::OnFlowControl,
+                              weak_ptr_factory_.GetWeakPtr(),
+                              pending_flow_control_quota_));
     pending_flow_control_quota_ = 0;
   }
 
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index 62d3b62c..cf3b7f75 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -202,7 +202,7 @@
   // different timing in the test, let's simulate a CreateNewWidget call coming
   // from the IO thread.  Use the existing window routing id to cause a
   // deliberate collision.
-  pending_rvh->CreateNewWidget(duplicate_routing_id, blink::WebPopupTypeSelect);
+  pending_rvh->CreateNewWidget(duplicate_routing_id, blink::WebPopupTypePage);
 
   // If the above operation doesn't crash, the test has succeeded!
 }
diff --git a/content/browser/service_worker/service_worker_context_core.cc b/content/browser/service_worker/service_worker_context_core.cc
index a76f7744..fef7bcdc 100644
--- a/content/browser/service_worker/service_worker_context_core.cc
+++ b/content/browser/service_worker/service_worker_context_core.cc
@@ -8,8 +8,10 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/file_path.h"
+#include "base/location.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/service_worker/embedded_worker_registry.h"
 #include "content/browser/service_worker/service_worker_context_observer.h"
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
@@ -446,7 +448,7 @@
 
 void ServiceWorkerContextCore::ScheduleDeleteAndStartOver() const {
   storage_->Disable();
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&ServiceWorkerContextWrapper::DeleteAndStartOver, wrapper_));
 }
diff --git a/content/browser/service_worker/service_worker_context_request_handler.cc b/content/browser/service_worker/service_worker_context_request_handler.cc
index bf360b9..f1a4fd3 100644
--- a/content/browser/service_worker/service_worker_context_request_handler.cc
+++ b/content/browser/service_worker/service_worker_context_request_handler.cc
@@ -12,6 +12,7 @@
 #include "content/browser/service_worker/service_worker_version.h"
 #include "content/browser/service_worker/service_worker_write_to_cache_job.h"
 #include "content/public/browser/resource_context.h"
+#include "content/public/common/resource_response_info.h"
 #include "net/base/load_flags.h"
 #include "net/url_request/url_request.h"
 
@@ -73,13 +74,17 @@
       extra_load_flags = net::LOAD_BYPASS_CACHE;
     }
 
-    return new ServiceWorkerWriteToCacheJob(request,
-                                            network_delegate,
-                                            resource_type_,
-                                            context_,
-                                            version_.get(),
-                                            extra_load_flags,
-                                            response_id);
+    ServiceWorkerVersion* stored_version = registration->waiting_version()
+                                               ? registration->waiting_version()
+                                               : registration->active_version();
+    int64 incumbent_response_id = kInvalidServiceWorkerResourceId;
+    if (stored_version && stored_version->script_url() == request->url()) {
+      incumbent_response_id =
+          stored_version->script_cache_map()->LookupResourceId(request->url());
+    }
+    return new ServiceWorkerWriteToCacheJob(
+        request, network_delegate, resource_type_, context_, version_.get(),
+        extra_load_flags, response_id, incumbent_response_id);
   }
 
   int64 response_id = kInvalidServiceWorkerResponseId;
@@ -93,15 +98,11 @@
 }
 
 void ServiceWorkerContextRequestHandler::GetExtraResponseInfo(
-    bool* was_fetched_via_service_worker,
-    bool* was_fallback_required_by_service_worker,
-    GURL* original_url_via_service_worker,
-    blink::WebServiceWorkerResponseType* response_type_via_service_worker,
-    base::TimeTicks* worker_start_time) const {
-  *was_fetched_via_service_worker = false;
-  *was_fallback_required_by_service_worker = false;
-  *original_url_via_service_worker = GURL();
-  *response_type_via_service_worker =
+    ResourceResponseInfo* response_info) const {
+  response_info->was_fetched_via_service_worker = false;
+  response_info->was_fallback_required_by_service_worker = false;
+  response_info->original_url_via_service_worker = GURL();
+  response_info->response_type_via_service_worker =
       blink::WebServiceWorkerResponseTypeDefault;
 }
 
diff --git a/content/browser/service_worker/service_worker_context_request_handler.h b/content/browser/service_worker/service_worker_context_request_handler.h
index e31e1da..85db8eb 100644
--- a/content/browser/service_worker/service_worker_context_request_handler.h
+++ b/content/browser/service_worker/service_worker_context_request_handler.h
@@ -29,12 +29,7 @@
       net::NetworkDelegate* network_delegate,
       ResourceContext* resource_context) override;
 
-  void GetExtraResponseInfo(
-      bool* was_fetched_via_service_worker,
-      bool* was_fallback_required_by_service_worker,
-      GURL* original_url_via_service_worker,
-      blink::WebServiceWorkerResponseType* response_type_via_service_worker,
-      base::TimeTicks* worker_start_time) const override;
+  void GetExtraResponseInfo(ResourceResponseInfo* response_info) const override;
 
  private:
   bool ShouldAddToScriptCache(const GURL& url);
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc
index d4a189c..264c9ce5 100644
--- a/content/browser/service_worker/service_worker_context_wrapper.cc
+++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -13,8 +13,11 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/profiler/scoped_tracker.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_context_observer.h"
@@ -41,7 +44,7 @@
     LAZY_INSTANCE_INITIALIZER;
 
 void RunSoon(const base::Closure& closure) {
-  base::MessageLoop::current()->PostTask(FROM_HERE, closure);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure);
 }
 
 void WorkerStarted(const ServiceWorkerContextWrapper::StatusCallback& callback,
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc
index 2ef8b6fa..1f383d73e 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -15,6 +15,7 @@
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/content_client.h"
+#include "content/public/common/resource_response_info.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_util.h"
 #include "net/url_request/url_request.h"
@@ -65,8 +66,9 @@
     net::NetworkDelegate* network_delegate,
     ResourceContext* resource_context) {
   if (job_.get() && worker_start_time_.is_null()) {
-    // Save worker-start time of the first job.
+    // Save worker timings of the first job.
     worker_start_time_ = job_->worker_start_time();
+    worker_ready_time_ = job_->worker_ready_time();
   }
 
   if (!context_ || !provider_host_) {
@@ -115,25 +117,20 @@
 }
 
 void ServiceWorkerControlleeRequestHandler::GetExtraResponseInfo(
-    bool* was_fetched_via_service_worker,
-    bool* was_fallback_required_by_service_worker,
-    GURL* original_url_via_service_worker,
-    blink::WebServiceWorkerResponseType* response_type_via_service_worker,
-    base::TimeTicks* worker_start_time) const {
+    ResourceResponseInfo* response_info) const {
   if (!job_.get()) {
-    *was_fetched_via_service_worker = false;
-    *was_fallback_required_by_service_worker = false;
-    *original_url_via_service_worker = GURL();
-    *worker_start_time = worker_start_time_;
+    response_info->was_fetched_via_service_worker = false;
+    response_info->was_fallback_required_by_service_worker = false;
+    response_info->original_url_via_service_worker = GURL();
+    response_info->service_worker_start_time = worker_start_time_;
+    response_info->service_worker_ready_time = worker_ready_time_;
     return;
   }
-  job_->GetExtraResponseInfo(
-      was_fetched_via_service_worker, was_fallback_required_by_service_worker,
-      original_url_via_service_worker, response_type_via_service_worker,
-      worker_start_time);
+  job_->GetExtraResponseInfo(response_info);
   if (!worker_start_time_.is_null()) {
-    // If we have worker start time from previous job, use it.
-    *worker_start_time = worker_start_time_;
+    // If we have worker timings from previous job, use it.
+    response_info->service_worker_start_time = worker_start_time_;
+    response_info->service_worker_ready_time = worker_ready_time_;
   }
 }
 
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.h b/content/browser/service_worker/service_worker_controllee_request_handler.h
index 1de2bf9..90b01f9 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.h
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.h
@@ -49,12 +49,7 @@
       net::NetworkDelegate* network_delegate,
       ResourceContext* resource_context) override;
 
-  void GetExtraResponseInfo(
-      bool* was_fetched_via_service_worker,
-      bool* was_fallback_required_by_service_worker,
-      GURL* original_url_via_service_worker,
-      blink::WebServiceWorkerResponseType* response_type_via_service_worker,
-      base::TimeTicks* worker_start_time) const override;
+  void GetExtraResponseInfo(ResourceResponseInfo* response_info) const override;
 
  private:
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerControlleeRequestHandlerTest,
@@ -83,6 +78,7 @@
   ResourceContext* resource_context_;
   GURL stripped_url_;
   base::TimeTicks worker_start_time_;
+  base::TimeTicks worker_ready_time_;
   base::WeakPtrFactory<ServiceWorkerControlleeRequestHandler> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerControlleeRequestHandler);
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index c2140d57..0af23c1 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -228,6 +228,15 @@
  private:
   friend class ServiceWorkerProviderHostTest;
   friend class ServiceWorkerWriteToCacheJobTest;
+  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest, Update_SameScript);
+  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest,
+                           Update_SameSizeScript);
+  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest,
+                           Update_TruncatedScript);
+  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest,
+                           Update_ElongatedScript);
+  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest,
+                           Update_EmptyScript);
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
                            UpdateBefore24Hours);
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
diff --git a/content/browser/service_worker/service_worker_register_job.cc b/content/browser/service_worker/service_worker_register_job.cc
index 6ab1db6..c4f7754f 100644
--- a/content/browser/service_worker/service_worker_register_job.cc
+++ b/content/browser/service_worker/service_worker_register_job.cc
@@ -6,7 +6,9 @@
 
 #include <vector>
 
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_job_coordinator.h"
 #include "content/browser/service_worker/service_worker_metrics.h"
@@ -21,7 +23,7 @@
 namespace {
 
 void RunSoon(const base::Closure& closure) {
-  base::MessageLoop::current()->PostTask(FROM_HERE, closure);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure);
 }
 
 }  // namespace
diff --git a/content/browser/service_worker/service_worker_request_handler.h b/content/browser/service_worker/service_worker_request_handler.h
index 3f28e3b..a3246e9 100644
--- a/content/browser/service_worker/service_worker_request_handler.h
+++ b/content/browser/service_worker/service_worker_request_handler.h
@@ -16,7 +16,6 @@
 #include "content/public/common/request_context_type.h"
 #include "content/public/common/resource_type.h"
 #include "net/url_request/url_request_job_factory.h"
-#include "third_party/WebKit/public/platform/WebServiceWorkerResponseType.h"
 
 namespace net {
 class NetworkDelegate;
@@ -35,6 +34,7 @@
 class ServiceWorkerContextCore;
 class ServiceWorkerContextWrapper;
 class ServiceWorkerProviderHost;
+struct ResourceResponseInfo;
 
 // Abstract base class for routing network requests to ServiceWorkers.
 // Created one per URLRequest and attached to each request.
@@ -85,11 +85,7 @@
       ResourceContext* context) = 0;
 
   virtual void GetExtraResponseInfo(
-      bool* was_fetched_via_service_worker,
-      bool* was_fallback_required_by_service_worker,
-      GURL* original_url_via_service_worker,
-      blink::WebServiceWorkerResponseType* response_type_via_service_worker,
-      base::TimeTicks* worker_start_time) const = 0;
+      ResourceResponseInfo* response_info) const = 0;
 
   // Methods to support cross site navigations.
   void PrepareForCrossSiteTransfer(int old_process_id);
diff --git a/content/browser/service_worker/service_worker_url_request_job.cc b/content/browser/service_worker/service_worker_url_request_job.cc
index 2db0cfb..17afffd 100644
--- a/content/browser/service_worker/service_worker_url_request_job.cc
+++ b/content/browser/service_worker/service_worker_url_request_job.cc
@@ -10,8 +10,11 @@
 
 #include "base/bind.h"
 #include "base/guid.h"
+#include "base/location.h"
 #include "base/memory/scoped_vector.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "content/browser/resource_context_impl.h"
 #include "content/browser/service_worker/service_worker_fetch_dispatcher.h"
@@ -25,6 +28,7 @@
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/service_worker_context.h"
 #include "content/public/common/referrer.h"
+#include "content/public/common/resource_response_info.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
@@ -292,24 +296,22 @@
 }
 
 void ServiceWorkerURLRequestJob::GetExtraResponseInfo(
-    bool* was_fetched_via_service_worker,
-    bool* was_fallback_required_by_service_worker,
-    GURL* original_url_via_service_worker,
-    blink::WebServiceWorkerResponseType* response_type_via_service_worker,
-    base::TimeTicks* worker_start_time) const {
+    ResourceResponseInfo* response_info) const {
   if (response_type_ != FORWARD_TO_SERVICE_WORKER) {
-    *was_fetched_via_service_worker = false;
-    *was_fallback_required_by_service_worker = false;
-    *original_url_via_service_worker = GURL();
-    *response_type_via_service_worker =
+    response_info->was_fetched_via_service_worker = false;
+    response_info->was_fallback_required_by_service_worker = false;
+    response_info->original_url_via_service_worker = GURL();
+    response_info->response_type_via_service_worker =
         blink::WebServiceWorkerResponseTypeDefault;
     return;
   }
-  *was_fetched_via_service_worker = true;
-  *was_fallback_required_by_service_worker = fall_back_required_;
-  *original_url_via_service_worker = response_url_;
-  *response_type_via_service_worker = service_worker_response_type_;
-  *worker_start_time = worker_start_time_;
+  response_info->was_fetched_via_service_worker = true;
+  response_info->was_fallback_required_by_service_worker = fall_back_required_;
+  response_info->original_url_via_service_worker = response_url_;
+  response_info->response_type_via_service_worker =
+      service_worker_response_type_;
+  response_info->service_worker_start_time = worker_start_time_;
+  response_info->service_worker_ready_time = worker_ready_time_;
 }
 
 
@@ -320,10 +322,9 @@
 void ServiceWorkerURLRequestJob::MaybeStartRequest() {
   if (is_started_ && response_type_ != NOT_DETERMINED) {
     // Start asynchronously.
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&ServiceWorkerURLRequestJob::StartRequest,
-                   weak_factory_.GetWeakPtr()));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&ServiceWorkerURLRequestJob::StartRequest,
+                              weak_factory_.GetWeakPtr()));
   }
 }
 
@@ -471,7 +472,8 @@
 }
 
 void ServiceWorkerURLRequestJob::DidPrepareFetchEvent() {
-  load_timing_info_.send_start = base::TimeTicks::Now();
+  worker_ready_time_ = base::TimeTicks::Now();
+  load_timing_info_.send_start = worker_ready_time_;
 }
 
 void ServiceWorkerURLRequestJob::DidDispatchFetchEvent(
diff --git a/content/browser/service_worker/service_worker_url_request_job.h b/content/browser/service_worker/service_worker_url_request_job.h
index 96e5007..18afaa7d 100644
--- a/content/browser/service_worker/service_worker_url_request_job.h
+++ b/content/browser/service_worker/service_worker_url_request_job.h
@@ -43,6 +43,7 @@
 class ServiceWorkerProviderHost;
 class ServiceWorkerVersion;
 class Stream;
+struct ResourceResponseInfo;
 
 class CONTENT_EXPORT ServiceWorkerURLRequestJob
     : public net::URLRequestJob,
@@ -109,16 +110,14 @@
   // StreamRegisterObserver override:
   void OnStreamRegistered(Stream* stream) override;
 
-  void GetExtraResponseInfo(
-      bool* was_fetched_via_service_worker,
-      bool* was_fallback_required_by_service_worker,
-      GURL* original_url_via_service_worker,
-      blink::WebServiceWorkerResponseType* response_type_via_service_worker,
-      base::TimeTicks* worker_start_time) const;
+  void GetExtraResponseInfo(ResourceResponseInfo* response_info) const;
 
   const base::TimeTicks& worker_start_time() const {
     return worker_start_time_;
   }
+  const base::TimeTicks& worker_ready_time() const {
+    return worker_ready_time_;
+  }
 
  protected:
   ~ServiceWorkerURLRequestJob() override;
@@ -172,6 +171,7 @@
   // Timing info to show on the popup in Devtools' Network tab.
   net::LoadTimingInfo load_timing_info_;
   base::TimeTicks worker_start_time_;
+  base::TimeTicks worker_ready_time_;
   base::Time response_time_;
 
   ResponseType response_type_;
diff --git a/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
index 9e8462a..2d709d0 100644
--- a/content/browser/service_worker/service_worker_url_request_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -101,8 +101,8 @@
 // the memory.
 storage::BlobProtocolHandler* CreateMockBlobProtocolHandler(
     storage::BlobStorageContext* blob_storage_context) {
-  // The FileSystemContext and MessageLoopProxy are not actually used but a
-  // MessageLoopProxy is needed to avoid a DCHECK in BlobURLRequestJob ctor.
+  // The FileSystemContext and task runner are not actually used but a
+  // task runner is needed to avoid a DCHECK in BlobURLRequestJob ctor.
   return new storage::BlobProtocolHandler(
       blob_storage_context, nullptr, base::ThreadTaskRunnerHandle::Get().get());
 }
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 924c55b..9bca8eed 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -5,11 +5,14 @@
 #include "content/browser/service_worker/service_worker_version.h"
 
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/child_process_security_policy_impl.h"
@@ -72,7 +75,7 @@
 
 void RunSoon(const base::Closure& callback) {
   if (!callback.is_null())
-    base::MessageLoop::current()->PostTask(FROM_HERE, callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
 }
 
 template <typename CallbackArray, typename Arg>
@@ -1328,7 +1331,8 @@
 }
 
 void ServiceWorkerVersion::OnSyncEventFinished(
-    int request_id) {
+    int request_id,
+    blink::WebServiceWorkerEventResult result) {
   TRACE_EVENT1("ServiceWorker",
                "ServiceWorkerVersion::OnSyncEventFinished",
                "Request id", request_id);
@@ -1338,8 +1342,18 @@
     return;
   }
 
+  ServiceWorkerStatusCode status = SERVICE_WORKER_OK;
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableServiceWorkerSync)) {
+    // Avoid potential race condition where flag is disabled after a sync event
+    // was dispatched
+    status = SERVICE_WORKER_ERROR_ABORT;
+  } else if (result == blink::WebServiceWorkerEventResultRejected) {
+    status = SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED;
+  }
+
   scoped_refptr<ServiceWorkerVersion> protect(this);
-  callback->Run(SERVICE_WORKER_OK);
+  callback->Run(status);
   RemoveCallbackAndStopIfRedundant(&sync_callbacks_, request_id);
 }
 
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index 39fa417..d77ed992 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -416,7 +416,8 @@
   void OnFetchEventFinished(int request_id,
                             ServiceWorkerFetchEventResult result,
                             const ServiceWorkerResponse& response);
-  void OnSyncEventFinished(int request_id);
+  void OnSyncEventFinished(int request_id,
+                           blink::WebServiceWorkerEventResult result);
   void OnNotificationClickEventFinished(int request_id);
   void OnPushEventFinished(int request_id,
                            blink::WebServiceWorkerEventResult result);
diff --git a/content/browser/service_worker/service_worker_write_to_cache_job.cc b/content/browser/service_worker/service_worker_write_to_cache_job.cc
index b04e98b..f2ad706 100644
--- a/content/browser/service_worker/service_worker_write_to_cache_job.cc
+++ b/content/browser/service_worker/service_worker_write_to_cache_job.cc
@@ -4,7 +4,8 @@
 
 #include "content/browser/service_worker/service_worker_write_to_cache_job.h"
 
-#include "base/strings/stringprintf.h"
+#include <algorithm>
+
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
@@ -39,7 +40,259 @@
     "The script resource is behind a redirect, which is disallowed.";
 const char kServiceWorkerAllowed[] = "Service-Worker-Allowed";
 
-}
+const int kBufferSize = 16 * 1024;
+
+}  // namespace
+
+// Reads an existing resource and copies it via
+// ServiceWorkerWriteToCacheJob::WriteData.
+class ServiceWorkerWriteToCacheJob::Copier : public base::RefCounted<Copier> {
+ public:
+  Copier(base::WeakPtr<ServiceWorkerWriteToCacheJob> owner,
+         scoped_ptr<ServiceWorkerResponseReader> reader,
+         int bytes_to_copy,
+         const base::Callback<void(ServiceWorkerStatusCode)>& callback)
+      : owner_(owner),
+        reader_(reader.release()),
+        bytes_to_copy_(bytes_to_copy),
+        callback_(callback) {
+    DCHECK_LT(0, bytes_to_copy_);
+  }
+
+  void Start() {
+    io_buffer_ = new net::IOBuffer(kBufferSize);
+    ReadSomeData();
+  }
+
+ private:
+  friend class base::RefCounted<Copier>;
+  ~Copier() {}
+
+  void ReadSomeData() {
+    reader_->ReadData(io_buffer_.get(), kBufferSize,
+                      base::Bind(&Copier::OnReadDataComplete, this));
+  }
+
+  void OnReadDataComplete(int result) {
+    if (!owner_)
+      return;
+    if (result <= 0) {
+      // We hit EOF or error but weren't done copying.
+      Complete(SERVICE_WORKER_ERROR_FAILED);
+      return;
+    }
+
+    int bytes_to_write = std::min(bytes_to_copy_, result);
+    owner_->WriteData(io_buffer_.get(), bytes_to_write,
+                      base::Bind(&Copier::OnWriteDataComplete, this));
+  }
+
+  void OnWriteDataComplete(int result) {
+    if (result < 0) {
+      Complete(SERVICE_WORKER_ERROR_FAILED);
+      return;
+    }
+
+    DCHECK_LE(result, bytes_to_copy_);
+    bytes_to_copy_ -= result;
+    if (bytes_to_copy_ == 0) {
+      Complete(SERVICE_WORKER_OK);
+      return;
+    }
+
+    ReadSomeData();
+  }
+
+  void Complete(ServiceWorkerStatusCode status) {
+    if (!owner_)
+      return;
+    callback_.Run(status);
+  }
+
+  base::WeakPtr<ServiceWorkerWriteToCacheJob> owner_;
+  scoped_ptr<ServiceWorkerResponseReader> reader_;
+  int bytes_to_copy_ = 0;
+  base::Callback<void(ServiceWorkerStatusCode)> callback_;
+  scoped_refptr<net::IOBuffer> io_buffer_;
+};
+
+// Abstract consumer for ServiceWorkerWriteToCacheJob that processes data from
+// the network.
+class ServiceWorkerWriteToCacheJob::NetDataConsumer {
+ public:
+  virtual ~NetDataConsumer() {}
+
+  // Called by |owner_|'s OnResponseStarted.
+  virtual void OnResponseStarted() = 0;
+
+  // HandleData should call |owner_|->NotifyReadComplete() when done.
+  virtual void HandleData(net::IOBuffer* buf, int size) = 0;
+};
+
+// Dumb consumer that just writes everything it sees to disk.
+class ServiceWorkerWriteToCacheJob::PassThroughConsumer
+    : public ServiceWorkerWriteToCacheJob::NetDataConsumer {
+ public:
+  explicit PassThroughConsumer(ServiceWorkerWriteToCacheJob* owner)
+      : owner_(owner), weak_factory_(this) {}
+  ~PassThroughConsumer() override {}
+
+  void OnResponseStarted() override {
+    owner_->WriteHeaders(
+        base::Bind(&PassThroughConsumer::OnWriteHeadersComplete,
+                   weak_factory_.GetWeakPtr()));
+    owner_->SetPendingIO();
+  }
+
+  void HandleData(net::IOBuffer* buf, int size) override {
+    if (size == 0) {
+      owner_->OnPassThroughComplete();
+      return;
+    }
+
+    owner_->WriteData(buf, size,
+                      base::Bind(&PassThroughConsumer::OnWriteDataComplete,
+                                 weak_factory_.GetWeakPtr()));
+    owner_->SetPendingIO();
+  }
+
+ private:
+  void OnWriteHeadersComplete() {
+    owner_->ClearPendingIO();
+    owner_->CommitHeadersAndNotifyHeadersComplete();
+  }
+
+  void OnWriteDataComplete(int result) {
+    owner_->ClearPendingIO();
+    owner_->NotifyReadComplete(result);
+  }
+
+  ServiceWorkerWriteToCacheJob* owner_;
+  base::WeakPtrFactory<PassThroughConsumer> weak_factory_;
+};
+
+// Compares an existing resource with data progressively fed to it.
+// Calls back to |owner|->OnCompareComplete once done.
+class ServiceWorkerWriteToCacheJob::Comparer
+    : public ServiceWorkerWriteToCacheJob::NetDataConsumer {
+ public:
+  Comparer(ServiceWorkerWriteToCacheJob* owner,
+           scoped_ptr<ServiceWorkerResponseReader> reader)
+      : owner_(owner), reader_(reader.release()), weak_factory_(this) {}
+  ~Comparer() override {}
+
+  void OnResponseStarted() override {
+    owner_->CommitHeadersAndNotifyHeadersComplete();
+  }
+
+  void HandleData(net::IOBuffer* buf, int size) override {
+    net_data_ = buf;
+    net_data_offset_ = 0;
+    net_data_size_ = size;
+
+    if (size == 0 && info_) {
+      Complete(bytes_matched_ == info_->response_data_size);
+      return;
+    }
+
+    if (!info_) {
+      read_buffer_ = new net::IOBuffer(kBufferSize);
+      info_ = new HttpResponseInfoIOBuffer;
+      reader_->ReadInfo(info_.get(), base::Bind(&Comparer::OnReadInfoComplete,
+                                                weak_factory_.GetWeakPtr()));
+      owner_->SetPendingIO();
+      return;
+    }
+
+    ReadSomeData();
+    owner_->SetPendingIO();
+  }
+
+ private:
+  int bytes_remaining() {
+    DCHECK(net_data_);
+    DCHECK_LE(0, net_data_offset_);
+    DCHECK_LE(net_data_offset_, net_data_size_);
+    return net_data_size_ - net_data_offset_;
+  }
+
+  void OnReadInfoComplete(int result) {
+    if (result < 0) {
+      Complete(false);
+      return;
+    }
+
+    if (bytes_remaining() == 0) {
+      Complete(bytes_matched_ == info_->response_data_size);
+      return;
+    }
+
+    ReadSomeData();
+  }
+
+  void ReadSomeData() {
+    DCHECK_LT(0, bytes_remaining());
+    int bytes_to_read = std::min(bytes_remaining(), kBufferSize);
+    reader_->ReadData(
+        read_buffer_.get(), bytes_to_read,
+        base::Bind(&Comparer::OnReadDataComplete, weak_factory_.GetWeakPtr()));
+  }
+
+  void OnReadDataComplete(int result) {
+    if (result <= 0) {
+      // We hit error or EOF but had more to compare.
+      Complete(false);
+      return;
+    }
+
+    DCHECK_LE(result, bytes_remaining());
+    if (memcmp(net_data_->data() + net_data_offset_, read_buffer_->data(),
+               result) != 0) {
+      Complete(false);
+      return;
+    }
+
+    net_data_offset_ += result;
+    if (bytes_remaining() == 0) {
+      NotifyReadComplete();
+      return;
+    }
+
+    ReadSomeData();
+  }
+
+  // Completes one HandleData() call.
+  void NotifyReadComplete() {
+    int size = net_data_size_;
+    net_data_ = nullptr;
+    net_data_offset_ = 0;
+    net_data_size_ = 0;
+
+    bytes_matched_ += size;
+    owner_->ClearPendingIO();
+    owner_->NotifyReadComplete(size);
+  }
+
+  // Completes the entire Comparer.
+  void Complete(bool is_equal) {
+    owner_->OnCompareComplete(bytes_matched_, is_equal);
+  }
+
+  ServiceWorkerWriteToCacheJob* owner_;
+  scoped_ptr<ServiceWorkerResponseReader> reader_;
+  scoped_refptr<net::IOBuffer> read_buffer_;
+  scoped_refptr<HttpResponseInfoIOBuffer> info_;
+
+  // Cumulative number of bytes successfully compared.
+  int bytes_matched_ = 0;
+
+  // State used for one HandleData() call.
+  scoped_refptr<net::IOBuffer> net_data_;
+  int net_data_offset_ = 0;
+  int net_data_size_ = 0;
+
+  base::WeakPtrFactory<Comparer> weak_factory_;
+};
 
 ServiceWorkerWriteToCacheJob::ServiceWorkerWriteToCacheJob(
     net::URLRequest* request,
@@ -48,12 +301,14 @@
     base::WeakPtr<ServiceWorkerContextCore> context,
     ServiceWorkerVersion* version,
     int extra_load_flags,
-    int64 response_id)
+    int64 response_id,
+    int64 incumbent_response_id)
     : net::URLRequestJob(request, network_delegate),
       resource_type_(resource_type),
       context_(context),
       url_(request->url()),
       response_id_(response_id),
+      incumbent_response_id_(incumbent_response_id),
       version_(version),
       has_been_killed_(false),
       did_notify_started_(false),
@@ -76,6 +331,14 @@
         net::URLRequestStatus::FAILED, net::ERR_FAILED));
     return;
   }
+  if (incumbent_response_id_ != kInvalidServiceWorkerResourceId) {
+    scoped_ptr<ServiceWorkerResponseReader> incumbent_reader =
+        context_->storage()->CreateResponseReader(incumbent_response_id_);
+    consumer_.reset(new Comparer(this, incumbent_reader.Pass()));
+  } else {
+    consumer_.reset(new PassThroughConsumer(this));
+  }
+
   version_->script_cache_map()->NotifyStartedCaching(
       url_, response_id_);
   did_notify_started_ = true;
@@ -140,20 +403,25 @@
   net_request_->SetExtraRequestHeaders(headers);
 }
 
-bool ServiceWorkerWriteToCacheJob::ReadRawData(
-    net::IOBuffer* buf,
-    int buf_size,
-    int *bytes_read) {
+bool ServiceWorkerWriteToCacheJob::ReadRawData(net::IOBuffer* buf,
+                                               int buf_size,
+                                               int* bytes_read) {
   net::URLRequestStatus status = ReadNetData(buf, buf_size, bytes_read);
   SetStatus(status);
   if (status.is_io_pending())
     return false;
 
-  // No more data to process, the job is complete.
-  io_buffer_ = NULL;
-  version_->script_cache_map()->NotifyFinishedCaching(
-      url_, writer_->amount_written(), status, std::string());
-  did_notify_finished_ = true;
+  if (!status.is_success()) {
+    AsyncNotifyDoneHelper(status, kFetchScriptError);
+    return false;
+  }
+
+  DCHECK_EQ(0, *bytes_read);
+  consumer_->HandleData(buf, 0);
+  if (did_notify_finished_)
+    return GetStatus().is_success();
+  if (GetStatus().is_io_pending())
+    return false;
   return status.is_success();
 }
 
@@ -190,12 +458,12 @@
 net::URLRequestStatus ServiceWorkerWriteToCacheJob::ReadNetData(
     net::IOBuffer* buf,
     int buf_size,
-    int *bytes_read) {
+    int* bytes_read) {
   DCHECK_GT(buf_size, 0);
   DCHECK(bytes_read);
-
   *bytes_read = 0;
   io_buffer_ = buf;
+  io_buffer_bytes_ = 0;
   int net_bytes_read = 0;
   if (!net_request_->Read(buf, buf_size, &net_bytes_read)) {
     if (net_request_->status().is_io_pending())
@@ -205,7 +473,7 @@
   }
 
   if (net_bytes_read != 0) {
-    WriteDataToCache(net_bytes_read);
+    HandleNetData(net_bytes_read);
     DCHECK(GetStatus().is_io_pending());
     return GetStatus();
   }
@@ -214,7 +482,7 @@
   return net_request_->status();
 }
 
-void ServiceWorkerWriteToCacheJob::WriteHeadersToCache() {
+void ServiceWorkerWriteToCacheJob::WriteHeaders(const base::Closure& callback) {
   if (!context_) {
     AsyncNotifyDoneHelper(
         net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
@@ -223,20 +491,20 @@
   }
   TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker",
                                "ServiceWorkerWriteToCacheJob::ExecutingJob",
-                               this,
-                               "WriteHeadersToCache");
+                               this, "WriteHeaders");
   writer_ = context_->storage()->CreateResponseWriter(response_id_);
-  info_buffer_ = new HttpResponseInfoIOBuffer(
-      new net::HttpResponseInfo(net_request_->response_info()));
+  scoped_refptr<HttpResponseInfoIOBuffer> info_buffer =
+      new HttpResponseInfoIOBuffer(
+          new net::HttpResponseInfo(net_request_->response_info()));
   writer_->WriteInfo(
-      info_buffer_.get(),
+      info_buffer.get(),
       base::Bind(&ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete,
-                 weak_factory_.GetWeakPtr()));
-  SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
+                 weak_factory_.GetWeakPtr(), callback));
 }
 
-void ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete(int result) {
-  SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status
+void ServiceWorkerWriteToCacheJob::OnWriteHeadersComplete(
+    const base::Closure& callback,
+    int result) {
   if (result < 0) {
     ServiceWorkerMetrics::CountWriteResponseResult(
         ServiceWorkerMetrics::WRITE_HEADERS_ERROR);
@@ -245,33 +513,31 @@
         kFetchScriptError);
     return;
   }
-  http_info_.reset(info_buffer_->http_info.release());
-  info_buffer_ = NULL;
   TRACE_EVENT_ASYNC_STEP_INTO0("ServiceWorker",
                                "ServiceWorkerWriteToCacheJob::ExecutingJob",
-                               this,
-                               "WriteHeadersToCacheCompleted");
-  NotifyHeadersComplete();
+                               this, "WriteHeadersCompleted");
+  callback.Run();
 }
 
-void ServiceWorkerWriteToCacheJob::WriteDataToCache(int amount_to_write) {
-  DCHECK_NE(0, amount_to_write);
-  TRACE_EVENT_ASYNC_STEP_INTO1("ServiceWorker",
-                               "ServiceWorkerWriteToCacheJob::ExecutingJob",
-                               this,
-                               "WriteDataToCache",
-                               "Amount to write", amount_to_write);
-  SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
+void ServiceWorkerWriteToCacheJob::WriteData(
+    net::IOBuffer* buf,
+    int bytes_to_write,
+    const base::Callback<void(int result)>& callback) {
+  DCHECK_LT(0, bytes_to_write);
+  TRACE_EVENT_ASYNC_STEP_INTO1(
+      "ServiceWorker", "ServiceWorkerWriteToCacheJob::ExecutingJob", this,
+      "WriteData", "Amount to write", bytes_to_write);
+
   writer_->WriteData(
-      io_buffer_.get(),
-      amount_to_write,
+      buf, bytes_to_write,
       base::Bind(&ServiceWorkerWriteToCacheJob::OnWriteDataComplete,
-                 weak_factory_.GetWeakPtr()));
+                 weak_factory_.GetWeakPtr(), callback));
 }
 
-void ServiceWorkerWriteToCacheJob::OnWriteDataComplete(int result) {
+void ServiceWorkerWriteToCacheJob::OnWriteDataComplete(
+    const base::Callback<void(int result)>& callback,
+    int result) {
   DCHECK_NE(0, result);
-  io_buffer_ = NULL;
   if (!context_) {
     AsyncNotifyDoneHelper(
         net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
@@ -288,11 +554,9 @@
   }
   ServiceWorkerMetrics::CountWriteResponseResult(
       ServiceWorkerMetrics::WRITE_OK);
-  SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status
-  NotifyReadComplete(result);
+  callback.Run(result);
   TRACE_EVENT_ASYNC_END0("ServiceWorker",
-                         "ServiceWorkerWriteToCacheJob::ExecutingJob",
-                         this);
+                         "ServiceWorkerWriteToCacheJob::ExecutingJob", this);
 }
 
 void ServiceWorkerWriteToCacheJob::OnReceivedRedirect(
@@ -411,7 +675,17 @@
   if (net_request_->response_info().network_accessed)
     version_->embedded_worker()->OnNetworkAccessedForScriptLoad();
 
-  WriteHeadersToCache();
+  consumer_->OnResponseStarted();
+}
+
+void ServiceWorkerWriteToCacheJob::CommitHeadersAndNotifyHeadersComplete() {
+  http_info_.reset(new net::HttpResponseInfo(net_request_->response_info()));
+  NotifyHeadersComplete();
+}
+
+void ServiceWorkerWriteToCacheJob::HandleNetData(int bytes_read) {
+  io_buffer_bytes_ = bytes_read;
+  consumer_->HandleData(io_buffer_.get(), bytes_read);
 }
 
 void ServiceWorkerWriteToCacheJob::OnReadCompleted(
@@ -424,17 +698,14 @@
     return;
   }
   if (bytes_read > 0) {
-    WriteDataToCache(bytes_read);
+    HandleNetData(bytes_read);
+    DCHECK(GetStatus().is_io_pending());
     return;
   }
+
   // No more data to process, the job is complete.
   DCHECK(request->status().is_success());
-  io_buffer_ = NULL;
-  version_->script_cache_map()->NotifyFinishedCaching(
-      url_, writer_->amount_written(), net::URLRequestStatus(), std::string());
-  did_notify_finished_ = true;
-  SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status
-  NotifyReadComplete(0);
+  HandleNetData(0);
 }
 
 bool ServiceWorkerWriteToCacheJob::CheckPathRestriction(
@@ -456,20 +727,99 @@
   return true;
 }
 
+void ServiceWorkerWriteToCacheJob::SetPendingIO() {
+  SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
+}
+
+void ServiceWorkerWriteToCacheJob::ClearPendingIO() {
+  SetStatus(net::URLRequestStatus());
+}
+
+void ServiceWorkerWriteToCacheJob::OnPassThroughComplete() {
+  NotifyFinishedCaching(net::URLRequestStatus(), std::string());
+  if (GetStatus().is_io_pending()) {
+    ClearPendingIO();
+    NotifyReadComplete(0);
+  }
+}
+
+void ServiceWorkerWriteToCacheJob::OnCompareComplete(int bytes_matched,
+                                                     bool is_equal) {
+  if (is_equal) {
+    // This version is identical to the incumbent, so discard it and fail this
+    // job.
+    version_->SetStartWorkerStatusCode(SERVICE_WORKER_ERROR_EXISTS);
+    AsyncNotifyDoneHelper(
+        net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
+        kFetchScriptError);
+    return;
+  }
+
+  // We must switch to the pass through consumer. Write what is known
+  // (headers + bytes matched) to disk.
+  WriteHeaders(base::Bind(&ServiceWorkerWriteToCacheJob::CopyIncumbent,
+                          weak_factory_.GetWeakPtr(), bytes_matched));
+  SetPendingIO();
+}
+
+void ServiceWorkerWriteToCacheJob::CopyIncumbent(int bytes_to_copy) {
+  if (bytes_to_copy == 0) {
+    OnCopyComplete(SERVICE_WORKER_OK);
+    return;
+  }
+  scoped_ptr<ServiceWorkerResponseReader> incumbent_reader =
+      context_->storage()->CreateResponseReader(incumbent_response_id_);
+  scoped_refptr<Copier> copier = new Copier(
+      weak_factory_.GetWeakPtr(), incumbent_reader.Pass(), bytes_to_copy,
+      base::Bind(&ServiceWorkerWriteToCacheJob::OnCopyComplete,
+                 weak_factory_.GetWeakPtr()));
+  copier->Start();  // It deletes itself when done.
+  DCHECK(GetStatus().is_io_pending());
+}
+
+void ServiceWorkerWriteToCacheJob::OnCopyComplete(
+    ServiceWorkerStatusCode status) {
+  if (status != SERVICE_WORKER_OK) {
+    AsyncNotifyDoneHelper(
+        net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED),
+        kFetchScriptError);
+    return;
+  }
+
+  // Continue processing the net data that triggered the comparison fail and
+  // copy.
+  if (io_buffer_bytes_ > 0) {
+    consumer_.reset(new PassThroughConsumer(this));
+    consumer_->HandleData(io_buffer_.get(), io_buffer_bytes_);
+    return;
+  }
+
+  // The copy was triggered by EOF from the network, which
+  // means the job is now done.
+  NotifyFinishedCaching(net::URLRequestStatus(), std::string());
+  ClearPendingIO();
+  NotifyReadComplete(0);
+}
+
 void ServiceWorkerWriteToCacheJob::AsyncNotifyDoneHelper(
     const net::URLRequestStatus& status,
     const std::string& status_message) {
   DCHECK(!status.is_io_pending());
+  NotifyFinishedCaching(status, status_message);
+  SetStatus(status);
+  NotifyDone(status);
+}
+
+void ServiceWorkerWriteToCacheJob::NotifyFinishedCaching(
+    net::URLRequestStatus status,
+    const std::string& status_message) {
   DCHECK(!did_notify_finished_);
   int size = -1;
-  if (writer_.get()) {
-    size = writer_->amount_written();
-  }
+  if (status.is_success())
+    size = writer_ ? writer_->amount_written() : 0;
   version_->script_cache_map()->NotifyFinishedCaching(url_, size, status,
                                                       status_message);
   did_notify_finished_ = true;
-  SetStatus(status);
-  NotifyDone(status);
 }
 
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_write_to_cache_job.h b/content/browser/service_worker/service_worker_write_to_cache_job.h
index 507b78b..38b040d 100644
--- a/content/browser/service_worker/service_worker_write_to_cache_job.h
+++ b/content/browser/service_worker/service_worker_write_to_cache_job.h
@@ -30,18 +30,25 @@
 // request is written to the service worker script cache and piped
 // to the consumer of the ServiceWorkerWriteToCacheJob for delivery
 // to the renderer process housing the worker.
+//
+// For updates, the main script is not written to disk until a change with the
+// incumbent script is detected. The incumbent script is progressively compared
+// with the new script as it is read from network. Once a change is detected,
+// everything that matched is copied to disk, and from then on the script is
+// written as it continues to be read from network. If the scripts were
+// identical, the job fails so the worker can be discarded.
 class CONTENT_EXPORT ServiceWorkerWriteToCacheJob
     : public net::URLRequestJob,
       public net::URLRequest::Delegate {
  public:
-  ServiceWorkerWriteToCacheJob(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate,
-      ResourceType resource_type,
-      base::WeakPtr<ServiceWorkerContextCore> context,
-      ServiceWorkerVersion* version,
-      int extra_load_flags,
-      int64 response_id);
+  ServiceWorkerWriteToCacheJob(net::URLRequest* request,
+                               net::NetworkDelegate* network_delegate,
+                               ResourceType resource_type,
+                               base::WeakPtr<ServiceWorkerContextCore> context,
+                               ServiceWorkerVersion* version,
+                               int extra_load_flags,
+                               int64 response_id,
+                               int64 incumbent_response_id);
 
  private:
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
@@ -50,6 +57,10 @@
                            UpdateAfter24Hours);
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
                            UpdateForceBypassCache);
+  class NetDataConsumer;
+  class PassThroughConsumer;
+  class Comparer;
+  class Copier;
 
   ~ServiceWorkerWriteToCacheJob() override;
 
@@ -70,14 +81,18 @@
   // write data to the disk cache.
   void InitNetRequest(int extra_load_flags);
   void StartNetRequest();
-  net::URLRequestStatus ReadNetData(
-      net::IOBuffer* buf,
-      int buf_size,
-      int *bytes_read);
-  void WriteHeadersToCache();
-  void OnWriteHeadersComplete(int result);
-  void WriteDataToCache(int bytes_to_write);
-  void OnWriteDataComplete(int result);
+  net::URLRequestStatus ReadNetData(net::IOBuffer* buf,
+                                    int buf_size,
+                                    int* bytes_read);
+
+  void CommitHeadersAndNotifyHeadersComplete();
+  void WriteHeaders(const base::Closure& callback);
+  void OnWriteHeadersComplete(const base::Closure& callback, int result);
+  void WriteData(net::IOBuffer* buf,
+                 int amount_to_write,
+                 const base::Callback<void(int result)>& callback);
+  void OnWriteDataComplete(const base::Callback<void(int result)>& callback,
+                           int result);
 
   // net::URLRequest::Delegate overrides that observe the net request.
   void OnReceivedRedirect(net::URLRequest* request,
@@ -97,19 +112,32 @@
 
   bool CheckPathRestriction(net::URLRequest* request);
 
+  void SetPendingIO();
+  void ClearPendingIO();
+  void OnPassThroughComplete();
+  void OnCompareComplete(int bytes_matched, bool is_equal);
+  void CopyIncumbent(int bytes_to_copy);
+  void OnCopyComplete(ServiceWorkerStatusCode status);
+  void HandleNetData(int bytes_read);
+
   void AsyncNotifyDoneHelper(const net::URLRequestStatus& status,
                              const std::string& status_message);
 
+  void NotifyFinishedCaching(net::URLRequestStatus status,
+                             const std::string& status_message);
+
   ResourceType resource_type_;  // Differentiate main script and imports
   scoped_refptr<net::IOBuffer> io_buffer_;
-  scoped_refptr<HttpResponseInfoIOBuffer> info_buffer_;
+  int io_buffer_bytes_;
   base::WeakPtr<ServiceWorkerContextCore> context_;
   GURL url_;
   int64 response_id_;
+  int64 incumbent_response_id_;
   scoped_ptr<net::URLRequest> net_request_;
   scoped_ptr<net::HttpResponseInfo> http_info_;
   scoped_ptr<ServiceWorkerResponseWriter> writer_;
   scoped_refptr<ServiceWorkerVersion> version_;
+  scoped_ptr<NetDataConsumer> consumer_;
   bool has_been_killed_;
   bool did_notify_started_;
   bool did_notify_finished_;
diff --git a/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc b/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
index cd90d45..7f6aabc 100644
--- a/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_write_to_cache_job_unittest.cc
@@ -2,17 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/fileapi/mock_url_request_delegate.h"
 #include "content/browser/service_worker/embedded_worker_test_helper.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_context_request_handler.h"
+#include "content/browser/service_worker/service_worker_disk_cache.h"
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/browser/service_worker/service_worker_registration.h"
+#include "content/browser/service_worker/service_worker_test_utils.h"
 #include "content/browser/service_worker/service_worker_utils.h"
 #include "content/common/resource_request_body.h"
 #include "content/public/test/mock_resource_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "net/base/io_buffer.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_response_headers.h"
 #include "net/url_request/url_request_context.h"
@@ -26,8 +32,6 @@
 
 namespace {
 
-int kMockRenderProcessId = 1224;
-int kMockProviderId = 1;
 const char kHeaders[] =
     "HTTP/1.1 200 OK\0"
     "Content-Type: text/javascript\0"
@@ -38,6 +42,14 @@
 void EmptyCallback() {
 }
 
+// The blocksize that ServiceWorkerWriteToCacheJob reads/writes at a time.
+const int kBlockSize = 16 * 1024;
+const int kNumBlocks = 8;
+const int kMiddleBlock = 5;
+
+std::string GenerateLongResponse() {
+  return std::string(kNumBlocks * kBlockSize, 'a');
+}
 net::URLRequestJob* CreateNormalURLRequestJob(
     net::URLRequest* request,
     net::NetworkDelegate* network_delegate) {
@@ -48,6 +60,14 @@
                                     true);
 }
 
+net::URLRequestJob* CreateResponseJob(const std::string& response_data,
+                                      net::URLRequest* request,
+                                      net::NetworkDelegate* network_delegate) {
+  return new net::URLRequestTestJob(request, network_delegate,
+                                    std::string(kHeaders, arraysize(kHeaders)),
+                                    response_data, true);
+}
+
 net::URLRequestJob* CreateInvalidMimeTypeJob(
     net::URLRequest* request,
     net::NetworkDelegate* network_delegate) {
@@ -78,10 +98,9 @@
                                auto_advance),
         weak_factory_(this) {}
   void Start() override {
-    base::MessageLoop::current()->PostTask(
-        FROM_HERE,
-        base::Bind(&SSLCertificateErrorJob::NotifyError,
-                   weak_factory_.GetWeakPtr()));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&SSLCertificateErrorJob::NotifyError,
+                              weak_factory_.GetWeakPtr()));
   }
   void NotifyError() {
     net::SSLInfo info;
@@ -141,7 +160,7 @@
   typedef base::Callback<
       net::URLRequestJob*(net::URLRequest*, net::NetworkDelegate*)> JobCallback;
 
-  MockHttpProtocolHandler(ResourceContext* resource_context)
+  explicit MockHttpProtocolHandler(ResourceContext* resource_context)
       : resource_context_(resource_context) {}
   ~MockHttpProtocolHandler() override {}
 
@@ -164,7 +183,72 @@
   ResourceContext* resource_context_;
   JobCallback create_job_callback_;
 };
-}
+
+class ResponseVerifier : public base::RefCounted<ResponseVerifier> {
+ public:
+  ResponseVerifier(scoped_ptr<ServiceWorkerResponseReader> reader,
+                   const std::string& expected,
+                   const base::Callback<void(bool)> callback)
+      : reader_(reader.release()), expected_(expected), callback_(callback) {}
+
+  void Start() {
+    info_buffer_ = new HttpResponseInfoIOBuffer();
+    io_buffer_ = new net::IOBuffer(kBlockSize);
+    reader_->ReadInfo(info_buffer_.get(),
+                      base::Bind(&ResponseVerifier::OnReadInfoComplete, this));
+    bytes_read_ = 0;
+  }
+
+  void OnReadInfoComplete(int result) {
+    if (result < 0) {
+      callback_.Run(false);
+      return;
+    }
+    if (info_buffer_->response_data_size !=
+        static_cast<int>(expected_.size())) {
+      callback_.Run(false);
+      return;
+    }
+    ReadSomeData();
+  }
+
+  void ReadSomeData() {
+    reader_->ReadData(io_buffer_.get(), kBlockSize,
+                      base::Bind(&ResponseVerifier::OnReadDataComplete, this));
+  }
+
+  void OnReadDataComplete(int result) {
+    if (result < 0) {
+      callback_.Run(false);
+      return;
+    }
+    if (result == 0) {
+      callback_.Run(true);
+      return;
+    }
+    std::string str(io_buffer_->data(), result);
+    std::string expect = expected_.substr(bytes_read_, result);
+    if (str != expect) {
+      callback_.Run(false);
+      return;
+    }
+    bytes_read_ += result;
+    ReadSomeData();
+  }
+
+ private:
+  friend class base::RefCounted<ResponseVerifier>;
+  ~ResponseVerifier() {}
+
+  scoped_ptr<ServiceWorkerResponseReader> reader_;
+  const std::string expected_;
+  base::Callback<void(bool)> callback_;
+  scoped_refptr<HttpResponseInfoIOBuffer> info_buffer_;
+  scoped_refptr<net::IOBuffer> io_buffer_;
+  size_t bytes_read_;
+};
+
+}  // namespace
 
 class ServiceWorkerWriteToCacheJobTest : public testing::Test {
  public:
@@ -173,27 +257,24 @@
         mock_protocol_handler_(nullptr) {}
   ~ServiceWorkerWriteToCacheJobTest() override {}
 
-  void SetUp() override {
-    helper_.reset(
-        new EmbeddedWorkerTestHelper(base::FilePath(), kMockRenderProcessId));
-
-    // A new unstored registration/version.
-    scope_ = GURL("https://host/scope/");
-    script_url_ = GURL("https://host/script.js");
-    registration_ =
-        new ServiceWorkerRegistration(scope_, 1L, context()->AsWeakPtr());
-    version_ = new ServiceWorkerVersion(
-        registration_.get(), script_url_, 1L, context()->AsWeakPtr());
-
-    // An empty host.
+  void CreateHostForVersion(
+      int process_id,
+      int provider_id,
+      const scoped_refptr<ServiceWorkerVersion>& version) {
     scoped_ptr<ServiceWorkerProviderHost> host(new ServiceWorkerProviderHost(
-        kMockRenderProcessId, MSG_ROUTING_NONE, kMockProviderId,
-        SERVICE_WORKER_PROVIDER_FOR_WINDOW, context()->AsWeakPtr(), nullptr));
-    provider_host_ = host->AsWeakPtr();
+        process_id, MSG_ROUTING_NONE, provider_id,
+        SERVICE_WORKER_PROVIDER_FOR_WORKER, context()->AsWeakPtr(), nullptr));
+    base::WeakPtr<ServiceWorkerProviderHost> provider_host = host->AsWeakPtr();
     context()->AddProviderHost(host.Pass());
-    provider_host_->running_hosted_version_ = version_;
+    provider_host->running_hosted_version_ = version;
+  }
 
-    context()->storage()->LazyInitialize(base::Bind(&EmptyCallback));
+  void SetUpScriptRequest(int process_id, int provider_id) {
+    request_.reset();
+    url_request_context_.reset();
+    url_request_job_factory_.reset();
+    mock_protocol_handler_ = nullptr;
+    // URLRequestJobs may post clean-up tasks on destruction.
     base::RunLoop().RunUntilIdle();
 
     url_request_context_.reset(new net::URLRequestContext);
@@ -206,20 +287,38 @@
     request_ = url_request_context_->CreateRequest(
         script_url_, net::DEFAULT_PRIORITY, &url_request_delegate_);
     ServiceWorkerRequestHandler::InitializeHandler(
-        request_.get(),
-        context_wrapper(),
-        &blob_storage_context_,
-        kMockRenderProcessId,
-        kMockProviderId,
-        false,
-        FETCH_REQUEST_MODE_NO_CORS,
-        FETCH_CREDENTIALS_MODE_OMIT,
-        RESOURCE_TYPE_SERVICE_WORKER,
-        REQUEST_CONTEXT_TYPE_SERVICE_WORKER,
-        REQUEST_CONTEXT_FRAME_TYPE_NONE,
+        request_.get(), context_wrapper(), &blob_storage_context_, process_id,
+        provider_id, false, FETCH_REQUEST_MODE_NO_CORS,
+        FETCH_CREDENTIALS_MODE_OMIT, RESOURCE_TYPE_SERVICE_WORKER,
+        REQUEST_CONTEXT_TYPE_SERVICE_WORKER, REQUEST_CONTEXT_FRAME_TYPE_NONE,
         scoped_refptr<ResourceRequestBody>());
   }
 
+  int NextRenderProcessId() { return next_render_process_id_++; }
+  int NextProviderId() { return next_provider_id_++; }
+  int NextVersionId() { return next_version_id_++; }
+
+  void SetUp() override {
+    int render_process_id = NextRenderProcessId();
+    int provider_id = NextProviderId();
+    helper_.reset(
+        new EmbeddedWorkerTestHelper(base::FilePath(), render_process_id));
+
+    // A new unstored registration/version.
+    scope_ = GURL("https://host/scope/");
+    script_url_ = GURL("https://host/script.js");
+    registration_ =
+        new ServiceWorkerRegistration(scope_, 1L, context()->AsWeakPtr());
+    version_ =
+        new ServiceWorkerVersion(registration_.get(), script_url_,
+                                 NextVersionId(), context()->AsWeakPtr());
+    CreateHostForVersion(render_process_id, provider_id, version_);
+    SetUpScriptRequest(render_process_id, provider_id);
+
+    context()->storage()->LazyInitialize(base::Bind(&EmptyCallback));
+    base::RunLoop().RunUntilIdle();
+  }
+
   void TearDown() override {
     request_.reset();
     url_request_context_.reset();
@@ -232,6 +331,63 @@
     base::RunLoop().RunUntilIdle();
   }
 
+  int CreateIncumbent(const std::string& response) {
+    mock_protocol_handler_->SetCreateJobCallback(
+        base::Bind(&CreateResponseJob, response));
+    request_->Start();
+    base::RunLoop().RunUntilIdle();
+    EXPECT_EQ(net::URLRequestStatus::SUCCESS, request_->status().status());
+    int incumbent_resource_id =
+        version_->script_cache_map()->LookupResourceId(script_url_);
+    EXPECT_NE(kInvalidServiceWorkerResponseId, incumbent_resource_id);
+
+    registration_->SetActiveVersion(version_);
+
+    // Teardown the request.
+    request_.reset();
+    url_request_context_.reset();
+    url_request_job_factory_.reset();
+    mock_protocol_handler_ = nullptr;
+    base::RunLoop().RunUntilIdle();
+
+    return incumbent_resource_id;
+  }
+
+  int GetResourceId(ServiceWorkerVersion* version) {
+    return version->script_cache_map()->LookupResourceId(script_url_);
+  }
+
+  // Performs the net request for an update of |registration_|'s incumbent
+  // to the script |response|. Returns the new version.
+  scoped_refptr<ServiceWorkerVersion> UpdateScript(
+      const std::string& response) {
+    int render_process_id = NextRenderProcessId();
+    int provider_id = NextProviderId();
+    scoped_refptr<ServiceWorkerVersion> new_version =
+        new ServiceWorkerVersion(registration_.get(), script_url_,
+                                 NextVersionId(), context()->AsWeakPtr());
+    CreateHostForVersion(render_process_id, provider_id, new_version);
+
+    SetUpScriptRequest(render_process_id, provider_id);
+    mock_protocol_handler_->SetCreateJobCallback(
+        base::Bind(&CreateResponseJob, response));
+    request_->Start();
+    base::RunLoop().RunUntilIdle();
+    return new_version;
+  }
+
+  void VerifyResource(int id, const std::string& expected) {
+    ASSERT_NE(kInvalidServiceWorkerResourceId, id);
+    bool is_equal = false;
+    scoped_ptr<ServiceWorkerResponseReader> reader =
+        context()->storage()->CreateResponseReader(id);
+    scoped_refptr<ResponseVerifier> verifier = new ResponseVerifier(
+        reader.Pass(), expected, CreateReceiverOnCurrentThread(&is_equal));
+    verifier->Start();
+    base::RunLoop().RunUntilIdle();
+    EXPECT_TRUE(is_equal);
+  }
+
   ServiceWorkerContextCore* context() const { return helper_->context(); }
   ServiceWorkerContextWrapper* context_wrapper() const {
     return helper_->context_wrapper();
@@ -254,6 +410,10 @@
   MockURLRequestDelegate url_request_delegate_;
   GURL scope_;
   GURL script_url_;
+
+  int next_render_process_id_ = 1224;  // dummy value
+  int next_provider_id_ = 1;
+  int64 next_version_id_ = 1L;
 };
 
 TEST_F(ServiceWorkerWriteToCacheJobTest, Normal) {
@@ -299,4 +459,118 @@
             version_->script_cache_map()->LookupResourceId(script_url_));
 }
 
+TEST_F(ServiceWorkerWriteToCacheJobTest, Update_SameScript) {
+  std::string response = GenerateLongResponse();
+  CreateIncumbent(response);
+  scoped_refptr<ServiceWorkerVersion> version = UpdateScript(response);
+  EXPECT_EQ(kInvalidServiceWorkerResponseId, GetResourceId(version.get()));
+}
+
+TEST_F(ServiceWorkerWriteToCacheJobTest, Update_SameSizeScript) {
+  std::string response = GenerateLongResponse();
+  CreateIncumbent(response);
+
+  // Change the first byte.
+  response[0] = 'x';
+  scoped_refptr<ServiceWorkerVersion> version = UpdateScript(response);
+  VerifyResource(GetResourceId(version.get()), response);
+  registration_->SetWaitingVersion(version);
+
+  // Change something within the first block.
+  response[5555] = 'x';
+  version = UpdateScript(response);
+  VerifyResource(GetResourceId(version.get()), response);
+  registration_->SetWaitingVersion(version);
+
+  // Change something in a middle block.
+  response[kMiddleBlock * kBlockSize + 111] = 'x';
+  version = UpdateScript(response);
+  VerifyResource(GetResourceId(version.get()), response);
+  registration_->SetWaitingVersion(version);
+
+  // Change something within the last block.
+  response[(kNumBlocks - 1) * kBlockSize] = 'x';
+  version = UpdateScript(response);
+  VerifyResource(GetResourceId(version.get()), response);
+  registration_->SetWaitingVersion(version);
+
+  // Change the last byte.
+  response[(kNumBlocks * kBlockSize) - 1] = 'x';
+  version = UpdateScript(response);
+  VerifyResource(GetResourceId(version.get()), response);
+  registration_->SetWaitingVersion(version);
+}
+
+TEST_F(ServiceWorkerWriteToCacheJobTest, Update_TruncatedScript) {
+  std::string response = GenerateLongResponse();
+  CreateIncumbent(response);
+
+  // Truncate a single byte.
+  response.resize(response.size() - 1);
+  scoped_refptr<ServiceWorkerVersion> version = UpdateScript(response);
+  VerifyResource(GetResourceId(version.get()), response);
+  registration_->SetWaitingVersion(version);
+
+  // Truncate to a middle block.
+  response.resize((kMiddleBlock + 1) * kBlockSize + 111);
+  version = UpdateScript(response);
+  VerifyResource(GetResourceId(version.get()), response);
+  registration_->SetWaitingVersion(version);
+
+  // Truncate to a block boundary.
+  response.resize((kMiddleBlock - 1) * kBlockSize);
+  version = UpdateScript(response);
+  VerifyResource(GetResourceId(version.get()), response);
+  registration_->SetWaitingVersion(version);
+
+  // Truncate to a single byte.
+  response.resize(1);
+  version = UpdateScript(response);
+  VerifyResource(GetResourceId(version.get()), response);
+  registration_->SetWaitingVersion(version);
+}
+
+TEST_F(ServiceWorkerWriteToCacheJobTest, Update_ElongatedScript) {
+  std::string original_response = GenerateLongResponse();
+  CreateIncumbent(original_response);
+
+  // Extend a single byte.
+  std::string new_response = original_response + 'a';
+  scoped_refptr<ServiceWorkerVersion> version = UpdateScript(new_response);
+  VerifyResource(GetResourceId(version.get()), new_response);
+  registration_->SetWaitingVersion(version);
+
+  // Extend multiple blocks.
+  new_response = original_response + std::string(3 * kBlockSize, 'a');
+  version = UpdateScript(new_response);
+  VerifyResource(GetResourceId(version.get()), new_response);
+  registration_->SetWaitingVersion(version);
+
+  // Extend multiple blocks and bytes.
+  new_response = original_response + std::string(7 * kBlockSize + 777, 'a');
+  version = UpdateScript(new_response);
+  VerifyResource(GetResourceId(version.get()), new_response);
+  registration_->SetWaitingVersion(version);
+}
+
+TEST_F(ServiceWorkerWriteToCacheJobTest, Update_EmptyScript) {
+  // Create empty incumbent.
+  CreateIncumbent(std::string());
+
+  // Update from empty to non-empty.
+  std::string response = GenerateLongResponse();
+  scoped_refptr<ServiceWorkerVersion> version = UpdateScript(response);
+  VerifyResource(GetResourceId(version.get()), response);
+  registration_->SetWaitingVersion(version);
+
+  // Update from non-empty to empty.
+  version = UpdateScript(std::string());
+  VerifyResource(GetResourceId(version.get()), std::string());
+  registration_->SetWaitingVersion(version);
+
+  // Update from empty to empty.
+  version = UpdateScript(std::string());
+  EXPECT_EQ(kInvalidServiceWorkerResponseId, GetResourceId(version.get()));
+}
+
 }  // namespace content
diff --git a/content/browser/shareable_file_reference_unittest.cc b/content/browser/shareable_file_reference_unittest.cc
index 84d035f..c2dae30f 100644
--- a/content/browser/shareable_file_reference_unittest.cc
+++ b/content/browser/shareable_file_reference_unittest.cc
@@ -6,8 +6,9 @@
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using storage::ShareableFileReference;
@@ -16,8 +17,8 @@
 
 TEST(ShareableFileReferenceTest, TestReferences) {
   base::MessageLoop message_loop;
-  scoped_refptr<base::MessageLoopProxy> loop_proxy =
-      base::MessageLoopProxy::current();
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+      base::ThreadTaskRunnerHandle::Get();
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
@@ -31,7 +32,7 @@
   reference1 = ShareableFileReference::Get(file);
   EXPECT_FALSE(reference1.get());
   reference1 = ShareableFileReference::GetOrCreate(
-      file, ShareableFileReference::DELETE_ON_FINAL_RELEASE, loop_proxy.get());
+      file, ShareableFileReference::DELETE_ON_FINAL_RELEASE, task_runner.get());
   EXPECT_TRUE(reference1.get());
   EXPECT_TRUE(file == reference1->path());
 
@@ -40,7 +41,7 @@
   reference2 = ShareableFileReference::Get(file);
   EXPECT_EQ(reference1.get(), reference2.get());
   reference2 = ShareableFileReference::GetOrCreate(
-      file, ShareableFileReference::DELETE_ON_FINAL_RELEASE, loop_proxy.get());
+      file, ShareableFileReference::DELETE_ON_FINAL_RELEASE, task_runner.get());
   EXPECT_EQ(reference1.get(), reference2.get());
 
   // Drop the first reference, the file and reference should still be there.
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 282141a..39effd92 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -8,8 +8,11 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/frame_host/cross_process_frame_connector.h"
 #include "content/browser/frame_host/frame_tree.h"
 #include "content/browser/frame_host/navigator.h"
@@ -431,7 +434,7 @@
     // TODO(lazyboy): Find a better way to avoid sleeping like this. See
     // http://crbug.com/405282 for details.
     base::RunLoop run_loop;
-    base::MessageLoop::current()->PostDelayedTask(
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, run_loop.QuitClosure(),
         base::TimeDelta::FromMilliseconds(10));
     run_loop.Run();
@@ -1007,8 +1010,6 @@
   FrameTreeNode* root =
       static_cast<WebContentsImpl*>(shell()->web_contents())->
           GetFrameTree()->root();
-  TestNavigationObserver observer(shell()->web_contents());
-
   ASSERT_EQ(2U, root->child_count());
 
   GURL site_b_url(
diff --git a/content/browser/speech/speech_recognition_browsertest.cc b/content/browser/speech/speech_recognition_browsertest.cc
index 8bc0749f..ee5e28e 100644
--- a/content/browser/speech/speech_recognition_browsertest.cc
+++ b/content/browser/speech/speech_recognition_browsertest.cc
@@ -5,9 +5,12 @@
 #include <list>
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/speech/google_streaming_remote_engine.h"
 #include "content/browser/speech/speech_recognition_manager_impl.h"
 #include "content/browser/speech/speech_recognizer_impl.h"
@@ -166,11 +169,11 @@
 
     const int n_buffers = duration_ms / ms_per_buffer;
     for (int i = 0; i < n_buffers; ++i) {
-      base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
-          &FeedSingleBufferToAudioController,
-          scoped_refptr<media::TestAudioInputController>(controller),
-          buffer_size,
-          feed_with_noise));
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE,
+          base::Bind(&FeedSingleBufferToAudioController,
+                     scoped_refptr<media::TestAudioInputController>(controller),
+                     buffer_size, feed_with_noise));
     }
   }
 
diff --git a/content/browser/speech/speech_recognition_manager_impl.cc b/content/browser/speech/speech_recognition_manager_impl.cc
index f02c29f1..019abe1a 100644
--- a/content/browser/speech/speech_recognition_manager_impl.cc
+++ b/content/browser/speech/speech_recognition_manager_impl.cc
@@ -5,6 +5,9 @@
 #include "content/browser/speech/speech_recognition_manager_impl.h"
 
 #include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
@@ -210,21 +213,17 @@
   }
 
   if (is_allowed) {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&SpeechRecognitionManagerImpl::DispatchEvent,
-                   weak_factory_.GetWeakPtr(),
-                   session_id,
-                   EVENT_START));
+                   weak_factory_.GetWeakPtr(), session_id, EVENT_START));
   } else {
     OnRecognitionError(session_id, SpeechRecognitionError(
         SPEECH_RECOGNITION_ERROR_NOT_ALLOWED));
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&SpeechRecognitionManagerImpl::DispatchEvent,
-                   weak_factory_.GetWeakPtr(),
-                   session_id,
-                   EVENT_ABORT));
+                   weak_factory_.GetWeakPtr(), session_id, EVENT_ABORT));
   }
 }
 
@@ -267,12 +266,10 @@
 
   iter->second->abort_requested = true;
 
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&SpeechRecognitionManagerImpl::DispatchEvent,
-                 weak_factory_.GetWeakPtr(),
-                 session_id,
-                 EVENT_ABORT));
+                 weak_factory_.GetWeakPtr(), session_id, EVENT_ABORT));
 }
 
 void SpeechRecognitionManagerImpl::StopAudioCaptureForSession(int session_id) {
@@ -283,12 +280,10 @@
   SessionsTable::iterator iter = sessions_.find(session_id);
   iter->second->ui.reset();
 
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&SpeechRecognitionManagerImpl::DispatchEvent,
-                 weak_factory_.GetWeakPtr(),
-                 session_id,
-                 EVENT_STOP_CAPTURE));
+                 weak_factory_.GetWeakPtr(), session_id, EVENT_STOP_CAPTURE));
 }
 
 // Here begins the SpeechRecognitionEventListener interface implementation,
@@ -372,12 +367,10 @@
     delegate_listener->OnAudioEnd(session_id);
   if (SpeechRecognitionEventListener* listener = GetListener(session_id))
     listener->OnAudioEnd(session_id);
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&SpeechRecognitionManagerImpl::DispatchEvent,
-                 weak_factory_.GetWeakPtr(),
-                 session_id,
-                 EVENT_AUDIO_ENDED));
+                 weak_factory_.GetWeakPtr(), session_id, EVENT_AUDIO_ENDED));
 }
 
 void SpeechRecognitionManagerImpl::OnRecognitionResults(
@@ -425,12 +418,10 @@
     delegate_listener->OnRecognitionEnd(session_id);
   if (SpeechRecognitionEventListener* listener = GetListener(session_id))
     listener->OnRecognitionEnd(session_id);
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&SpeechRecognitionManagerImpl::DispatchEvent,
-                 weak_factory_.GetWeakPtr(),
-                 session_id,
-                 EVENT_RECOGNITION_ENDED));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&SpeechRecognitionManagerImpl::DispatchEvent,
+                            weak_factory_.GetWeakPtr(), session_id,
+                            EVENT_RECOGNITION_ENDED));
 }
 
 int SpeechRecognitionManagerImpl::GetSession(
diff --git a/content/browser/speech/speech_recognizer_impl_unittest.cc b/content/browser/speech/speech_recognizer_impl_unittest.cc
index ba6b06a..320ca81 100644
--- a/content/browser/speech/speech_recognizer_impl_unittest.cc
+++ b/content/browser/speech/speech_recognizer_impl_unittest.cc
@@ -19,7 +19,6 @@
 #include "net/url_request/url_request_status.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using base::MessageLoopProxy;
 using media::AudioInputController;
 using media::AudioInputStream;
 using media::AudioManager;
@@ -58,7 +57,7 @@
     recognizer_ = new SpeechRecognizerImpl(
         this, kTestingSessionId, false, false, sr_engine);
     audio_manager_.reset(new media::MockAudioManager(
-        base::MessageLoop::current()->message_loop_proxy().get()));
+        base::MessageLoop::current()->task_runner().get()));
     recognizer_->SetAudioManagerForTesting(audio_manager_.get());
 
     int audio_packet_length_bytes =
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 0545c3a..ceb2d235 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -7,7 +7,9 @@
 #include <set>
 #include <vector>
 
+#include "base/location.h"
 #include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/fileapi/browser_file_system_helper.h"
@@ -484,8 +486,10 @@
   base::SequencedTaskRunner* idb_task_runner =
       BrowserThread::CurrentlyOn(BrowserThread::UI) &&
               BrowserMainLoop::GetInstance()
-          ? BrowserMainLoop::GetInstance()->indexed_db_thread()
-                ->message_loop_proxy().get()
+          ? BrowserMainLoop::GetInstance()
+                ->indexed_db_thread()
+                ->task_runner()
+                .get()
           : NULL;
   scoped_refptr<IndexedDBContextImpl> indexed_db_context =
       new IndexedDBContextImpl(path,
diff --git a/content/browser/storage_partition_impl_map.cc b/content/browser/storage_partition_impl_map.cc
index 7ba28d7..8b99d042 100644
--- a/content/browser/storage_partition_impl_map.cc
+++ b/content/browser/storage_partition_impl_map.cc
@@ -9,10 +9,13 @@
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "content/browser/appcache/appcache_interceptor.h"
 #include "content/browser/appcache/chrome_appcache_service.h"
@@ -521,7 +524,7 @@
       FROM_HERE,
       base::Bind(&BlockingObliteratePath, browser_context_->GetPath(),
                  domain_root, paths_to_keep,
-                 base::MessageLoopProxy::current(), on_gc_required));
+                 base::ThreadTaskRunnerHandle::Get(), on_gc_required));
 }
 
 void StoragePartitionImplMap::GarbageCollect(
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc
index a2950c8..79e33beb2 100644
--- a/content/browser/storage_partition_impl_unittest.cc
+++ b/content/browser/storage_partition_impl_unittest.cc
@@ -3,8 +3,10 @@
 // found in the LICENSE file.
 
 #include "base/files/file_util.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/gpu/shader_disk_cache.h"
@@ -403,11 +405,11 @@
   EXPECT_EQ(1u, Size());
 
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(
-          &ClearData,
-          BrowserContext::GetDefaultStoragePartition(browser_context()),
-          &run_loop));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&ClearData,
+                 BrowserContext::GetDefaultStoragePartition(browser_context()),
+                 &run_loop));
   run_loop.Run();
   EXPECT_EQ(0u, Size());
 }
@@ -475,7 +477,7 @@
       GetMockManager());
 
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&ClearQuotaData, partition, &run_loop));
   run_loop.Run();
 
@@ -502,7 +504,7 @@
       GetMockManager());
 
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&ClearQuotaData, partition, &run_loop));
   run_loop.Run();
 
@@ -529,7 +531,7 @@
       GetMockManager());
 
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&ClearQuotaData, partition, &run_loop));
   run_loop.Run();
 
@@ -554,7 +556,7 @@
       GetMockManager());
 
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&ClearQuotaData, partition, &run_loop));
   run_loop.Run();
 
@@ -581,10 +583,9 @@
       GetMockManager());
 
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&ClearQuotaDataForOrigin,
-                            partition, kOrigin1, base::Time(),
-                            &run_loop));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&ClearQuotaDataForOrigin, partition, kOrigin1,
+                            base::Time(), &run_loop));
   run_loop.Run();
 
   EXPECT_FALSE(GetMockManager()->OriginHasData(kOrigin1, kTemporary,
@@ -610,11 +611,10 @@
       GetMockManager());
 
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&ClearQuotaDataForOrigin,
-                            partition, GURL(),
-                            base::Time::Now() - base::TimeDelta::FromHours(1),
-                            &run_loop));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&ClearQuotaDataForOrigin, partition, GURL(),
+                 base::Time::Now() - base::TimeDelta::FromHours(1), &run_loop));
   run_loop.Run();
 
   EXPECT_FALSE(GetMockManager()->OriginHasData(kOrigin1, kTemporary,
@@ -639,11 +639,10 @@
       BrowserContext::GetDefaultStoragePartition(browser_context()));
   partition->OverrideQuotaManagerForTesting(
       GetMockManager());
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&ClearQuotaDataForNonPersistent,
-                            partition,
-                            base::Time::Now() - base::TimeDelta::FromDays(7),
-                            &run_loop));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&ClearQuotaDataForNonPersistent, partition,
+                 base::Time::Now() - base::TimeDelta::FromDays(7), &run_loop));
   run_loop.Run();
 
   EXPECT_FALSE(GetMockManager()->OriginHasData(kOrigin1, kTemporary,
@@ -675,9 +674,8 @@
   partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
 
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&ClearQuotaDataWithOriginMatcher,
-                            partition, GURL(),
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&ClearQuotaDataWithOriginMatcher, partition, GURL(),
                             base::Bind(&DoesOriginMatchForUnprotectedWeb),
                             base::Time(), &run_loop));
   run_loop.Run();
@@ -712,11 +710,11 @@
 
   // Try to remove kOrigin1. Expect failure.
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&ClearQuotaDataWithOriginMatcher,
-                            partition, kOrigin1,
-                            base::Bind(&DoesOriginMatchForUnprotectedWeb),
-                            base::Time(), &run_loop));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&ClearQuotaDataWithOriginMatcher, partition, kOrigin1,
+                 base::Bind(&DoesOriginMatchForUnprotectedWeb), base::Time(),
+                 &run_loop));
   run_loop.Run();
 
   EXPECT_TRUE(GetMockManager()->OriginHasData(kOrigin1, kTemporary,
@@ -748,10 +746,9 @@
   partition->OverrideQuotaManagerForTesting(
       GetMockManager());
   partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(&ClearQuotaDataWithOriginMatcher,
-                 partition, GURL(),
+      base::Bind(&ClearQuotaDataWithOriginMatcher, partition, GURL(),
                  base::Bind(&DoesOriginMatchForBothProtectedAndUnprotectedWeb),
                  base::Time(), &run_loop));
   run_loop.Run();
@@ -778,9 +775,8 @@
       BrowserContext::GetDefaultStoragePartition(browser_context()));
   partition->OverrideQuotaManagerForTesting(
       GetMockManager());
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&ClearQuotaDataWithOriginMatcher,
-                            partition, GURL(),
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&ClearQuotaDataWithOriginMatcher, partition, GURL(),
                             base::Bind(&DoesOriginMatchUnprotected),
                             base::Time(), &run_loop));
   run_loop.Run();
@@ -803,10 +799,9 @@
   partition->SetURLRequestContext(browser_context()->GetRequestContext());
 
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&ClearCookies,
-                            partition, base::Time(), base::Time::Max(),
-                            &run_loop));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&ClearCookies, partition, base::Time(),
+                            base::Time::Max(), &run_loop));
   run_loop.Run();
 
   EXPECT_FALSE(tester.ContainsCookie());
@@ -824,10 +819,9 @@
   partition->SetURLRequestContext(browser_context()->GetRequestContext());
 
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE, base::Bind(&ClearCookies,
-                            partition, an_hour_ago, base::Time::Max(),
-                            &run_loop));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&ClearCookies, partition, an_hour_ago,
+                            base::Time::Max(), &run_loop));
   run_loop.Run();
 
   EXPECT_FALSE(tester.ContainsCookie());
@@ -851,13 +845,12 @@
   partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
 
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&ClearStuff,
                  StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE,
                  partition, base::Time(), base::Time::Max(),
-                 base::Bind(&DoesOriginMatchForUnprotectedWeb),
-                 &run_loop));
+                 base::Bind(&DoesOriginMatchForUnprotectedWeb), &run_loop));
   run_loop.Run();
 
   EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin1));
@@ -883,7 +876,7 @@
   partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
 
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&ClearStuff,
                  StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE,
@@ -912,7 +905,7 @@
   base::Time a_week_ago = base::Time::Now() - base::TimeDelta::FromDays(7);
 
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&ClearStuff,
                  StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE,
diff --git a/content/browser/streams/stream.cc b/content/browser/streams/stream.cc
index fb36ad9..3f4ae680 100644
--- a/content/browser/streams/stream.cc
+++ b/content/browser/streams/stream.cc
@@ -6,7 +6,8 @@
 
 #include "base/bind.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "content/browser/streams/stream_handle_impl.h"
 #include "content/browser/streams/stream_read_observer.h"
@@ -35,11 +36,9 @@
       write_observer_(write_observer),
       stream_handle_(NULL),
       weak_ptr_factory_(this) {
-  CreateByteStream(base::MessageLoopProxy::current(),
-                   base::MessageLoopProxy::current(),
-                   kDeferSizeThreshold,
-                   &writer_,
-                   &reader_);
+  CreateByteStream(base::ThreadTaskRunnerHandle::Get(),
+                   base::ThreadTaskRunnerHandle::Get(), kDeferSizeThreshold,
+                   &writer_, &reader_);
 
   // Setup callback for writing.
   writer_->RegisterCallback(base::Bind(&Stream::OnSpaceAvailable,
@@ -122,7 +121,7 @@
   writer_.reset();
 
   // Continue asynchronously.
-  base::MessageLoopProxy::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&Stream::OnDataAvailable, weak_ptr_factory_.GetWeakPtr()));
 }
diff --git a/content/browser/streams/stream_handle_impl.cc b/content/browser/streams/stream_handle_impl.cc
index 5bc2acbf..ba4dee2 100644
--- a/content/browser/streams/stream_handle_impl.cc
+++ b/content/browser/streams/stream_handle_impl.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/streams/stream.h"
 
 namespace content {
@@ -23,11 +23,12 @@
 StreamHandleImpl::StreamHandleImpl(const base::WeakPtr<Stream>& stream)
     : stream_(stream),
       url_(stream->url()),
-      stream_message_loop_(base::MessageLoopProxy::current().get()) {}
+      stream_task_runner_(base::ThreadTaskRunnerHandle::Get().get()) {
+}
 
 StreamHandleImpl::~StreamHandleImpl() {
-  stream_message_loop_->PostTaskAndReply(FROM_HERE,
-      base::Bind(&Stream::CloseHandle, stream_),
+  stream_task_runner_->PostTaskAndReply(
+      FROM_HERE, base::Bind(&Stream::CloseHandle, stream_),
       base::Bind(&RunCloseListeners, close_listeners_));
 }
 
diff --git a/content/browser/streams/stream_handle_impl.h b/content/browser/streams/stream_handle_impl.h
index d2bd94d..15e8e20 100644
--- a/content/browser/streams/stream_handle_impl.h
+++ b/content/browser/streams/stream_handle_impl.h
@@ -11,7 +11,7 @@
 #include "content/public/browser/stream_handle.h"
 
 namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
 }
 
 namespace content {
@@ -30,7 +30,7 @@
 
   base::WeakPtr<Stream> stream_;
   GURL url_;
-  base::MessageLoopProxy* stream_message_loop_;
+  base::SingleThreadTaskRunner* stream_task_runner_;
   std::vector<base::Closure> close_listeners_;
 };
 
diff --git a/content/browser/streams/stream_url_request_job.cc b/content/browser/streams/stream_url_request_job.cc
index 3d4ac7f77..d2bce89 100644
--- a/content/browser/streams/stream_url_request_job.cc
+++ b/content/browser/streams/stream_url_request_job.cc
@@ -4,7 +4,10 @@
 
 #include "content/browser/streams/stream_url_request_job.h"
 
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/browser/streams/stream.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
@@ -80,7 +83,7 @@
 // net::URLRequestJob methods.
 void StreamURLRequestJob::Start() {
   // Continue asynchronously.
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&StreamURLRequestJob::DidStart, weak_factory_.GetWeakPtr()));
 }
diff --git a/content/browser/tracing/background_tracing_manager_browsertest.cc b/content/browser/tracing/background_tracing_manager_browsertest.cc
index 54a1127..13a309ec 100644
--- a/content/browser/tracing/background_tracing_manager_browsertest.cc
+++ b/content/browser/tracing/background_tracing_manager_browsertest.cc
@@ -3,12 +3,14 @@
 // found in the LICENSE file.
 
 #include "base/bind.h"
+#include "base/trace_event/trace_event.h"
 #include "content/public/browser/background_tracing_manager.h"
 #include "content/public/browser/background_tracing_preemptive_config.h"
 #include "content/public/browser/background_tracing_reactive_config.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/public/test/test_utils.h"
+#include "third_party/zlib/zlib.h"
 
 namespace content {
 
@@ -29,16 +31,42 @@
                    base::Unretained(this));
   }
 
-  void Upload(const base::RefCountedString* file_contents,
+  void Upload(const scoped_refptr<base::RefCountedString>& file_contents,
               base::Callback<void()> done_callback) {
     receive_count_ += 1;
+    EXPECT_TRUE(file_contents);
 
+    size_t compressed_length = file_contents->data().length();
+    const size_t kOutputBufferLength = 10 * 1024 * 1024;
+    std::vector<char> output_str(kOutputBufferLength);
+
+    z_stream stream = {0};
+    stream.avail_in = compressed_length;
+    stream.avail_out = kOutputBufferLength;
+    stream.next_in = (Bytef*)&file_contents->data()[0];
+    stream.next_out = (Bytef*)vector_as_array(&output_str);
+
+    // 16 + MAX_WBITS means only decoding gzip encoded streams, and using
+    // the biggest window size, according to zlib.h
+    int result = inflateInit2(&stream, 16 + MAX_WBITS);
+    EXPECT_EQ(Z_OK, result);
+    result = inflate(&stream, Z_FINISH);
+    int bytes_written = kOutputBufferLength - stream.avail_out;
+
+    inflateEnd(&stream);
+    EXPECT_EQ(Z_STREAM_END, result);
+
+    last_file_contents_.assign(vector_as_array(&output_str), bytes_written);
     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                             base::Bind(done_callback));
     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                             base::Bind(callback_));
   }
 
+  bool TraceHasMatchingString(const char* str) {
+    return last_file_contents_.find(str) != std::string::npos;
+  }
+
   int get_receive_count() const { return receive_count_; }
 
   const BackgroundTracingManager::ReceiveCallback& get_receive_callback()
@@ -50,6 +78,7 @@
   BackgroundTracingManager::ReceiveCallback receive_callback_;
   base::Closure callback_;
   int receive_count_;
+  std::string last_file_contents_;
 };
 
 void StartedFinalizingCallback(base::Closure callback,
@@ -97,7 +126,8 @@
 
 void DisableScenarioWhenIdle() {
   BackgroundTracingManager::GetInstance()->SetActiveScenario(
-      NULL, BackgroundTracingManager::ReceiveCallback(), false);
+      NULL, BackgroundTracingManager::ReceiveCallback(),
+      BackgroundTracingManager::NO_DATA_FILTERING);
 }
 
 // This tests that the endpoint receives the final trace data.
@@ -118,7 +148,8 @@
             GetInstance()->RegisterTriggerType("preemptive_test");
 
     BackgroundTracingManager::GetInstance()->SetActiveScenario(
-        config.Pass(), upload_config_wrapper.get_receive_callback(), true);
+        config.Pass(), upload_config_wrapper.get_receive_callback(),
+        BackgroundTracingManager::NO_DATA_FILTERING);
 
     BackgroundTracingManager::GetInstance()->WhenIdle(
         base::Bind(&DisableScenarioWhenIdle));
@@ -150,7 +181,8 @@
             "preemptive_test");
 
     BackgroundTracingManager::GetInstance()->SetActiveScenario(
-        config.Pass(), upload_config_wrapper.get_receive_callback(), true);
+        config.Pass(), upload_config_wrapper.get_receive_callback(),
+        BackgroundTracingManager::NO_DATA_FILTERING);
 
     BackgroundTracingManager::GetInstance()->WhenIdle(
         base::Bind(&DisableScenarioWhenIdle));
@@ -166,6 +198,112 @@
   }
 }
 
+namespace {
+
+bool IsTraceEventArgsWhitelisted(const char* category_group_name,
+                                 const char* event_name) {
+  if (MatchPattern(category_group_name, "benchmark") &&
+      MatchPattern(event_name, "whitelisted")) {
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace
+
+// This tests that non-whitelisted args get stripped if required.
+IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
+                       NoWhitelistedArgsStripped) {
+  SetupBackgroundTracingManager();
+
+  base::trace_event::TraceLog::GetInstance()->SetArgumentFilterPredicate(
+      base::Bind(&IsTraceEventArgsWhitelisted));
+
+  base::RunLoop wait_for_upload;
+  BackgroundTracingManagerUploadConfigWrapper upload_config_wrapper(
+      wait_for_upload.QuitClosure());
+
+  scoped_ptr<BackgroundTracingPreemptiveConfig> config =
+      CreatePreemptiveConfig();
+
+  content::BackgroundTracingManager::TriggerHandle handle =
+      content::BackgroundTracingManager::GetInstance()->RegisterTriggerType(
+          "preemptive_test");
+
+  base::RunLoop wait_for_activated;
+  BackgroundTracingManager::GetInstance()->SetTracingEnabledCallbackForTesting(
+      wait_for_activated.QuitClosure());
+  EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
+      config.Pass(), upload_config_wrapper.get_receive_callback(),
+      BackgroundTracingManager::ANONYMIZE_DATA));
+
+  wait_for_activated.Run();
+
+  TRACE_EVENT1("benchmark", "whitelisted", "find_this", 1);
+  TRACE_EVENT1("benchmark", "not_whitelisted", "this_not_found", 1);
+
+  BackgroundTracingManager::GetInstance()->WhenIdle(
+      base::Bind(&DisableScenarioWhenIdle));
+
+  BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
+      handle, base::Bind(&StartedFinalizingCallback, base::Closure(), true));
+
+  wait_for_upload.Run();
+
+  EXPECT_TRUE(upload_config_wrapper.get_receive_count() == 1);
+  EXPECT_TRUE(upload_config_wrapper.TraceHasMatchingString("{"));
+  EXPECT_TRUE(upload_config_wrapper.TraceHasMatchingString("find_this"));
+  EXPECT_TRUE(!upload_config_wrapper.TraceHasMatchingString("this_not_found"));
+}
+
+// This tests subprocesses (like a navigating renderer) which gets told to
+// provide a argument-filtered trace and has no predicate in place to do the
+// filtering (in this case, only the browser process gets it set), will crash
+// rather than return potential PII.
+IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
+                       CrashWhenSubprocessWithoutArgumentFilter) {
+  SetupBackgroundTracingManager();
+
+  base::trace_event::TraceLog::GetInstance()->SetArgumentFilterPredicate(
+      base::Bind(&IsTraceEventArgsWhitelisted));
+
+  base::RunLoop wait_for_upload;
+  BackgroundTracingManagerUploadConfigWrapper upload_config_wrapper(
+      wait_for_upload.QuitClosure());
+
+  scoped_ptr<BackgroundTracingPreemptiveConfig> config =
+      CreatePreemptiveConfig();
+
+  content::BackgroundTracingManager::TriggerHandle handle =
+      content::BackgroundTracingManager::GetInstance()->RegisterTriggerType(
+          "preemptive_test");
+
+  base::RunLoop wait_for_activated;
+  BackgroundTracingManager::GetInstance()->SetTracingEnabledCallbackForTesting(
+      wait_for_activated.QuitClosure());
+  EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario(
+      config.Pass(), upload_config_wrapper.get_receive_callback(),
+      BackgroundTracingManager::ANONYMIZE_DATA));
+
+  wait_for_activated.Run();
+
+  NavigateToURL(shell(), GetTestUrl("", "about:blank"));
+
+  BackgroundTracingManager::GetInstance()->WhenIdle(
+      base::Bind(&DisableScenarioWhenIdle));
+
+  BackgroundTracingManager::GetInstance()->TriggerNamedEvent(
+      handle, base::Bind(&StartedFinalizingCallback, base::Closure(), true));
+
+  wait_for_upload.Run();
+
+  EXPECT_TRUE(upload_config_wrapper.get_receive_count() == 1);
+  // We should *not* receive anything at all from the renderer,
+  // the process should've crashed rather than letting that happen.
+  EXPECT_TRUE(!upload_config_wrapper.TraceHasMatchingString("CrRendererMain"));
+}
+
 // This tests multiple triggers still only gathers once.
 IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest,
                        CallMultipleTriggersOnlyGatherOnce) {
@@ -194,7 +332,8 @@
         BackgroundTracingManager::GetInstance()->RegisterTriggerType("test2");
 
     BackgroundTracingManager::GetInstance()->SetActiveScenario(
-        config.Pass(), upload_config_wrapper.get_receive_callback(), true);
+        config.Pass(), upload_config_wrapper.get_receive_callback(),
+        BackgroundTracingManager::NO_DATA_FILTERING);
 
     BackgroundTracingManager::GetInstance()->WhenIdle(
         base::Bind(&DisableScenarioWhenIdle));
@@ -256,7 +395,8 @@
             "does_not_exist");
 
     BackgroundTracingManager::GetInstance()->SetActiveScenario(
-        config.Pass(), upload_config_wrapper.get_receive_callback(), true);
+        config.Pass(), upload_config_wrapper.get_receive_callback(),
+        BackgroundTracingManager::NO_DATA_FILTERING);
 
     BackgroundTracingManager::GetInstance()->WhenIdle(
         base::Bind(&DisableScenarioWhenIdle));
@@ -292,7 +432,8 @@
         ->InvalidateTriggerHandlesForTesting();
 
     BackgroundTracingManager::GetInstance()->SetActiveScenario(
-        config.Pass(), upload_config_wrapper.get_receive_callback(), true);
+        config.Pass(), upload_config_wrapper.get_receive_callback(),
+        BackgroundTracingManager::NO_DATA_FILTERING);
 
     BackgroundTracingManager::GetInstance()->WhenIdle(
         base::Bind(&DisableScenarioWhenIdle));
@@ -327,7 +468,8 @@
     config->configs.push_back(rule);
 
     bool result = BackgroundTracingManager::GetInstance()->SetActiveScenario(
-        config.Pass(), upload_config_wrapper.get_receive_callback(), true);
+        config.Pass(), upload_config_wrapper.get_receive_callback(),
+        BackgroundTracingManager::NO_DATA_FILTERING);
 
     EXPECT_FALSE(result);
   }
@@ -351,7 +493,8 @@
             GetInstance()->RegisterTriggerType("reactive_test");
 
     BackgroundTracingManager::GetInstance()->SetActiveScenario(
-        config.Pass(), upload_config_wrapper.get_receive_callback(), true);
+        config.Pass(), upload_config_wrapper.get_receive_callback(),
+        BackgroundTracingManager::NO_DATA_FILTERING);
 
     BackgroundTracingManager::GetInstance()->WhenIdle(
         base::Bind(&DisableScenarioWhenIdle));
@@ -385,7 +528,8 @@
             GetInstance()->RegisterTriggerType("reactive_test");
 
     BackgroundTracingManager::GetInstance()->SetActiveScenario(
-        config.Pass(), upload_config_wrapper.get_receive_callback(), true);
+        config.Pass(), upload_config_wrapper.get_receive_callback(),
+        BackgroundTracingManager::NO_DATA_FILTERING);
 
     BackgroundTracingManager::GetInstance()->WhenIdle(
         base::Bind(&DisableScenarioWhenIdle));
@@ -420,7 +564,8 @@
             GetInstance()->RegisterTriggerType("reactive_test");
 
     BackgroundTracingManager::GetInstance()->SetActiveScenario(
-        config.Pass(), upload_config_wrapper.get_receive_callback(), true);
+        config.Pass(), upload_config_wrapper.get_receive_callback(),
+        BackgroundTracingManager::NO_DATA_FILTERING);
 
     BackgroundTracingManager::GetInstance()->WhenIdle(
         base::Bind(&DisableScenarioWhenIdle));
diff --git a/content/browser/tracing/background_tracing_manager_impl.cc b/content/browser/tracing/background_tracing_manager_impl.cc
index b636cc88..7f4f15e 100644
--- a/content/browser/tracing/background_tracing_manager_impl.cc
+++ b/content/browser/tracing/background_tracing_manager_impl.cc
@@ -9,6 +9,9 @@
 #include "content/public/browser/background_tracing_preemptive_config.h"
 #include "content/public/browser/background_tracing_reactive_config.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/tracing_delegate.h"
+#include "content/public/common/content_client.h"
 
 namespace content {
 
@@ -74,7 +77,8 @@
 }
 
 BackgroundTracingManagerImpl::BackgroundTracingManagerImpl()
-    : is_gathering_(false),
+    : delegate_(GetContentClient()->browser()->GetTracingDelegate()),
+      is_gathering_(false),
       is_tracing_(false),
       requires_anonymized_data_(true),
       trigger_handle_ids_(0) {
@@ -130,11 +134,20 @@
 bool BackgroundTracingManagerImpl::SetActiveScenario(
     scoped_ptr<BackgroundTracingConfig> config,
     const BackgroundTracingManager::ReceiveCallback& receive_callback,
-    bool requires_anonymized_data) {
+    DataFiltering data_filtering) {
   CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   if (is_tracing_)
     return false;
 
+  bool requires_anonymized_data = (data_filtering == ANONYMIZE_DATA);
+
+  // TODO(oysteine): Retry when time_until_allowed has elapsed.
+  if (config && delegate_ &&
+      !delegate_->IsAllowedToBeginBackgroundScenario(
+          *config.get(), requires_anonymized_data)) {
+    return false;
+  }
+
   if (!IsSupportedConfig(config.get()))
     return false;
 
@@ -155,6 +168,13 @@
   if (!config_)
     return;
 
+  // TODO(oysteine): Retry later.
+  if (delegate_ &&
+      !delegate_->IsAllowedToBeginBackgroundScenario(
+          *config_.get(), requires_anonymized_data_)) {
+    return;
+  }
+
   if (config_->mode == BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) {
     EnableRecording(GetCategoryFilterStringForCategoryPreset(
         static_cast<BackgroundTracingPreemptiveConfig*>(config_.get())
@@ -296,6 +316,11 @@
   trigger_handles_.clear();
 }
 
+void BackgroundTracingManagerImpl::SetTracingEnabledCallbackForTesting(
+    const base::Closure& callback) {
+  tracing_enabled_callback_for_testing_ = callback;
+};
+
 void BackgroundTracingManagerImpl::FireTimerForTesting() {
   tracing_timer_->FireTimerForTesting();
 }
@@ -303,9 +328,12 @@
 void BackgroundTracingManagerImpl::EnableRecording(
     std::string category_filter_str,
     base::trace_event::TraceRecordMode record_mode) {
+  base::trace_event::TraceConfig trace_config(category_filter_str, record_mode);
+  if (requires_anonymized_data_)
+    trace_config.EnableArgumentFilter();
+
   is_tracing_ = TracingController::GetInstance()->EnableRecording(
-      base::trace_event::TraceConfig(category_filter_str, record_mode),
-      TracingController::EnableRecordingDoneCallback());
+      trace_config, tracing_enabled_callback_for_testing_);
 }
 
 void BackgroundTracingManagerImpl::OnFinalizeStarted(
@@ -314,7 +342,7 @@
 
   if (!receive_callback_.is_null())
     receive_callback_.Run(
-        file_contents.get(),
+        file_contents,
         base::Bind(&BackgroundTracingManagerImpl::OnFinalizeComplete,
                    base::Unretained(this)));
 }
@@ -344,12 +372,21 @@
   is_gathering_ = true;
   is_tracing_ = false;
 
-  content::TracingController::GetInstance()->DisableRecording(
-      content::TracingController::CreateCompressedStringSink(
-          data_endpoint_wrapper_));
+  bool is_allowed_finalization =
+      !delegate_ || (config_ &&
+                     delegate_->IsAllowedToEndBackgroundScenario(
+                         *config_.get(), requires_anonymized_data_));
+
+  scoped_refptr<TracingControllerImpl::TraceDataSink> trace_data_sink;
+  if (is_allowed_finalization) {
+    trace_data_sink = content::TracingController::CreateCompressedStringSink(
+        data_endpoint_wrapper_);
+  }
+
+  content::TracingController::GetInstance()->DisableRecording(trace_data_sink);
 
   if (!callback.is_null())
-    callback.Run(true);
+    callback.Run(is_allowed_finalization);
 }
 
 std::string
diff --git a/content/browser/tracing/background_tracing_manager_impl.h b/content/browser/tracing/background_tracing_manager_impl.h
index 9795629..9970e92b 100644
--- a/content/browser/tracing/background_tracing_manager_impl.h
+++ b/content/browser/tracing/background_tracing_manager_impl.h
@@ -15,13 +15,15 @@
 
 namespace content {
 
+class TracingDelegate;
+
 class BackgroundTracingManagerImpl : public content::BackgroundTracingManager {
  public:
   static BackgroundTracingManagerImpl* GetInstance();
 
   bool SetActiveScenario(scoped_ptr<BackgroundTracingConfig>,
                          const ReceiveCallback&,
-                         bool) override;
+                         DataFiltering data_filtering) override;
   void WhenIdle(IdleCallback idle_callback) override;
 
   void TriggerNamedEvent(TriggerHandle, StartedFinalizingCallback) override;
@@ -29,7 +31,8 @@
   void GetTriggerNameList(std::vector<std::string>* trigger_names) override;
 
   void InvalidateTriggerHandlesForTesting() override;
-
+  void SetTracingEnabledCallbackForTesting(
+      const base::Closure& callback) override;
   void FireTimerForTesting() override;
 
  private:
@@ -82,6 +85,7 @@
     StartedFinalizingCallback callback_;
   };
 
+  scoped_ptr<TracingDelegate> delegate_;
   scoped_ptr<content::BackgroundTracingConfig> config_;
   scoped_refptr<TraceDataEndpointWrapper> data_endpoint_wrapper_;
   std::map<TriggerHandle, std::string> trigger_handles_;
@@ -94,6 +98,7 @@
   int trigger_handle_ids_;
 
   IdleCallback idle_callback_;
+  base::Closure tracing_enabled_callback_for_testing_;
 
   friend struct base::DefaultLazyInstanceTraits<BackgroundTracingManagerImpl>;
 
diff --git a/content/browser/web_contents/aura/overscroll_window_animation.cc b/content/browser/web_contents/aura/overscroll_window_animation.cc
index 854a299..c89faa0 100644
--- a/content/browser/web_contents/aura/overscroll_window_animation.cc
+++ b/content/browser/web_contents/aura/overscroll_window_animation.cc
@@ -86,6 +86,7 @@
 void OverscrollWindowAnimation::OnOverscrollModeChange(
     OverscrollMode old_mode,
     OverscrollMode new_mode) {
+  DCHECK_NE(old_mode, new_mode);
   Direction new_direction = GetDirectionForMode(new_mode);
   if (new_direction == SLIDE_NONE) {
     // The user cancelled the in progress animation.
diff --git a/content/browser/web_contents/aura/overscroll_window_delegate.cc b/content/browser/web_contents/aura/overscroll_window_delegate.cc
index b4c3644..d8ce8b6 100644
--- a/content/browser/web_contents/aura/overscroll_window_delegate.cc
+++ b/content/browser/web_contents/aura/overscroll_window_delegate.cc
@@ -43,6 +43,8 @@
 }
 
 void OverscrollWindowDelegate::ResetOverscroll() {
+  if (overscroll_mode_ == OVERSCROLL_NONE)
+    return;
   delegate_->OnOverscrollModeChange(overscroll_mode_, OVERSCROLL_NONE);
   overscroll_mode_ = OVERSCROLL_NONE;
   delta_x_ = 0;
diff --git a/content/browser/web_contents/aura/overscroll_window_delegate_unittest.cc b/content/browser/web_contents/aura/overscroll_window_delegate_unittest.cc
index 75579d7..13382a8 100644
--- a/content/browser/web_contents/aura/overscroll_window_delegate_unittest.cc
+++ b/content/browser/web_contents/aura/overscroll_window_delegate_unittest.cc
@@ -25,6 +25,7 @@
       : window_(nullptr),
         overscroll_complete_(false),
         overscroll_started_(false),
+        mode_changed_(false),
         current_mode_(OVERSCROLL_NONE),
         touch_start_threshold_(content::GetOverscrollConfig(
             content::OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN)),
@@ -37,6 +38,7 @@
   void Reset() {
     overscroll_complete_ = false;
     overscroll_started_ = false;
+    mode_changed_ = false;
     current_mode_ = OVERSCROLL_NONE;
     window_.reset(CreateNormalWindow(
         0, root_window(), new OverscrollWindowDelegate(this, gfx::Image())));
@@ -48,6 +50,7 @@
 
   bool overscroll_complete() { return overscroll_complete_; }
   bool overscroll_started() { return overscroll_started_; }
+  bool mode_changed() { return mode_changed_; }
 
   OverscrollMode current_mode() { return current_mode_; }
 
@@ -89,6 +92,7 @@
 
   void OnOverscrollModeChange(OverscrollMode old_mode,
                               OverscrollMode new_mode) override {
+    mode_changed_ = true;
     current_mode_ = new_mode;
     if (current_mode_ != OVERSCROLL_NONE)
       overscroll_started_ = true;
@@ -100,7 +104,7 @@
   // State flags.
   bool overscroll_complete_;
   bool overscroll_started_;
-
+  bool mode_changed_;
   OverscrollMode current_mode_;
 
   // Config defined constants.
@@ -167,6 +171,13 @@
   generator.ReleaseTouch();
   EXPECT_EQ(delegate->overscroll_mode_, OVERSCROLL_NONE);
   EXPECT_TRUE(overscroll_complete());
+
+  // Generate a mouse events which normally cancel the overscroll. Confirm
+  // that superfluous mode changed events are not dispatched.
+  Reset();
+  generator.PressLeftButton();
+  generator.MoveMouseTo(gfx::Point(10, 10));
+  EXPECT_FALSE(mode_changed());
 }
 
 // Tests that the overscroll does not start until the gesture gets past a
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index ee5afdf4..378177e4 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -8,14 +8,17 @@
 
 #include "base/command_line.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/process/process.h"
 #include "base/profiler/scoped_tracker.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "components/mime_util/mime_util.h"
@@ -1026,7 +1029,12 @@
 bool WebContentsImpl::IsCrashed() const {
   return (crashed_status_ == base::TERMINATION_STATUS_PROCESS_CRASHED ||
           crashed_status_ == base::TERMINATION_STATUS_ABNORMAL_TERMINATION ||
-          crashed_status_ == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
+          crashed_status_ == base::TERMINATION_STATUS_PROCESS_WAS_KILLED
+#if defined(OS_CHROMEOS)
+          ||
+          crashed_status_ == base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM
+#endif
+          );
 }
 
 void WebContentsImpl::SetIsCrashed(base::TerminationStatus status,
@@ -1284,6 +1292,7 @@
   // corresponding RenderView and main RenderFrame have already been created.
   // Ensure observers are notified about this.
   if (params.renderer_initiated_creation) {
+    GetRenderViewHost()->set_renderer_initialized(true);
     RenderViewCreated(GetRenderViewHost());
     GetRenderManager()->current_frame_host()->SetRenderFrameCreated(true);
   }
@@ -1609,7 +1618,8 @@
   create_params.opener_suppressed = params.opener_suppressed;
   if (params.disposition == NEW_BACKGROUND_TAB)
     create_params.initially_hidden = true;
-  create_params.renderer_initiated_creation = true;
+  create_params.renderer_initiated_creation =
+      main_frame_route_id != MSG_ROUTING_NONE;
 
   WebContentsImpl* new_contents = NULL;
   if (!is_guest) {
@@ -3509,7 +3519,8 @@
     delegate_->WillRunBeforeUnloadConfirm();
 
   bool suppress_this_message =
-      rfhi->rfh_state() != RenderFrameHostImpl::STATE_DEFAULT || !delegate_ ||
+      rfhi->rfh_state() != RenderFrameHostImpl::STATE_DEFAULT ||
+      ShowingInterstitialPage() || !delegate_ ||
       delegate_->ShouldSuppressDialogs(this) ||
       !delegate_->GetJavaScriptDialogManager(this);
   if (suppress_this_message) {
@@ -3799,10 +3810,9 @@
   if (loading_weak_factory_.HasWeakPtrs())
     return;
 
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&WebContentsImpl::SendChangeLoadProgress,
-                 loading_weak_factory_.GetWeakPtr()),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::Bind(&WebContentsImpl::SendChangeLoadProgress,
+                            loading_weak_factory_.GetWeakPtr()),
       min_delay);
 }
 
@@ -3957,11 +3967,16 @@
 int WebContentsImpl::CreateSwappedOutRenderView(
     SiteInstance* instance) {
   int render_view_routing_id = MSG_ROUTING_NONE;
-  GetRenderManager()->CreateRenderFrame(
-      instance, nullptr, MSG_ROUTING_NONE,
-      CREATE_RF_SWAPPED_OUT | CREATE_RF_FOR_MAIN_FRAME_NAVIGATION |
-          CREATE_RF_HIDDEN,
-      &render_view_routing_id);
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kSitePerProcess)) {
+    GetRenderManager()->CreateRenderFrameProxy(instance);
+  } else {
+    GetRenderManager()->CreateRenderFrame(
+        instance, nullptr, MSG_ROUTING_NONE,
+        CREATE_RF_SWAPPED_OUT | CREATE_RF_FOR_MAIN_FRAME_NAVIGATION |
+            CREATE_RF_HIDDEN,
+        &render_view_routing_id);
+  }
   return render_view_routing_id;
 }
 
@@ -4152,11 +4167,18 @@
   // Create a swapped out RenderView in the given SiteInstance if none exists,
   // setting its opener to the given route_id.  Return the new view's route_id.
   int render_view_routing_id = MSG_ROUTING_NONE;
-  GetRenderManager()->CreateRenderFrame(instance, nullptr, opener_route_id,
-                                        CREATE_RF_FOR_MAIN_FRAME_NAVIGATION |
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kSitePerProcess)) {
+    GetRenderManager()->CreateRenderFrameProxy(instance);
+    render_view_routing_id =
+        frame_tree_.GetRenderViewHost(instance)->GetRoutingID();
+  } else {
+    GetRenderManager()->CreateRenderFrame(instance, nullptr, opener_route_id,
+                                          CREATE_RF_FOR_MAIN_FRAME_NAVIGATION |
                                             CREATE_RF_SWAPPED_OUT |
                                             CREATE_RF_HIDDEN,
-                                        &render_view_routing_id);
+                                          &render_view_routing_id);
+  }
   return render_view_routing_id;
 }
 
@@ -4178,6 +4200,7 @@
     RenderViewHost* render_view_host,
     int opener_route_id,
     int proxy_routing_id,
+    const FrameReplicationState& replicated_frame_state,
     bool for_main_frame_navigation) {
   TRACE_EVENT0("browser,navigation",
                "WebContentsImpl::CreateRenderViewForRenderManager");
@@ -4209,6 +4232,7 @@
                                               opener_route_id,
                                               proxy_routing_id,
                                               max_page_id,
+                                              replicated_frame_state,
                                               created_with_opener_)) {
     return false;
   }
@@ -4269,10 +4293,9 @@
 }
 
 bool WebContentsImpl::CreateRenderViewForInitialEmptyDocument() {
-  return CreateRenderViewForRenderManager(GetRenderViewHost(),
-                                          MSG_ROUTING_NONE,
-                                          MSG_ROUTING_NONE,
-                                          true);
+  return CreateRenderViewForRenderManager(
+      GetRenderViewHost(), MSG_ROUTING_NONE, MSG_ROUTING_NONE,
+      frame_tree_.root()->current_replication_state(), true);
 }
 
 #elif defined(OS_MACOSX)
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 8a46227..bffa888 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -572,6 +572,7 @@
       RenderViewHost* render_view_host,
       int opener_route_id,
       int proxy_routing_id,
+      const FrameReplicationState& replicated_frame_state,
       bool for_main_frame_navigation) override;
   bool CreateRenderFrameForRenderManager(RenderFrameHost* render_frame_host,
                                          int parent_routing_id,
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index 22efe5d..309a91c3 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -459,6 +459,8 @@
 // Test that navigating across a site boundary creates a new RenderViewHost
 // with a new SiteInstance.  Going back should do the same.
 TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
+  bool is_site_per_process = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kSitePerProcess);
   TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
   int orig_rvh_delete_count = 0;
   orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
@@ -523,9 +525,9 @@
   EXPECT_EQ(url2, contents()->GetVisibleURL());
   EXPECT_NE(instance1, instance2);
   EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
-  // We keep the original RFH around, swapped out.
-  EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
-      orig_rfh));
+  // We keep a proxy for the original RFH's SiteInstance.
+  EXPECT_TRUE(contents()->GetRenderManagerForTesting()->GetRenderFrameProxyHost(
+      orig_rfh->GetSiteInstance()));
   EXPECT_EQ(orig_rvh_delete_count, 0);
 
   // Going back should switch SiteInstances again.  The first SiteInstance is
@@ -538,7 +540,8 @@
     contents()->GetMainFrame()->PrepareForCommit();
   }
   TestRenderFrameHost* goback_rfh = contents()->GetPendingMainFrame();
-  EXPECT_EQ(orig_rfh, goback_rfh);
+  if (!is_site_per_process)
+    EXPECT_EQ(orig_rfh, goback_rfh);
   EXPECT_TRUE(contents()->CrossProcessNavigationPending());
 
   // Navigations should be suspended in goback_rfh until BeforeUnloadACK.
@@ -555,9 +558,9 @@
   EXPECT_FALSE(contents()->CrossProcessNavigationPending());
   EXPECT_EQ(goback_rfh, contents()->GetMainFrame());
   EXPECT_EQ(instance1, contents()->GetSiteInstance());
-  // The pending RFH should now be swapped out, not deleted.
+  // There should be a proxy for the pending RFH SiteInstance.
   EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
-      IsOnSwappedOutList(pending_rfh));
+      GetRenderFrameProxyHost(pending_rfh->GetSiteInstance()));
   EXPECT_EQ(pending_rvh_delete_count, 0);
   pending_rfh->OnSwappedOut();
 
@@ -776,9 +779,9 @@
   EXPECT_EQ(url2, contents()->GetVisibleURL());
   EXPECT_NE(new_instance, orig_instance);
   EXPECT_FALSE(contents()->GetPendingMainFrame());
-  // We keep the original RFH around, swapped out.
-  EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
-      orig_rfh));
+  // We keep a proxy for the original RFH's SiteInstance.
+  EXPECT_TRUE(contents()->GetRenderManagerForTesting()->GetRenderFrameProxyHost(
+      orig_rfh->GetSiteInstance()));
   EXPECT_EQ(orig_rvh_delete_count, 0);
   orig_rfh->OnSwappedOut();
 
diff --git a/content/browser/web_contents/web_contents_view_aura_browsertest.cc b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
index ccd1689..e9ba331 100644
--- a/content/browser/web_contents/web_contents_view_aura_browsertest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
@@ -5,9 +5,12 @@
 #include "content/browser/web_contents/web_contents_view_aura.h"
 
 #include "base/command_line.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
@@ -46,9 +49,8 @@
 // for details.
 void GiveItSomeTime() {
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      run_loop.QuitClosure(),
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(),
       base::TimeDelta::FromMillisecondsD(10));
   run_loop.Run();
 }
diff --git a/content/browser/webui/url_data_manager_backend.cc b/content/browser/webui/url_data_manager_backend.cc
index 1c171c2..ba1f5d46 100644
--- a/content/browser/webui/url_data_manager_backend.cc
+++ b/content/browser/webui/url_data_manager_backend.cc
@@ -12,11 +12,12 @@
 #include "base/compiler_specific.h"
 #include "base/debug/alias.h"
 #include "base/lazy_instance.h"
+#include "base/location.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/profiler/scoped_tracker.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
@@ -639,19 +640,17 @@
     // is guaranteed because request for mime type is placed in the
     // message loop before request for data. And correspondingly their
     // replies are put on the IO thread in the same order.
-    target_message_loop->PostTask(
+    target_message_loop->task_runner()->PostTask(
         FROM_HERE,
-        base::Bind(&GetMimeTypeOnUI,
-                   scoped_refptr<URLDataSourceImpl>(source),
+        base::Bind(&GetMimeTypeOnUI, scoped_refptr<URLDataSourceImpl>(source),
                    path, job->AsWeakPtr()));
 
     // The DataSource wants StartDataRequest to be called on a specific thread,
     // usually the UI thread, for this path.
-    target_message_loop->PostTask(
-        FROM_HERE,
-        base::Bind(&URLDataManagerBackend::CallStartRequest,
-                   make_scoped_refptr(source), path, render_process_id,
-                   render_frame_id, request_id));
+    target_message_loop->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&URLDataManagerBackend::CallStartRequest,
+                              make_scoped_refptr(source), path,
+                              render_process_id, render_frame_id, request_id));
   }
   return true;
 }
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc
index 7b2d143..5c01528 100644
--- a/content/child/blink_platform_impl.cc
+++ b/content/child/blink_platform_impl.cc
@@ -527,14 +527,12 @@
 
 bool BlinkPlatformImpl::portAllowed(const blink::WebURL& url) const {
   GURL gurl = GURL(url);
+  // Return true for URLs without a port specified.  This is needed to let
+  // through non-network schemes that don't go over the network.
   if (!gurl.has_port())
     return true;
-  int port = gurl.IntPort();
-  if (net::IsPortAllowedByOverride(port))
-    return true;
-  if (gurl.SchemeIs("ftp"))
-    return net::IsPortAllowedByFtp(port);
-  return net::IsPortAllowedByDefault(port);
+  return net::IsPortAllowedForScheme(gurl.EffectiveIntPort(), gurl.scheme(),
+                                     net::PORT_OVERRIDES_ALLOWED);
 }
 
 blink::WebThread* BlinkPlatformImpl::createThread(const char* name) {
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc
index feec85e..aa6577eb603 100644
--- a/content/child/resource_dispatcher.cc
+++ b/content/child/resource_dispatcher.cc
@@ -644,6 +644,7 @@
   RemoteToLocalTimeTicks(converter, &load_timing->send_end);
   RemoteToLocalTimeTicks(converter, &load_timing->receive_headers_end);
   RemoteToLocalTimeTicks(converter, &renderer_info->service_worker_start_time);
+  RemoteToLocalTimeTicks(converter, &renderer_info->service_worker_ready_time);
 
   // Collect UMA on the inter-process skew.
   bool is_skew_additive = false;
diff --git a/content/child/shared_memory_data_consumer_handle.cc b/content/child/shared_memory_data_consumer_handle.cc
new file mode 100644
index 0000000..f5d6e69
--- /dev/null
+++ b/content/child/shared_memory_data_consumer_handle.cc
@@ -0,0 +1,281 @@
+// 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 "content/child/shared_memory_data_consumer_handle.h"
+
+#include <algorithm>
+#include <deque>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "content/public/child/fixed_received_data.h"
+
+namespace content {
+
+namespace {
+
+class DelegateThreadSafeReceivedData final
+    : public RequestPeer::ThreadSafeReceivedData {
+ public:
+  explicit DelegateThreadSafeReceivedData(
+      scoped_ptr<RequestPeer::ReceivedData> data)
+      : data_(data.Pass()),
+        task_runner_(base::MessageLoop::current()->task_runner()) {}
+  ~DelegateThreadSafeReceivedData() override {
+    if (!task_runner_->BelongsToCurrentThread()) {
+      // Delete the data on the original thread.
+      task_runner_->DeleteSoon(FROM_HERE, data_.release());
+    }
+  }
+
+  const char* payload() const override { return data_->payload(); }
+  int length() const override { return data_->length(); }
+  int encoded_length() const override { return data_->encoded_length(); }
+
+ private:
+  scoped_ptr<RequestPeer::ReceivedData> data_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(DelegateThreadSafeReceivedData);
+};
+
+}  // namespace
+
+using Result = blink::WebDataConsumerHandle::Result;
+
+class SharedMemoryDataConsumerHandle::Context final
+    : public base::RefCountedThreadSafe<Context> {
+ public:
+  Context()
+      : result_(Ok),
+        first_offset_(0),
+        client_(nullptr),
+        is_reader_active_(true) {}
+
+  bool IsEmpty() const { return queue_.empty(); }
+  void Clear() {
+    for (auto& data : queue_) {
+      delete data;
+    }
+    queue_.clear();
+    first_offset_ = 0;
+    client_ = nullptr;
+  }
+  void Notify() {
+    // Note that this function is not protected by |lock_| (actually it
+    // shouldn't be) but |notification_task_runner_| is thread-safe.
+
+    if (notification_task_runner_->BelongsToCurrentThread()) {
+      NotifyImmediately();
+    } else {
+      notification_task_runner_->PostTask(
+          FROM_HERE, base::Bind(&Context::NotifyImmediately, this));
+    }
+  }
+
+  RequestPeer::ThreadSafeReceivedData* Top() { return queue_.front(); }
+  void Push(scoped_ptr<RequestPeer::ThreadSafeReceivedData> data) {
+    queue_.push_back(data.release());
+  }
+  size_t first_offset() const { return first_offset_; }
+  Result result() const { return result_; }
+  void set_result(Result r) { result_ = r; }
+  Client* client() { return client_; }
+  void SetClient(Client* client) {
+    if (client) {
+      notification_task_runner_ = base::MessageLoop::current()->task_runner();
+      client_ = client;
+    } else {
+      notification_task_runner_ = nullptr;
+      client_ = nullptr;
+    }
+  }
+  bool is_reader_active() const { return is_reader_active_; }
+  void set_is_reader_active(bool b) { is_reader_active_ = b; }
+  void Consume(size_t s) {
+    first_offset_ += s;
+    auto top = Top();
+    if (static_cast<size_t>(top->length()) <= first_offset_) {
+      delete top;
+      queue_.pop_front();
+      first_offset_ = 0;
+    }
+  }
+  base::Lock& lock() { return lock_; }
+
+ private:
+  friend class base::RefCountedThreadSafe<Context>;
+  ~Context() {
+    // This is necessary because the queue stores raw pointers.
+    Clear();
+  }
+
+  void NotifyImmediately() {
+    // As we can assume that all reader-side methods are called on this
+    // thread (see WebDataConsumerHandle comments), we don't need to lock.
+    if (client_)
+      client_->didGetReadable();
+  }
+
+  base::Lock lock_;
+  // |result_| stores the ultimate state of this handle if it has. Otherwise,
+  // |Ok| is set.
+  Result result_;
+  // TODO(yhirano): Use std::deque<scoped_ptr<ThreadSafeReceivedData>>
+  // once it is allowed.
+  std::deque<RequestPeer::ThreadSafeReceivedData*> queue_;
+  size_t first_offset_;
+  Client* client_;
+  scoped_refptr<base::SingleThreadTaskRunner> notification_task_runner_;
+  bool is_reader_active_;
+
+  DISALLOW_COPY_AND_ASSIGN(Context);
+};
+
+SharedMemoryDataConsumerHandle::Writer::Writer(
+    const scoped_refptr<Context>& context,
+    BackpressureMode mode)
+    : context_(context), mode_(mode) {
+}
+
+SharedMemoryDataConsumerHandle::Writer::~Writer() {
+  Close();
+}
+
+void SharedMemoryDataConsumerHandle::Writer::AddData(
+    scoped_ptr<RequestPeer::ReceivedData> data) {
+  if (!data->length()) {
+    // We omit empty data.
+    return;
+  }
+
+  bool needs_notification = false;
+  {
+    base::AutoLock lock(context_->lock());
+    if (!context_->is_reader_active()) {
+      // No one is interested in the data.
+      return;
+    }
+
+    needs_notification = context_->client() && context_->IsEmpty();
+    scoped_ptr<RequestPeer::ThreadSafeReceivedData> data_to_pass;
+    if (mode_ == kApplyBackpressure) {
+      data_to_pass =
+          make_scoped_ptr(new DelegateThreadSafeReceivedData(data.Pass()));
+    } else {
+      data_to_pass = make_scoped_ptr(new FixedReceivedData(data.get()));
+    }
+    context_->Push(data_to_pass.Pass());
+  }
+
+  if (needs_notification)
+    context_->Notify();
+}
+
+void SharedMemoryDataConsumerHandle::Writer::Close() {
+  bool needs_notification = false;
+
+  {
+    base::AutoLock lock(context_->lock());
+    if (context_->result() == Ok) {
+      context_->set_result(Done);
+      needs_notification = context_->client() && context_->IsEmpty();
+    }
+  }
+  if (needs_notification)
+    context_->Notify();
+}
+
+SharedMemoryDataConsumerHandle::SharedMemoryDataConsumerHandle(
+    BackpressureMode mode,
+    scoped_ptr<Writer>* writer)
+    : context_(new Context) {
+  writer->reset(new Writer(context_, mode));
+}
+
+SharedMemoryDataConsumerHandle::~SharedMemoryDataConsumerHandle() {
+  base::AutoLock lock(context_->lock());
+  context_->set_is_reader_active(false);
+  context_->Clear();
+}
+
+Result SharedMemoryDataConsumerHandle::read(void* data,
+                                            size_t size,
+                                            Flags flags,
+                                            size_t* read_size_to_return) {
+  base::AutoLock lock(context_->lock());
+
+  size_t total_read_size = 0;
+  *read_size_to_return = 0;
+  if (context_->result() != Ok && context_->result() != Done)
+    return context_->result();
+
+  while (!context_->IsEmpty() && total_read_size < size) {
+    const auto& top = context_->Top();
+    size_t readable = top->length() - context_->first_offset();
+    size_t writable = size - total_read_size;
+    size_t read_size = std::min(readable, writable);
+    const char* begin = top->payload() + context_->first_offset();
+    std::copy(begin, begin + read_size,
+              static_cast<char*>(data) + total_read_size);
+    total_read_size += read_size;
+    context_->Consume(read_size);
+  }
+  *read_size_to_return = total_read_size;
+  return total_read_size ? Ok : context_->result() == Done ? Done : ShouldWait;
+}
+
+Result SharedMemoryDataConsumerHandle::beginRead(const void** buffer,
+                                                 Flags flags,
+                                                 size_t* available) {
+  *buffer = nullptr;
+  *available = 0;
+
+  base::AutoLock lock(context_->lock());
+
+  if (context_->result() != Ok && context_->result() != Done)
+    return context_->result();
+
+  if (context_->IsEmpty())
+    return context_->result() == Done ? Done : ShouldWait;
+
+  const auto& top = context_->Top();
+  *buffer = top->payload() + context_->first_offset();
+  *available = top->length() - context_->first_offset();
+
+  return Ok;
+}
+
+Result SharedMemoryDataConsumerHandle::endRead(size_t read_size) {
+  base::AutoLock lock(context_->lock());
+
+  if (context_->IsEmpty())
+    return UnexpectedError;
+
+  context_->Consume(read_size);
+  return Ok;
+}
+
+void SharedMemoryDataConsumerHandle::registerClient(Client* client) {
+  bool needs_notification = false;
+  {
+    base::AutoLock lock(context_->lock());
+
+    context_->SetClient(client);
+    needs_notification = !context_->IsEmpty();
+  }
+  if (needs_notification)
+    context_->Notify();
+}
+
+void SharedMemoryDataConsumerHandle::unregisterClient() {
+  base::AutoLock lock(context_->lock());
+
+  context_->SetClient(nullptr);
+}
+
+}  // namespace content
diff --git a/content/child/shared_memory_data_consumer_handle.h b/content/child/shared_memory_data_consumer_handle.h
new file mode 100644
index 0000000..03f3df0
--- /dev/null
+++ b/content/child/shared_memory_data_consumer_handle.h
@@ -0,0 +1,60 @@
+// 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 CONTENT_CHILD_SHARED_MEMORY_DATA_CONSUMER_HANDLE_H_
+#define CONTENT_CHILD_SHARED_MEMORY_DATA_CONSUMER_HANDLE_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "content/public/child/request_peer.h"
+#include "third_party/WebKit/public/platform/WebDataConsumerHandle.h"
+
+namespace content {
+
+// This class is a WebDataConsumerHandle that accepts RequestPeer::ReceivedData.
+class CONTENT_EXPORT SharedMemoryDataConsumerHandle final
+    : public NON_EXPORTED_BASE(blink::WebDataConsumerHandle) {
+ private:
+  class Context;
+
+ public:
+  enum BackpressureMode {
+    kApplyBackpressure,
+    kDoNotApplyBackpressure,
+  };
+
+  class CONTENT_EXPORT Writer final {
+   public:
+    Writer(const scoped_refptr<Context>& context, BackpressureMode mode);
+    ~Writer();
+    void AddData(scoped_ptr<RequestPeer::ReceivedData> data);
+    void Close();
+
+   private:
+    scoped_refptr<Context> context_;
+    BackpressureMode mode_;
+
+    DISALLOW_COPY_AND_ASSIGN(Writer);
+  };
+
+  SharedMemoryDataConsumerHandle(BackpressureMode mode,
+                                 scoped_ptr<Writer>* writer);
+  virtual ~SharedMemoryDataConsumerHandle();
+
+  virtual Result read(void* data, size_t size, Flags flags, size_t* readSize);
+  virtual Result beginRead(const void** buffer, Flags flags, size_t* available);
+  virtual Result endRead(size_t readSize);
+  virtual void registerClient(Client* client);
+  virtual void unregisterClient();
+
+ private:
+  scoped_refptr<Context> context_;
+
+  DISALLOW_COPY_AND_ASSIGN(SharedMemoryDataConsumerHandle);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_CHILD_SHARED_MEMORY_DATA_CONSUMER_HANDLE_H_
diff --git a/content/child/shared_memory_data_consumer_handle_unittest.cc b/content/child/shared_memory_data_consumer_handle_unittest.cc
new file mode 100644
index 0000000..8617aa5
--- /dev/null
+++ b/content/child/shared_memory_data_consumer_handle_unittest.cc
@@ -0,0 +1,694 @@
+// 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 "content/child/shared_memory_data_consumer_handle.h"
+
+#include <string.h>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/threading/thread.h"
+#include "content/public/child/fixed_received_data.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+using blink::WebDataConsumerHandle;
+using Result = WebDataConsumerHandle::Result;
+using Writer = SharedMemoryDataConsumerHandle::Writer;
+using BackpressureMode = SharedMemoryDataConsumerHandle::BackpressureMode;
+const BackpressureMode kApplyBackpressure =
+    SharedMemoryDataConsumerHandle::kApplyBackpressure;
+const BackpressureMode kDoNotApplyBackpressure =
+    SharedMemoryDataConsumerHandle::kDoNotApplyBackpressure;
+
+const WebDataConsumerHandle::Flags kNone = WebDataConsumerHandle::FlagNone;
+const Result kOk = WebDataConsumerHandle::Ok;
+const Result kDone = WebDataConsumerHandle::Done;
+const Result kShouldWait = WebDataConsumerHandle::ShouldWait;
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::MockFunction;
+using ::testing::Return;
+using ::testing::StrictMock;
+
+using Checkpoint = StrictMock<MockFunction<void(int)>>;
+using ReceivedData = RequestPeer::ReceivedData;
+
+class Logger final : public base::RefCounted<Logger> {
+ public:
+  Logger() {}
+  void Add(const std::string& entry) { log_ += entry + "\n"; }
+  const std::string& log() const { return log_; }
+
+ private:
+  friend class base::RefCounted<Logger>;
+  ~Logger() {}
+  std::string log_;
+
+  DISALLOW_COPY_AND_ASSIGN(Logger);
+};
+
+class LoggingFixedReceivedData final : public RequestPeer::ReceivedData {
+ public:
+  LoggingFixedReceivedData(const char* name,
+                           const char* s,
+                           scoped_refptr<Logger> logger)
+      : name_(name), data_(s, s + strlen(s)), logger_(logger) {}
+  ~LoggingFixedReceivedData() override {
+    logger_->Add(name_ + " is destructed.");
+  }
+
+  const char* payload() const override {
+    return data_.empty() ? nullptr : &data_[0];
+  }
+  int length() const override { return static_cast<int>(data_.size()); }
+  int encoded_length() const override { return static_cast<int>(data_.size()); }
+
+ private:
+  const std::string name_;
+  const std::vector<char> data_;
+  scoped_refptr<Logger> logger_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoggingFixedReceivedData);
+};
+
+class MockClient : public WebDataConsumerHandle::Client {
+ public:
+  MOCK_METHOD0(didGetReadable, void());
+};
+
+std::string ToString(const void* p, size_t size) {
+  const char* q = static_cast<const char*>(p);
+  return std::string(q, q + size);
+}
+
+class ThreadedSharedMemoryDataConsumerHandleTest : public ::testing::Test {
+ protected:
+  class ReadDataOperation;
+  class ClientImpl final : public WebDataConsumerHandle::Client {
+   public:
+    explicit ClientImpl(ReadDataOperation* operation) : operation_(operation) {}
+
+    void didGetReadable() override { operation_->ReadData(); }
+
+   private:
+    ReadDataOperation* operation_;
+  };
+
+  class ReadDataOperation final {
+   public:
+    typedef WebDataConsumerHandle::Result Result;
+    ReadDataOperation(scoped_ptr<WebDataConsumerHandle> handle,
+                      base::MessageLoop* main_message_loop,
+                      const base::Closure& on_done)
+        : handle_(handle.Pass()),
+          main_message_loop_(main_message_loop),
+          on_done_(on_done) {}
+
+    const std::string& result() const { return result_; }
+
+    void ReadData() {
+      if (!client_) {
+        client_.reset(new ClientImpl(this));
+        handle_->registerClient(client_.get());
+      }
+
+      Result rv = kOk;
+      size_t read_size = 0;
+
+      while (true) {
+        char buffer[16];
+        rv = handle_->read(&buffer, sizeof(buffer), kNone, &read_size);
+        if (rv != kOk)
+          break;
+        result_.insert(result_.size(), &buffer[0], read_size);
+      }
+
+      if (rv == kShouldWait) {
+        // Wait a while...
+        return;
+      }
+
+      if (rv != kDone) {
+        // Something is wrong.
+        result_ = "error";
+      }
+
+      // The operation is done.
+      main_message_loop_->PostTask(FROM_HERE, on_done_);
+    }
+
+   private:
+    scoped_ptr<WebDataConsumerHandle> handle_;
+    scoped_ptr<WebDataConsumerHandle::Client> client_;
+    base::MessageLoop* main_message_loop_;
+    base::Closure on_done_;
+    std::string result_;
+  };
+
+  void SetUp() override {
+    handle_.reset(
+        new SharedMemoryDataConsumerHandle(kApplyBackpressure, &writer_));
+  }
+
+  StrictMock<MockClient> client_;
+  scoped_ptr<WebDataConsumerHandle> handle_;
+  scoped_ptr<Writer> writer_;
+  base::MessageLoop loop_;
+};
+
+class SharedMemoryDataConsumerHandleTest
+    : public ::testing::TestWithParam<BackpressureMode> {
+ protected:
+  void SetUp() override {
+    handle_.reset(new SharedMemoryDataConsumerHandle(GetParam(), &writer_));
+  }
+  scoped_ptr<FixedReceivedData> NewFixedData(const char* s) {
+    return make_scoped_ptr(new FixedReceivedData(s, strlen(s), strlen(s)));
+  }
+
+  StrictMock<MockClient> client_;
+  scoped_ptr<SharedMemoryDataConsumerHandle> handle_;
+  scoped_ptr<Writer> writer_;
+  base::MessageLoop loop_;
+};
+
+TEST_P(SharedMemoryDataConsumerHandleTest, ReadFromEmpty) {
+  char buffer[4];
+  size_t read = 88;
+  Result result = handle_->read(buffer, 4, kNone, &read);
+
+  EXPECT_EQ(kShouldWait, result);
+  EXPECT_EQ(0u, read);
+}
+
+TEST_P(SharedMemoryDataConsumerHandleTest, AutoClose) {
+  char buffer[4];
+  size_t read = 88;
+
+  writer_.reset();
+  Result result = handle_->read(buffer, 4, kNone, &read);
+
+  EXPECT_EQ(kDone, result);
+  EXPECT_EQ(0u, read);
+}
+
+TEST_P(SharedMemoryDataConsumerHandleTest, ReadSimple) {
+  writer_->AddData(NewFixedData("hello"));
+
+  char buffer[4] = {};
+  size_t read = 88;
+  Result result = handle_->read(buffer, 3, kNone, &read);
+
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(3u, read);
+  EXPECT_STREQ("hel", buffer);
+
+  result = handle_->read(buffer, 3, kNone, &read);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(2u, read);
+  EXPECT_STREQ("lol", buffer);
+
+  result = handle_->read(buffer, 3, kNone, &read);
+  EXPECT_EQ(kShouldWait, result);
+  EXPECT_EQ(0u, read);
+
+  writer_->Close();
+
+  result = handle_->read(buffer, 3, kNone, &read);
+  EXPECT_EQ(kDone, result);
+  EXPECT_EQ(0u, read);
+}
+
+TEST_P(SharedMemoryDataConsumerHandleTest, CloseBeforeReading) {
+  writer_->AddData(NewFixedData("hello"));
+  writer_->Close();
+
+  char buffer[20] = {};
+  size_t read = 88;
+  Result result = handle_->read(buffer, sizeof(buffer), kNone, &read);
+
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(5u, read);
+  EXPECT_STREQ("hello", buffer);
+
+  result = handle_->read(buffer, sizeof(buffer), kNone, &read);
+  EXPECT_EQ(kDone, result);
+  EXPECT_EQ(0u, read);
+}
+
+TEST_P(SharedMemoryDataConsumerHandleTest, AddMultipleData) {
+  writer_->AddData(NewFixedData("Once "));
+  writer_->AddData(NewFixedData("upon "));
+  writer_->AddData(NewFixedData("a "));
+  writer_->AddData(NewFixedData("time "));
+  writer_->AddData(NewFixedData("there "));
+  writer_->AddData(NewFixedData("was "));
+  writer_->AddData(NewFixedData("a "));
+  writer_->Close();
+
+  char buffer[20];
+  size_t read;
+  Result result;
+
+  std::fill(&buffer[0], &buffer[arraysize(buffer)], 0);
+  result = handle_->read(buffer, 6, kNone, &read);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(6u, read);
+  EXPECT_STREQ("Once u", buffer);
+
+  std::fill(&buffer[0], &buffer[arraysize(buffer)], 0);
+  result = handle_->read(buffer, 2, kNone, &read);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(2u, read);
+  EXPECT_STREQ("po", buffer);
+
+  std::fill(&buffer[0], &buffer[arraysize(buffer)], 0);
+  result = handle_->read(buffer, 9, kNone, &read);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(9u, read);
+  EXPECT_STREQ("n a time ", buffer);
+
+  std::fill(&buffer[0], &buffer[arraysize(buffer)], 0);
+  result = handle_->read(buffer, 3, kNone, &read);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(3u, read);
+  EXPECT_STREQ("the", buffer);
+
+  std::fill(&buffer[0], &buffer[arraysize(buffer)], 0);
+  result = handle_->read(buffer, 20, kNone, &read);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(9u, read);
+  EXPECT_STREQ("re was a ", buffer);
+
+  result = handle_->read(buffer, sizeof(buffer), kNone, &read);
+  EXPECT_EQ(kDone, result);
+  EXPECT_EQ(0u, read);
+}
+
+TEST_P(SharedMemoryDataConsumerHandleTest, AddMultipleDataInteractively) {
+  writer_->AddData(NewFixedData("Once "));
+  writer_->AddData(NewFixedData("upon "));
+
+  char buffer[20];
+  size_t read;
+  Result result;
+
+  std::fill(&buffer[0], &buffer[arraysize(buffer)], 0);
+  result = handle_->read(buffer, 6, kNone, &read);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(6u, read);
+  EXPECT_STREQ("Once u", buffer);
+
+  std::fill(&buffer[0], &buffer[arraysize(buffer)], 0);
+  result = handle_->read(buffer, 2, kNone, &read);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(2u, read);
+  EXPECT_STREQ("po", buffer);
+
+  std::fill(&buffer[0], &buffer[arraysize(buffer)], 0);
+  result = handle_->read(buffer, 9, kNone, &read);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(2u, read);
+  EXPECT_STREQ("n ", buffer);
+
+  writer_->AddData(NewFixedData("a "));
+
+  std::fill(&buffer[0], &buffer[arraysize(buffer)], 0);
+  result = handle_->read(buffer, 1, kNone, &read);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(1u, read);
+  EXPECT_STREQ("a", buffer);
+
+  writer_->AddData(NewFixedData("time "));
+  writer_->AddData(NewFixedData("there "));
+  writer_->AddData(NewFixedData("was "));
+  writer_->AddData(NewFixedData("a "));
+  writer_->Close();
+
+  std::fill(&buffer[0], &buffer[arraysize(buffer)], 0);
+  result = handle_->read(buffer, 9, kNone, &read);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(9u, read);
+  EXPECT_STREQ(" time the", buffer);
+
+  std::fill(&buffer[0], &buffer[arraysize(buffer)], 0);
+  result = handle_->read(buffer, 20, kNone, &read);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(9u, read);
+  EXPECT_STREQ("re was a ", buffer);
+
+  result = handle_->read(buffer, sizeof(buffer), kNone, &read);
+  EXPECT_EQ(kDone, result);
+  EXPECT_EQ(0u, read);
+}
+
+TEST_P(SharedMemoryDataConsumerHandleTest, RegisterClient) {
+  Checkpoint checkpoint;
+
+  InSequence s;
+  EXPECT_CALL(checkpoint, Call(0));
+  EXPECT_CALL(checkpoint, Call(1));
+  EXPECT_CALL(client_, didGetReadable());
+  EXPECT_CALL(checkpoint, Call(2));
+
+  checkpoint.Call(0);
+  handle_->registerClient(&client_);
+  checkpoint.Call(1);
+  writer_->Close();
+  checkpoint.Call(2);
+}
+
+TEST_P(SharedMemoryDataConsumerHandleTest, RegisterClientWhenDataExists) {
+  Checkpoint checkpoint;
+
+  InSequence s;
+  EXPECT_CALL(checkpoint, Call(0));
+  EXPECT_CALL(checkpoint, Call(1));
+  EXPECT_CALL(client_, didGetReadable());
+  EXPECT_CALL(checkpoint, Call(2));
+
+  checkpoint.Call(0);
+  writer_->AddData(NewFixedData("Once "));
+  checkpoint.Call(1);
+  handle_->registerClient(&client_);
+  checkpoint.Call(2);
+}
+
+TEST_P(SharedMemoryDataConsumerHandleTest, AddDataWhenClientIsRegistered) {
+  Checkpoint checkpoint;
+  char buffer[20];
+  Result result;
+  size_t size;
+
+  InSequence s;
+  EXPECT_CALL(checkpoint, Call(0));
+  EXPECT_CALL(checkpoint, Call(1));
+  EXPECT_CALL(client_, didGetReadable());
+  EXPECT_CALL(checkpoint, Call(2));
+  EXPECT_CALL(checkpoint, Call(3));
+  EXPECT_CALL(checkpoint, Call(4));
+  EXPECT_CALL(client_, didGetReadable());
+  EXPECT_CALL(checkpoint, Call(5));
+
+  checkpoint.Call(0);
+  handle_->registerClient(&client_);
+  checkpoint.Call(1);
+  writer_->AddData(NewFixedData("Once "));
+  checkpoint.Call(2);
+  writer_->AddData(NewFixedData("upon "));
+  checkpoint.Call(3);
+  result = handle_->read(buffer, sizeof(buffer), kNone, &size);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(10u, size);
+  checkpoint.Call(4);
+  writer_->AddData(NewFixedData("a "));
+  checkpoint.Call(5);
+}
+
+TEST_P(SharedMemoryDataConsumerHandleTest, CloseWithClientAndData) {
+  Checkpoint checkpoint;
+
+  InSequence s;
+  EXPECT_CALL(checkpoint, Call(0));
+  EXPECT_CALL(checkpoint, Call(1));
+  EXPECT_CALL(client_, didGetReadable());
+  EXPECT_CALL(checkpoint, Call(2));
+  EXPECT_CALL(checkpoint, Call(3));
+
+  checkpoint.Call(0);
+  handle_->registerClient(&client_);
+  checkpoint.Call(1);
+  writer_->AddData(NewFixedData("Once "));
+  checkpoint.Call(2);
+  writer_->Close();
+  checkpoint.Call(3);
+}
+
+TEST_P(SharedMemoryDataConsumerHandleTest, UnregisterClient) {
+  Checkpoint checkpoint;
+
+  InSequence s;
+  EXPECT_CALL(checkpoint, Call(0));
+  EXPECT_CALL(checkpoint, Call(1));
+  EXPECT_CALL(checkpoint, Call(2));
+
+  checkpoint.Call(0);
+  handle_->registerClient(&client_);
+  checkpoint.Call(1);
+  handle_->unregisterClient();
+  writer_->AddData(NewFixedData("Once "));
+  checkpoint.Call(2);
+}
+
+TEST_P(SharedMemoryDataConsumerHandleTest, TwoPhaseReadShouldWait) {
+  Result result;
+  const void* buffer = &result;
+  size_t size = 99;
+
+  result = handle_->beginRead(&buffer, kNone, &size);
+  EXPECT_EQ(kShouldWait, result);
+  EXPECT_EQ(nullptr, buffer);
+  EXPECT_EQ(0u, size);
+}
+
+TEST_P(SharedMemoryDataConsumerHandleTest, TwoPhaseReadSimple) {
+  writer_->AddData(NewFixedData("Once "));
+
+  Result result;
+  const void* buffer = &result;
+  size_t size = 99;
+
+  result = handle_->beginRead(&buffer, kNone, &size);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(5u, size);
+  EXPECT_EQ("Once ", ToString(buffer, 5));
+
+  handle_->endRead(1);
+
+  result = handle_->beginRead(&buffer, kNone, &size);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(4u, size);
+  EXPECT_EQ("nce ", ToString(buffer, 4));
+
+  handle_->endRead(4);
+
+  result = handle_->beginRead(&buffer, kNone, &size);
+  EXPECT_EQ(kShouldWait, result);
+  EXPECT_EQ(0u, size);
+  EXPECT_EQ(nullptr, buffer);
+
+  writer_->Close();
+
+  result = handle_->beginRead(&buffer, kNone, &size);
+  EXPECT_EQ(kDone, result);
+  EXPECT_EQ(0u, size);
+  EXPECT_EQ(nullptr, buffer);
+}
+
+TEST_P(SharedMemoryDataConsumerHandleTest, TwoPhaseReadWithMultipleData) {
+  writer_->AddData(NewFixedData("Once "));
+  writer_->AddData(NewFixedData("upon "));
+
+  Result result;
+  const void* buffer = &result;
+  size_t size = 99;
+
+  result = handle_->beginRead(&buffer, kNone, &size);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(5u, size);
+  EXPECT_EQ("Once ", ToString(buffer, 5));
+
+  handle_->endRead(1);
+
+  result = handle_->beginRead(&buffer, kNone, &size);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(4u, size);
+  EXPECT_EQ("nce ", ToString(buffer, 4));
+
+  handle_->endRead(4);
+
+  result = handle_->beginRead(&buffer, kNone, &size);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(5u, size);
+  EXPECT_EQ("upon ", ToString(buffer, 5));
+
+  handle_->endRead(5);
+
+  result = handle_->beginRead(&buffer, kNone, &size);
+  EXPECT_EQ(kShouldWait, result);
+  EXPECT_EQ(0u, size);
+  EXPECT_EQ(nullptr, buffer);
+
+  writer_->Close();
+
+  result = handle_->beginRead(&buffer, kNone, &size);
+  EXPECT_EQ(kDone, result);
+  EXPECT_EQ(0u, size);
+  EXPECT_EQ(nullptr, buffer);
+}
+
+TEST(SharedMemoryDataConsumerHandleBackpressureTest, Read) {
+  base::MessageLoop loop;
+  char buffer[20];
+  Result result;
+  size_t size;
+
+  scoped_ptr<Writer> writer;
+  auto handle = make_scoped_ptr(
+      new SharedMemoryDataConsumerHandle(kApplyBackpressure, &writer));
+  scoped_refptr<Logger> logger(new Logger);
+  writer->AddData(
+      make_scoped_ptr(new LoggingFixedReceivedData("data1", "Once ", logger)));
+  writer->AddData(
+      make_scoped_ptr(new LoggingFixedReceivedData("data2", "upon ", logger)));
+  writer->AddData(
+      make_scoped_ptr(new LoggingFixedReceivedData("data3", "a ", logger)));
+  writer->AddData(
+      make_scoped_ptr(new LoggingFixedReceivedData("data4", "time ", logger)));
+
+  logger->Add("1");
+  result = handle->read(buffer, 2, kNone, &size);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(2u, size);
+  logger->Add("2");
+  result = handle->read(buffer, 5, kNone, &size);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(5u, size);
+  logger->Add("3");
+  result = handle->read(buffer, 6, kNone, &size);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(6u, size);
+  logger->Add("4");
+
+  EXPECT_EQ(
+      "1\n"
+      "2\n"
+      "data1 is destructed.\n"
+      "3\n"
+      "data2 is destructed.\n"
+      "data3 is destructed.\n"
+      "4\n",
+      logger->log());
+}
+
+TEST(SharedMemoryDataConsumerHandleBackpressureTest, CloseAndReset) {
+  base::MessageLoop loop;
+  char buffer[20];
+  Result result;
+  size_t size;
+
+  scoped_ptr<Writer> writer;
+  auto handle = make_scoped_ptr(
+      new SharedMemoryDataConsumerHandle(kApplyBackpressure, &writer));
+  scoped_refptr<Logger> logger(new Logger);
+  writer->AddData(
+      make_scoped_ptr(new LoggingFixedReceivedData("data1", "Once ", logger)));
+  writer->AddData(
+      make_scoped_ptr(new LoggingFixedReceivedData("data2", "upon ", logger)));
+  writer->AddData(
+      make_scoped_ptr(new LoggingFixedReceivedData("data3", "a ", logger)));
+
+  logger->Add("1");
+  result = handle->read(buffer, 2, kNone, &size);
+  EXPECT_EQ(kOk, result);
+  EXPECT_EQ(2u, size);
+  logger->Add("2");
+  writer->Close();
+  logger->Add("3");
+  handle.reset();
+  logger->Add("4");
+
+  EXPECT_EQ(
+      "1\n"
+      "2\n"
+      "3\n"
+      "data1 is destructed.\n"
+      "data2 is destructed.\n"
+      "data3 is destructed.\n"
+      "4\n",
+      logger->log());
+}
+
+TEST(SharedMemoryDataConsumerHandleWithoutBackpressureTest, AddData) {
+  base::MessageLoop loop;
+  scoped_ptr<Writer> writer;
+  auto handle = make_scoped_ptr(
+      new SharedMemoryDataConsumerHandle(kDoNotApplyBackpressure, &writer));
+  scoped_refptr<Logger> logger(new Logger);
+
+  logger->Add("1");
+  writer->AddData(
+      make_scoped_ptr(new LoggingFixedReceivedData("data1", "Once ", logger)));
+  logger->Add("2");
+  writer->AddData(
+      make_scoped_ptr(new LoggingFixedReceivedData("data2", "upon ", logger)));
+  logger->Add("3");
+
+  EXPECT_EQ(
+      "1\n"
+      "data1 is destructed.\n"
+      "2\n"
+      "data2 is destructed.\n"
+      "3\n",
+      logger->log());
+}
+
+TEST_F(ThreadedSharedMemoryDataConsumerHandleTest, Read) {
+  base::RunLoop run_loop;
+  auto operation = make_scoped_ptr(
+      new ReadDataOperation(handle_.Pass(), &loop_, run_loop.QuitClosure()));
+  scoped_refptr<Logger> logger(new Logger);
+
+  base::Thread t("DataConsumerHandle test thread");
+  ASSERT_TRUE(t.Start());
+
+  t.message_loop()->PostTask(FROM_HERE,
+                             base::Bind(&ReadDataOperation::ReadData,
+                                        base::Unretained(operation.get())));
+
+  logger->Add("1");
+  writer_->AddData(
+      make_scoped_ptr(new LoggingFixedReceivedData("data1", "Once ", logger)));
+  writer_->AddData(
+      make_scoped_ptr(new LoggingFixedReceivedData("data2", "upon ", logger)));
+  writer_->AddData(make_scoped_ptr(
+      new LoggingFixedReceivedData("data3", "a time ", logger)));
+  writer_->AddData(
+      make_scoped_ptr(new LoggingFixedReceivedData("data4", "there ", logger)));
+  writer_->AddData(
+      make_scoped_ptr(new LoggingFixedReceivedData("data5", "was ", logger)));
+  writer_->Close();
+  logger->Add("2");
+
+  run_loop.Run();
+  t.Stop();
+
+  EXPECT_EQ("Once upon a time there was ", operation->result());
+  EXPECT_EQ(
+      "1\n"
+      "2\n"
+      "data1 is destructed.\n"
+      "data2 is destructed.\n"
+      "data3 is destructed.\n"
+      "data4 is destructed.\n"
+      "data5 is destructed.\n",
+      logger->log());
+}
+
+INSTANTIATE_TEST_CASE_P(SharedMemoryDataConsumerHandleTest,
+                        SharedMemoryDataConsumerHandleTest,
+                        ::testing::Values(kApplyBackpressure,
+                                          kDoNotApplyBackpressure));
+}  // namespace
+
+}  // namespace content
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc
index 4280dbc..6cd625e7 100644
--- a/content/child/web_url_loader_impl.cc
+++ b/content/child/web_url_loader_impl.cc
@@ -994,6 +994,8 @@
     const TimeTicks kNullTicks;
     timing.setWorkerStart(
         (info.service_worker_start_time - kNullTicks).InSecondsF());
+    timing.setWorkerReady(
+        (info.service_worker_ready_time - kNullTicks).InSecondsF());
     response->setLoadTiming(timing);
   }
 
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index ecfe362c..09f7a4a 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -486,9 +486,12 @@
     "geolocation_service.mojom",
     "permission_service.mojom",
     "presentation/presentation_service.mojom",
+    "process_control.mojom",
     "render_frame_setup.mojom",
   ]
 
+  import_dirs = [ "//mojo/services" ]
+
   deps = [
     "//content/public/common:mojo_bindings",
     "//mojo/application/public/interfaces",
diff --git a/content/common/accessibility_messages.h b/content/common/accessibility_messages.h
index e7d0bcdf..91a2b4f9 100644
--- a/content/common/accessibility_messages.h
+++ b/content/common/accessibility_messages.h
@@ -128,6 +128,10 @@
                     int /* object id */,
                     gfx::Rect /* subfocus */)
 
+// Relay a request from assistive technology to show the context menu for a
+// given object.
+IPC_MESSAGE_ROUTED1(AccessibilityMsg_ShowContextMenu, int /* object id */)
+
 // Relay a request from assistive technology to move a given object
 // to a specific location, in the WebContents area coordinate space, i.e.
 // (0, 0) is the top-left corner of the WebContents.
diff --git a/content/common/gpu/client/gpu_channel_host.cc b/content/common/gpu/client/gpu_channel_host.cc
index b4460bb..60c5bbe 100644
--- a/content/common/gpu/client/gpu_channel_host.cc
+++ b/content/common/gpu/client/gpu_channel_host.cc
@@ -18,7 +18,7 @@
 #include "ipc/ipc_sync_message_filter.h"
 #include "url/gurl.h"
 
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_MACOSX)
 #include "content/public/common/sandbox_init.h"
 #endif
 
@@ -303,8 +303,9 @@
   if (IsLost())
     return base::SharedMemory::NULLHandle();
 
-#if defined(OS_WIN)
-  // Windows needs to explicitly duplicate the handle out to another process.
+#if defined(OS_WIN) || defined(OS_MACOSX)
+  // Windows and Mac need to explicitly duplicate the handle out to another
+  // process.
   base::SharedMemoryHandle target_handle;
   base::ProcessId peer_pid;
   {
@@ -313,22 +314,21 @@
       return base::SharedMemory::NULLHandle();
     peer_pid = channel_->GetPeerPID();
   }
-  if (!BrokerDuplicateHandle(source_handle,
-                             peer_pid,
-                             &target_handle,
-                             FILE_GENERIC_READ | FILE_GENERIC_WRITE,
-                             0)) {
+#if defined(OS_WIN)
+  bool success =
+      BrokerDuplicateHandle(source_handle, peer_pid, &target_handle,
+                            FILE_GENERIC_READ | FILE_GENERIC_WRITE, 0);
+#elif defined(OS_MACOSX)
+  bool success = BrokerDuplicateSharedMemoryHandle(source_handle, peer_pid,
+                                                   &target_handle);
+#endif
+  if (!success)
     return base::SharedMemory::NULLHandle();
-  }
 
   return target_handle;
 #else
-  int duped_handle = HANDLE_EINTR(dup(source_handle.fd));
-  if (duped_handle < 0)
-    return base::SharedMemory::NULLHandle();
-
-  return base::FileDescriptor(duped_handle, true);
-#endif
+  return base::SharedMemory::DuplicateHandle(source_handle);
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
 }
 
 int32 GpuChannelHost::ReserveTransferBufferId() {
diff --git a/content/common/gpu/gpu_channel_manager.cc b/content/common/gpu/gpu_channel_manager.cc
index 73dd502d..4cec7cb 100644
--- a/content/common/gpu/gpu_channel_manager.cc
+++ b/content/common/gpu/gpu_channel_manager.cc
@@ -4,14 +4,11 @@
 
 #include "content/common/gpu/gpu_channel_manager.h"
 
-#include <algorithm>
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "base/trace_event/process_memory_dump.h"
 #include "content/common/gpu/gpu_channel.h"
 #include "content/common/gpu/gpu_memory_buffer_factory.h"
 #include "content/common/gpu/gpu_memory_manager.h"
@@ -115,8 +112,6 @@
   DCHECK(router_);
   DCHECK(io_task_runner);
   DCHECK(shutdown_event);
-  base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
-      this, io_task_runner_);
   channel_->AddFilter(filter_.get());
 }
 
@@ -348,23 +343,6 @@
   return default_offscreen_surface_.get();
 }
 
-bool GpuChannelManager::OnMemoryDump(
-    base::trace_event::ProcessMemoryDump* pmd) {
-  for (const auto& channel : gpu_channels_) {
-    auto dump_name = channel.second->GetChannelName();
-    std::replace(dump_name.begin(), dump_name.end(), '.', '_');
-
-    base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(
-        base::StringPrintf("gl/%s", dump_name.c_str()));
-
-    dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
-                    base::trace_event::MemoryAllocatorDump::kUnitsBytes,
-                    channel.second->GetMemoryUsage());
-  }
-
-  return true;
-}
-
 void GpuChannelManager::OnRelinquishResources() {
   relinquish_resources_pending_ = true;
   CheckRelinquishGpuResources();
diff --git a/content/common/gpu/gpu_channel_manager.h b/content/common/gpu/gpu_channel_manager.h
index 0b0d2180b..a15a8adb 100644
--- a/content/common/gpu/gpu_channel_manager.h
+++ b/content/common/gpu/gpu_channel_manager.h
@@ -13,7 +13,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "base/trace_event/memory_dump_provider.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
 #include "content/common/content_param_traits.h"
@@ -61,8 +60,7 @@
 // managing the lifetimes of GPU channels and forwarding IPC requests from the
 // browser process to them based on the corresponding renderer ID.
 class CONTENT_EXPORT GpuChannelManager : public IPC::Listener,
-                          public IPC::Sender,
-                          public base::trace_event::MemoryDumpProvider {
+                          public IPC::Sender {
  public:
   GpuChannelManager(MessageRouter* router,
                     GpuWatchdog* watchdog,
@@ -106,9 +104,6 @@
     return gpu_memory_buffer_factory_.get();
   }
 
-  // base::trace_event::MemoryDumpProvider implementation.
-  bool OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd) override;
-
  private:
   typedef base::ScopedPtrHashMap<int, scoped_ptr<GpuChannel>> GpuChannelMap;
 
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc
index 729f66d7d..bd57c41 100644
--- a/content/common/gpu/gpu_command_buffer_stub.cc
+++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -22,6 +22,7 @@
 #include "content/common/gpu/media/gpu_video_decode_accelerator.h"
 #include "content/common/gpu/media/gpu_video_encode_accelerator.h"
 #include "content/public/common/content_client.h"
+#include "content/public/common/content_switches.h"
 #include "gpu/command_buffer/common/constants.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "gpu/command_buffer/common/mailbox.h"
@@ -472,6 +473,13 @@
 
   decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group_.get()));
 
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSingleProcess) &&
+      !base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kInProcessGPU)) {
+    decoder_->SetAllowExit(true);
+  }
+
   scheduler_.reset(new gpu::GpuScheduler(command_buffer_.get(),
                                          decoder_.get(),
                                          decoder_.get()));
diff --git a/content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc b/content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc
index fa12bf9..dfc0e38 100644
--- a/content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc
+++ b/content/common/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "ui/gl/gl_image.h"
+#include "ui/ozone/public/ozone_platform.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
 
 namespace content {
@@ -41,8 +42,9 @@
 void GpuMemoryBufferFactoryOzoneNativeBuffer::
     GetSupportedGpuMemoryBufferConfigurations(
         std::vector<Configuration>* configurations) {
-  if (!ui::SurfaceFactoryOzone::GetInstance()->CanCreateNativePixmap(
-          ui::SurfaceFactoryOzone::SCANOUT))
+  if (!ui::OzonePlatform::GetInstance()
+           ->GetSurfaceFactoryOzone()
+           ->CanCreateNativePixmap(ui::SurfaceFactoryOzone::SCANOUT))
     return;
 
   configurations->assign(
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h
index 2f30dacd..7e507e4 100644
--- a/content/common/gpu/gpu_messages.h
+++ b/content/common/gpu/gpu_messages.h
@@ -89,16 +89,17 @@
   IPC_STRUCT_MEMBER(gfx::PluginWindowHandle, surface_handle)
 IPC_STRUCT_END()
 
+#if defined(OS_MACOSX)
 IPC_STRUCT_BEGIN(GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params)
   IPC_STRUCT_MEMBER(int32, surface_id)
   IPC_STRUCT_MEMBER(uint64, surface_handle)
   IPC_STRUCT_MEMBER(int32, route_id)
   IPC_STRUCT_MEMBER(gfx::Size, size)
+  IPC_STRUCT_MEMBER(gfx::Rect, damage_rect)
   IPC_STRUCT_MEMBER(float, scale_factor)
   IPC_STRUCT_MEMBER(std::vector<ui::LatencyInfo>, latency_info)
 IPC_STRUCT_END()
 
-#if defined(OS_MACOSX)
 IPC_STRUCT_BEGIN(AcceleratedSurfaceMsg_BufferPresented_Params)
   // If the browser needs framerate throttling based on GPU back-pressure to be
   // disabled (e.g, because the NSView isn't visible but tab capture is active),
@@ -393,9 +394,12 @@
                      int32 /* surface_id */,
                      int32 /* route_id */)
 
-// Same as above with a rect of the part of the surface that changed.
+
+#if defined(OS_MACOSX)
+// Tells the browser that an accelerated surface has swapped.
 IPC_MESSAGE_CONTROL1(GpuHostMsg_AcceleratedSurfaceBuffersSwapped,
                      GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params)
+#endif
 
 IPC_MESSAGE_CONTROL1(GpuHostMsg_DidCreateOffscreenContext,
                      GURL /* url */)
diff --git a/content/common/gpu/image_transport_surface.cc b/content/common/gpu/image_transport_surface.cc
index 6d2808f..587d3a5 100644
--- a/content/common/gpu/image_transport_surface.cc
+++ b/content/common/gpu/image_transport_surface.cc
@@ -96,6 +96,7 @@
   return handled;
 }
 
+#if defined(OS_MACOSX)
 void ImageTransportHelper::SendAcceleratedSurfaceBuffersSwapped(
     GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params) {
   // TRACE_EVENT for gpu tests:
@@ -107,6 +108,7 @@
   params.route_id = route_id_;
   manager_->Send(new GpuHostMsg_AcceleratedSurfaceBuffersSwapped(params));
 }
+#endif
 
 void ImageTransportHelper::SetPreemptByFlag(
     scoped_refptr<gpu::PreemptionFlag> preemption_flag) {
diff --git a/content/common/gpu/image_transport_surface.h b/content/common/gpu/image_transport_surface.h
index c0bceaba..397dd78a 100644
--- a/content/common/gpu/image_transport_surface.h
+++ b/content/common/gpu/image_transport_surface.h
@@ -22,8 +22,10 @@
 #include "ui/gfx/swap_result.h"
 #include "ui/gl/gl_surface.h"
 
+#if defined(OS_MACOSX)
 struct AcceleratedSurfaceMsg_BufferPresented_Params;
 struct GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params;
+#endif
 
 namespace gfx {
 class GLSurface;
@@ -122,8 +124,10 @@
 
   // Helper send functions. Caller fills in the surface specific params
   // like size and surface id. The helper fills in the rest.
+#if defined(OS_MACOSX)
   void SendAcceleratedSurfaceBuffersSwapped(
       GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params);
+#endif
 
   void SetPreemptByFlag(
       scoped_refptr<gpu::PreemptionFlag> preemption_flag);
diff --git a/content/common/gpu/image_transport_surface_fbo_mac.h b/content/common/gpu/image_transport_surface_fbo_mac.h
index d39e2459..6b22801 100644
--- a/content/common/gpu/image_transport_surface_fbo_mac.h
+++ b/content/common/gpu/image_transport_surface_fbo_mac.h
@@ -133,6 +133,7 @@
   // Whether a SwapBuffers IPC needs to be sent to the browser.
   bool is_swap_buffers_send_pending_;
   std::vector<ui::LatencyInfo> latency_info_;
+  gfx::Rect pending_swap_pixel_damage_rect_;
 
   scoped_ptr<ImageTransportHelper> helper_;
 
diff --git a/content/common/gpu/image_transport_surface_fbo_mac.mm b/content/common/gpu/image_transport_surface_fbo_mac.mm
index 102a6b3..ec827c2e 100644
--- a/content/common/gpu/image_transport_surface_fbo_mac.mm
+++ b/content/common/gpu/image_transport_surface_fbo_mac.mm
@@ -171,6 +171,7 @@
 
 gfx::SwapResult ImageTransportSurfaceFBO::SwapBuffers() {
   TRACE_EVENT0("gpu", "ImageTransportSurfaceFBO::SwapBuffers");
+  pending_swap_pixel_damage_rect_ = gfx::Rect(pixel_size_);
   return SwapBuffersInternal() ? gfx::SwapResult::SWAP_ACK
                                : gfx::SwapResult::SWAP_FAILED;
 }
@@ -198,10 +199,12 @@
   GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
   params.surface_handle = surface_handle;
   params.size = pixel_size;
+  params.damage_rect = pending_swap_pixel_damage_rect_;
   params.scale_factor = scale_factor;
   params.latency_info.swap(latency_info_);
   helper_->SendAcceleratedSurfaceBuffersSwapped(params);
   is_swap_buffers_send_pending_ = false;
+  pending_swap_pixel_damage_rect_ = gfx::Rect();
 }
 
 void ImageTransportSurfaceFBO::SetRendererID(int renderer_id) {
@@ -214,6 +217,7 @@
                                                         int width,
                                                         int height) {
   TRACE_EVENT0("gpu", "ImageTransportSurfaceFBO::PostSubBuffer");
+  pending_swap_pixel_damage_rect_.Union(gfx::Rect(x, y, width, height));
   return SwapBuffersInternal() ? gfx::SwapResult::SWAP_ACK
                                : gfx::SwapResult::SWAP_FAILED;
 }
diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.cc b/content/common/gpu/media/gpu_video_decode_accelerator.cc
index c4d7eb9..99a782f 100644
--- a/content/common/gpu/media/gpu_video_decode_accelerator.cc
+++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc
@@ -479,17 +479,9 @@
         texture_target_ == GL_TEXTURE_RECTANGLE_ARB) {
       // These textures have their dimensions defined by the underlying storage.
       // Use |texture_dimensions_| for this size.
-      texture_manager->SetLevelInfo(texture_ref,
-                                    texture_target_,
-                                    0,
-                                    GL_RGBA,
-                                    texture_dimensions_.width(),
-                                    texture_dimensions_.height(),
-                                    1,
-                                    0,
-                                    GL_RGBA,
-                                    0,
-                                    false);
+      texture_manager->SetLevelInfo(
+          texture_ref, texture_target_, 0, GL_RGBA, texture_dimensions_.width(),
+          texture_dimensions_.height(), 1, 0, GL_RGBA, 0, gfx::Rect());
     } else {
       // For other targets, texture dimensions should already be defined.
       GLsizei width = 0, height = 0;
@@ -506,7 +498,8 @@
           video_decode_accelerator_.get()->GetSurfaceInternalFormat();
       if (format != GL_RGBA) {
         texture_manager->SetLevelInfo(texture_ref, texture_target_, 0, format,
-                                      width, height, 1, 0, format, 0, false);
+                                      width, height, 1, 0, format, 0,
+                                      gfx::Rect());
       }
     }
     buffers.push_back(media::PictureBuffer(buffer_ids[i], texture_dimensions_,
diff --git a/content/common/gpu/media/vaapi_jpeg_decoder_unittest.cc b/content/common/gpu/media/vaapi_jpeg_decoder_unittest.cc
index 70f4edff..2e9180f6 100644
--- a/content/common/gpu/media/vaapi_jpeg_decoder_unittest.cc
+++ b/content/common/gpu/media/vaapi_jpeg_decoder_unittest.cc
@@ -132,5 +132,6 @@
 int main(int argc, char** argv) {
   testing::InitGoogleTest(&argc, argv);
   base::AtExitManager exit_manager;
+  content::VaapiWrapper::PreSandboxInitialization();
   return RUN_ALL_TESTS();
 }
diff --git a/content/common/gpu/media/video_encode_accelerator_unittest.cc b/content/common/gpu/media/video_encode_accelerator_unittest.cc
index c9e6055..ec02e62a 100644
--- a/content/common/gpu/media/video_encode_accelerator_unittest.cc
+++ b/content/common/gpu/media/video_encode_accelerator_unittest.cc
@@ -743,6 +743,9 @@
 
   scoped_ptr<StreamValidator> validator_;
 
+  // The time when the first frame is submitted for encode.
+  base::TimeTicks first_frame_start_time_;
+
   // The time when the last encoded frame is ready.
   base::TimeTicks last_frame_ready_time_;
 
@@ -940,8 +943,8 @@
 }
 
 double VEAClient::frames_per_second() {
-  CHECK(!encode_start_time_.empty());
-  base::TimeDelta duration = last_frame_ready_time_ - encode_start_time_[0];
+  CHECK_NE(num_encoded_frames_, 0UL);
+  base::TimeDelta duration = last_frame_ready_time_ - first_frame_start_time_;
   return num_encoded_frames_ / duration.InSecondsF();
 }
 
@@ -959,9 +962,10 @@
     num_frames_to_encode_ = g_num_frames_to_encode;
 
   // Speed up vector insertion.
-  encode_start_time_.reserve(num_frames_to_encode_);
-  if (g_env->needs_encode_latency())
+  if (g_env->needs_encode_latency()) {
+    encode_start_time_.reserve(num_frames_to_encode_);
     encode_latencies_.reserve(num_frames_to_encode_);
+  }
 
   // We may need to loop over the stream more than once if more frames than
   // provided is required for bitrate tests.
@@ -1146,8 +1150,14 @@
     ++num_keyframes_requested_;
   }
 
-  CHECK_EQ(input_id, static_cast<int32>(encode_start_time_.size()));
-  encode_start_time_.push_back(base::TimeTicks::Now());
+  if (input_id == 0) {
+    first_frame_start_time_ = base::TimeTicks::Now();
+  }
+
+  if (g_env->needs_encode_latency()) {
+    CHECK_EQ(input_id, static_cast<int32>(encode_start_time_.size()));
+    encode_start_time_.push_back(base::TimeTicks::Now());
+  }
   encoder_->Encode(video_frame, force_keyframe);
 }
 
diff --git a/content/common/gpu/stream_texture_android.cc b/content/common/gpu/stream_texture_android.cc
index 9d65bcd..d5a57a02 100644
--- a/content/common/gpu/stream_texture_android.cc
+++ b/content/common/gpu/stream_texture_android.cc
@@ -41,17 +41,9 @@
         new StreamTexture(owner_stub, stream_id, texture->service_id()));
     gfx::Size size = gl_image->GetSize();
     texture_manager->SetTarget(texture, GL_TEXTURE_EXTERNAL_OES);
-    texture_manager->SetLevelInfo(texture,
-                                  GL_TEXTURE_EXTERNAL_OES,
-                                  0,
-                                  GL_RGBA,
-                                  size.width(),
-                                  size.height(),
-                                  1,
-                                  0,
-                                  GL_RGBA,
-                                  GL_UNSIGNED_BYTE,
-                                  true);
+    texture_manager->SetLevelInfo(texture, GL_TEXTURE_EXTERNAL_OES, 0, GL_RGBA,
+                                  size.width(), size.height(), 1, 0, GL_RGBA,
+                                  GL_UNSIGNED_BYTE, gfx::Rect(size));
     texture_manager->SetLevelImage(
         texture, GL_TEXTURE_EXTERNAL_OES, 0, gl_image.get());
     return true;
diff --git a/content/common/input/synthetic_gesture_params.cc b/content/common/input/synthetic_gesture_params.cc
index 6d24237..aff9e96 100644
--- a/content/common/input/synthetic_gesture_params.cc
+++ b/content/common/input/synthetic_gesture_params.cc
@@ -26,7 +26,10 @@
   return gesture_source_type == TOUCH_INPUT ||
          gesture_source_type == MOUSE_INPUT;
 #elif defined(OS_ANDROID)
-  return gesture_source_type == TOUCH_INPUT;
+  // Android supports mouse wheel events, but mouse drag is not yet
+  // supported. See crbug.com/468806.
+  return gesture_source_type == TOUCH_INPUT ||
+         gesture_source_type == MOUSE_INPUT;
 #else
   return gesture_source_type == MOUSE_INPUT;
 #endif
diff --git a/content/common/media/video_capture_messages.h b/content/common/media/video_capture_messages.h
index 77f95bf..a9fd27b 100644
--- a/content/common/media/video_capture_messages.h
+++ b/content/common/media/video_capture_messages.h
@@ -110,10 +110,11 @@
 
 // Tell the browser process that the renderer has finished reading from
 // a buffer previously delivered by VideoCaptureMsg_BufferReady.
-IPC_MESSAGE_CONTROL3(VideoCaptureHostMsg_BufferReady,
+IPC_MESSAGE_CONTROL4(VideoCaptureHostMsg_BufferReady,
                      int /* device_id */,
                      int /* buffer_id */,
-                     uint32 /* syncpoint */)
+                     uint32 /* syncpoint */,
+                     double /* consumer_resource_utilization */)
 
 // Get the formats supported by a device referenced by |capture_session_id|.
 IPC_MESSAGE_CONTROL2(VideoCaptureHostMsg_GetDeviceSupportedFormats,
diff --git a/content/common/process_control.mojom b/content/common/process_control.mojom
new file mode 100644
index 0000000..4b3237a
--- /dev/null
+++ b/content/common/process_control.mojom
@@ -0,0 +1,12 @@
+// 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 content;
+
+import "mojo/application/public/interfaces/application.mojom";
+
+interface ProcessControl {
+  LoadApplication(string url, mojo.Application& request) => (bool success);
+};
+
diff --git a/content/common/resource_messages.h b/content/common/resource_messages.h
index 4a2c6fdd..bc38f02 100644
--- a/content/common/resource_messages.h
+++ b/content/common/resource_messages.h
@@ -130,6 +130,7 @@
   IPC_STRUCT_TRAITS_MEMBER(original_url_via_service_worker)
   IPC_STRUCT_TRAITS_MEMBER(response_type_via_service_worker)
   IPC_STRUCT_TRAITS_MEMBER(service_worker_start_time)
+  IPC_STRUCT_TRAITS_MEMBER(service_worker_ready_time)
   IPC_STRUCT_TRAITS_MEMBER(proxy_server)
 IPC_STRUCT_TRAITS_END()
 
diff --git a/content/common/service_worker/service_worker_messages.h b/content/common/service_worker/service_worker_messages.h
index a54b3909..d18bef7 100644
--- a/content/common/service_worker/service_worker_messages.h
+++ b/content/common/service_worker/service_worker_messages.h
@@ -199,8 +199,9 @@
                     int /* request_id */,
                     content::ServiceWorkerFetchEventResult,
                     content::ServiceWorkerResponse)
-IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_SyncEventFinished,
-                    int /* request_id */)
+IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_SyncEventFinished,
+                    int /* request_id */,
+                    blink::WebServiceWorkerEventResult)
 IPC_MESSAGE_ROUTED1(ServiceWorkerHostMsg_NotificationClickEventFinished,
                     int /* request_id */)
 IPC_MESSAGE_ROUTED2(ServiceWorkerHostMsg_PushEventFinished,
diff --git a/content/content.gyp b/content/content.gyp
index de5327e..13a8385 100644
--- a/content/content.gyp
+++ b/content/content.gyp
@@ -287,6 +287,7 @@
               'dependencies': [
                 'content_child',
                 'content_common',
+                'content_common_mojo_bindings.gyp:content_common_mojo_bindings',
               ],
             },
           ],
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 6b8e555..12472fd 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -11,10 +11,15 @@
     '../device/vibration/vibration.gyp:device_vibration',
     '../device/vibration/vibration.gyp:device_vibration_mojo_bindings',
     '../google_apis/google_apis.gyp:google_apis',
+    '../mojo/mojo_base.gyp:mojo_application_base',
+    '../mojo/mojo_base.gyp:mojo_url_type_converters',
+    '../mojo/mojo_services.gyp:network_service_bindings_lib',
+    '../mojo/mojo_shell.gyp:mojo_shell_lib',
     '../net/net.gyp:net',
     '../net/net.gyp:net_extras',
     '../skia/skia.gyp:skia',
     '../sql/sql.gyp:sql',
+    '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
     '../third_party/re2/re2.gyp:re2',
     '../third_party/zlib/google/zip.gyp:zip',
     '../third_party/zlib/zlib.gyp:zlib',
@@ -165,6 +170,7 @@
       'public/browser/media_device_id.h',
       'public/browser/message_port_delegate.h',
       'public/browser/message_port_provider.h',
+      'public/browser/mojo_app_connection.h',
       'public/browser/native_web_keyboard_event.h',
       'public/browser/navigation_controller.cc',
       'public/browser/navigation_controller.h',
@@ -253,6 +259,7 @@
       'public/browser/stream_info.h',
       'public/browser/trace_uploader.h',
       'public/browser/tracing_controller.h',
+      'public/browser/tracing_delegate.cc',
       'public/browser/tracing_delegate.h',
       'public/browser/url_data_source.cc',
       'public/browser/url_data_source.h',
@@ -1030,8 +1037,12 @@
       'browser/message_port_service.h',
       'browser/mime_registry_message_filter.cc',
       'browser/mime_registry_message_filter.h',
+      'browser/mojo/mojo_app_connection_impl.cc',
+      'browser/mojo/mojo_app_connection_impl.h',
       'browser/mojo/mojo_application_host.cc',
       'browser/mojo/mojo_application_host.h',
+      'browser/mojo/mojo_shell_context.cc',
+      'browser/mojo/mojo_shell_context.h',
       'browser/mojo/service_registrar_android.cc',
       'browser/mojo/service_registrar_android.h',
       'browser/mojo/service_registry_android.cc',
diff --git a/content/content_child.gypi b/content/content_child.gypi
index e7d75d2..bc7b1c1c 100644
--- a/content/content_child.gypi
+++ b/content/content_child.gypi
@@ -209,6 +209,8 @@
       'child/runtime_features.h',
       'child/scoped_child_process_reference.cc',
       'child/scoped_child_process_reference.h',
+      'child/shared_memory_data_consumer_handle.cc',
+      'child/shared_memory_data_consumer_handle.h',
       'child/shared_memory_received_data_factory.cc',
       'child/shared_memory_received_data_factory.h',
       'child/service_worker/service_worker_dispatcher.cc',
diff --git a/content/content_common_mojo_bindings.gyp b/content/content_common_mojo_bindings.gyp
index dc2df70..4f01043 100644
--- a/content/content_common_mojo_bindings.gyp
+++ b/content/content_common_mojo_bindings.gyp
@@ -16,6 +16,7 @@
           'common/geolocation_service.mojom',
           'common/permission_service.mojom',
           'common/presentation/presentation_service.mojom',
+          'common/process_control.mojom',
           'common/render_frame_setup.mojom',
 
           # NOTE: Sources duplicated in
diff --git a/content/content_jni.gypi b/content/content_jni.gypi
index 8ea648f..c93e4efd 100644
--- a/content/content_jni.gypi
+++ b/content/content_jni.gypi
@@ -31,13 +31,13 @@
     'public/android/java/src/org/chromium/content/browser/MediaDrmCredentialManager.java',
     'public/android/java/src/org/chromium/content/browser/MediaSession.java',
     'public/android/java/src/org/chromium/content/browser/MediaResourceGetter.java',
+    'public/android/java/src/org/chromium/content/browser/MotionEventSynthesizer.java',
     'public/android/java/src/org/chromium/content/browser/PowerSaveBlocker.java',
     'public/android/java/src/org/chromium/content/browser/ServiceRegistrar.java',
     'public/android/java/src/org/chromium/content/browser/ServiceRegistry.java',
     'public/android/java/src/org/chromium/content/browser/ScreenOrientationProvider.java',
     'public/android/java/src/org/chromium/content/browser/SpeechRecognition.java',
     'public/android/java/src/org/chromium/content/browser/TimeZoneMonitor.java',
-    'public/android/java/src/org/chromium/content/browser/TouchEventSynthesizer.java',
     'public/android/java/src/org/chromium/content/browser/TracingControllerAndroid.java',
     'public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java',
     'public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java',
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index 027e43a..a3c6da35 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -657,6 +657,8 @@
       'renderer/media/webrtc/webrtc_video_capturer_adapter.h',
       'renderer/media/webrtc/webrtc_video_track_adapter.cc',
       'renderer/media/webrtc/webrtc_video_track_adapter.h',
+      'renderer/media/webrtc/webrtc_video_frame_adapter.cc',
+      'renderer/media/webrtc/webrtc_video_frame_adapter.h',
       'renderer/media/webrtc_audio_capturer.cc',
       'renderer/media/webrtc_audio_capturer.h',
       'renderer/media/webrtc_audio_device_impl.cc',
diff --git a/content/content_shell.gypi b/content/content_shell.gypi
index 475008a..6893e2d 100644
--- a/content/content_shell.gypi
+++ b/content/content_shell.gypi
@@ -234,6 +234,8 @@
         'shell/renderer/shell_content_renderer_client.h',
         'shell/renderer/shell_render_view_observer.cc',
         'shell/renderer/shell_render_view_observer.h',
+        'shell/utility/shell_content_utility_client.cc',
+        'shell/utility/shell_content_utility_client.h',
       ],
       'msvs_settings': {
         'VCLinkerTool': {
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 64e8770..0dfc8ca 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -83,6 +83,8 @@
       'public/test/test_file_system_options.h',
       'public/test/test_launcher.cc',
       'public/test/test_launcher.h',
+      'public/test/test_mojo_app.cc',
+      'public/test/test_mojo_app.h',
       'public/test/test_navigation_observer.cc',
       'public/test/test_navigation_observer.h',
       'public/test/test_notification_tracker.cc',
@@ -222,6 +224,7 @@
       'browser/media/media_canplaytype_browsertest.cc',
       'browser/media/media_source_browsertest.cc',
       'browser/message_port_provider_browsertest.cc',
+      'browser/mojo_shell_browsertest.cc',
       'browser/net_info_browsertest.cc',
       'browser/plugin_browsertest.cc',
       'browser/renderer_host/input/touch_action_browsertest.cc',
@@ -593,6 +596,7 @@
       'child/power_monitor_broadcast_source_unittest.cc',
       'child/resource_dispatcher_unittest.cc',
       'child/service_worker/service_worker_dispatcher_unittest.cc',
+      'child/shared_memory_data_consumer_handle_unittest.cc',
       'child/shared_memory_received_data_factory_unittest.cc',
       'child/simple_webmimeregistry_impl_unittest.cc',
       'child/site_isolation_policy_unittest.cc',
@@ -787,6 +791,7 @@
       'target_name': 'test_support_content',
       'type': 'static_library',
       'dependencies': [
+        '../mojo/mojo_base.gyp:mojo_application_base',
         '../mojo/mojo_base.gyp:mojo_environment_chromium',
         '../net/net.gyp:net_test_support',
         '../skia/skia.gyp:skia',
@@ -794,6 +799,7 @@
         '../testing/gmock.gyp:gmock',
         '../testing/gtest.gyp:gtest',
         '../third_party/mojo/mojo_edk.gyp:mojo_system_impl',
+        '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
         '../ui/accessibility/accessibility.gyp:ax_gen',
         '../ui/base/ime/ui_base_ime.gyp:ui_base_ime',
         '../ui/base/ui_base.gyp:ui_base',
@@ -861,6 +867,7 @@
             }],
           ],
           'dependencies': [
+            'content_test_mojo_bindings',
             'content.gyp:content_child',
             'content.gyp:content_common',
             'content.gyp:content_gpu',
@@ -873,11 +880,14 @@
             '../cc/cc.gyp:cc',
             '../cc/cc_tests.gyp:cc_test_support',
             '../components/scheduler/scheduler.gyp:scheduler',
+            '../components/scheduler/scheduler.gyp:scheduler_test_support',
             '../gpu/blink/gpu_blink.gyp:gpu_blink',
             '../ipc/mojo/ipc_mojo.gyp:*',
             '../media/blink/media_blink.gyp:media_blink',
             '../media/media.gyp:media',
             '../media/midi/midi.gyp:midi',
+            '../mojo/mojo_base.gyp:mojo_application_base',
+            '../mojo/mojo_base.gyp:mojo_environment_chromium',
             '../ppapi/ppapi_internal.gyp:ppapi_host',
             '../ppapi/ppapi_internal.gyp:ppapi_proxy',
             '../ppapi/ppapi_internal.gyp:ppapi_shared',
@@ -885,6 +895,7 @@
             '../storage/storage_browser.gyp:storage',
             '../storage/storage_common.gyp:storage_common',
             '../third_party/WebKit/public/blink.gyp:blink',
+            '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
             '../ui/compositor/compositor.gyp:compositor_test_support',
             '../ui/surface/surface.gyp:surface',
             '../v8/tools/gyp/v8.gyp:v8',
@@ -1312,6 +1323,15 @@
           ],
         },
         {
+          # GN version: //content/test:test_mojo_bindings
+          'target_name': 'content_test_mojo_bindings',
+          'type': 'static_library',
+          'sources': [
+            'public/test/test_mojo_service.mojom',
+          ],
+          'includes': [ '../third_party/mojo/mojom_bindings_generator.gypi' ],
+        },
+        {
           # GN version: //content/test:web_ui_test_mojo_bindings
           'target_name': 'web_ui_test_mojo_bindings',
           'type': 'static_library',
@@ -1350,6 +1370,7 @@
             '../ipc/ipc.gyp:test_support_ipc',
             '../media/media.gyp:media_test_support',
             '../media/media.gyp:shared_memory_support',
+            '../mojo/mojo_base.gyp:mojo_application_base',
             '../mojo/mojo_base.gyp:mojo_environment_chromium',
             '../net/net.gyp:net_test_support',
             '../ppapi/ppapi_internal.gyp:ppapi_host',
diff --git a/content/content_utility.gypi b/content/content_utility.gypi
index bbdfd4f..96d81f8d 100644
--- a/content/content_utility.gypi
+++ b/content/content_utility.gypi
@@ -6,6 +6,12 @@
   'dependencies': [
     '../base/base.gyp:base',
     '../courgette/courgette.gyp:courgette_lib',
+    '../mojo/mojo_base.gyp:mojo_application_base',
+    '../mojo/mojo_base.gyp:mojo_application_bindings',
+    '../mojo/mojo_base.gyp:mojo_common_lib',
+    '../mojo/mojo_shell.gyp:mojo_shell_lib',
+    '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
+    '../url/url.gyp:url_lib',
   ],
   'variables': {
     'utility_sources': [
@@ -14,6 +20,8 @@
       'utility/utility_blink_platform_impl.cc',
       'utility/utility_blink_platform_impl.h',
       'utility/utility_main.cc',
+      'utility/utility_process_control_impl.cc',
+      'utility/utility_process_control_impl.h',
       'utility/utility_thread_impl.cc',
       'utility/utility_thread_impl.h',
       'utility/webthread_impl_for_utility_thread.cc',
diff --git a/content/gpu/gpu_watchdog_thread.cc b/content/gpu/gpu_watchdog_thread.cc
index 6052d41..e6da1a4 100644
--- a/content/gpu/gpu_watchdog_thread.cc
+++ b/content/gpu/gpu_watchdog_thread.cc
@@ -13,8 +13,10 @@
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/files/file_util.h"
+#include "base/location.h"
 #include "base/power_monitor/power_monitor.h"
 #include "base/process/process.h"
+#include "base/single_thread_task_runner.h"
 #include "build/build_config.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/result_codes.h"
@@ -75,9 +77,8 @@
 void GpuWatchdogThread::PostAcknowledge() {
   // Called on the monitored thread. Responds with OnAcknowledge. Cannot use
   // the method factory. Rely on reference counting instead.
-  message_loop()->PostTask(
-      FROM_HERE,
-      base::Bind(&GpuWatchdogThread::OnAcknowledge, this));
+  task_runner()->PostTask(FROM_HERE,
+                          base::Bind(&GpuWatchdogThread::OnAcknowledge, this));
 }
 
 void GpuWatchdogThread::CheckArmed() {
@@ -162,10 +163,9 @@
   bool was_suspended = (base::Time::Now() > suspension_timeout_);
 
   // The monitored thread has responded. Post a task to check it again.
-  message_loop()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&GpuWatchdogThread::OnCheck, weak_factory_.GetWeakPtr(),
-          was_suspended),
+  task_runner()->PostDelayedTask(
+      FROM_HERE, base::Bind(&GpuWatchdogThread::OnCheck,
+                            weak_factory_.GetWeakPtr(), was_suspended),
       0.5 * timeout_);
 }
 
@@ -194,13 +194,12 @@
   // Post a task to the monitored thread that does nothing but wake up the
   // TaskObserver. Any other tasks that are pending on the watched thread will
   // also wake up the observer. This simply ensures there is at least one.
-  watched_message_loop_->PostTask(
-      FROM_HERE,
-      base::Bind(&base::DoNothing));
+  watched_message_loop_->task_runner()->PostTask(FROM_HERE,
+                                                 base::Bind(&base::DoNothing));
 
   // Post a task to the watchdog thread to exit if the monitored thread does
   // not respond in time.
-  message_loop()->PostDelayedTask(
+  task_runner()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&GpuWatchdogThread::DeliberatelyTerminateToRecoverFromHang,
                  weak_factory_.GetWeakPtr()),
@@ -341,9 +340,8 @@
 
 #endif
 void GpuWatchdogThread::AddPowerObserver() {
-  message_loop()->PostTask(
-      FROM_HERE,
-      base::Bind(&GpuWatchdogThread::OnAddPowerObserver, this));
+  task_runner()->PostTask(
+      FROM_HERE, base::Bind(&GpuWatchdogThread::OnAddPowerObserver, this));
 }
 
 void GpuWatchdogThread::OnAddPowerObserver() {
diff --git a/content/ppapi_plugin/ppapi_thread.cc b/content/ppapi_plugin/ppapi_thread.cc
index a0ed633..10c82631 100644
--- a/content/ppapi_plugin/ppapi_thread.cc
+++ b/content/ppapi_plugin/ppapi_thread.cc
@@ -202,16 +202,24 @@
 base::SharedMemoryHandle PpapiThread::ShareSharedMemoryHandleWithRemote(
     const base::SharedMemoryHandle& handle,
     base::ProcessId remote_pid) {
-  base::PlatformFile local_platform_file =
-#if defined(OS_POSIX)
-      handle.fd;
-#elif defined(OS_WIN)
-      handle;
-#else
-#error Not implemented.
+#if defined(OS_WIN)
+  if (peer_handle_.IsValid()) {
+    DCHECK(is_broker_);
+    return IPC::GetFileHandleForProcess(handle, peer_handle_.Get(), false);
+  }
 #endif
-  return PpapiThread::ShareHandleWithRemote(local_platform_file, remote_pid,
-                                            false);
+
+  DCHECK(remote_pid != base::kNullProcessId);
+#if defined(OS_WIN) || defined(OS_MACOSX)
+  base::SharedMemoryHandle duped_handle;
+  bool success =
+      BrokerDuplicateSharedMemoryHandle(handle, remote_pid, &duped_handle);
+  if (success)
+    return duped_handle;
+  return base::SharedMemory::NULLHandle();
+#else
+  return base::SharedMemory::DuplicateHandle(handle);
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
 }
 
 std::set<PP_Instance>* PpapiThread::GetGloballySeenInstanceIDSet() {
diff --git a/content/public/android/java/src/org/chromium/content/browser/BackgroundSyncLauncherService.java b/content/public/android/java/src/org/chromium/content/browser/BackgroundSyncLauncherService.java
index fd7b55a90..40a129b 100644
--- a/content/public/android/java/src/org/chromium/content/browser/BackgroundSyncLauncherService.java
+++ b/content/public/android/java/src/org/chromium/content/browser/BackgroundSyncLauncherService.java
@@ -61,8 +61,8 @@
         }
     }
 
-    public BackgroundSyncLauncherService(String name) {
-        super(name);
+    public BackgroundSyncLauncherService() {
+        super("BackgroundSyncLauncherService");
     }
 
     @Override
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 1e33a959..e79a9db4 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
@@ -2449,8 +2449,8 @@
 
     @SuppressWarnings("unused")
     @CalledByNative
-    private TouchEventSynthesizer createTouchEventSynthesizer() {
-        return new TouchEventSynthesizer(this);
+    private MotionEventSynthesizer createMotionEventSynthesizer() {
+        return new MotionEventSynthesizer(this);
     }
 
     @SuppressWarnings("unused")
diff --git a/content/public/android/java/src/org/chromium/content/browser/TouchEventSynthesizer.java b/content/public/android/java/src/org/chromium/content/browser/MotionEventSynthesizer.java
similarity index 78%
rename from content/public/android/java/src/org/chromium/content/browser/TouchEventSynthesizer.java
rename to content/public/android/java/src/org/chromium/content/browser/MotionEventSynthesizer.java
index 9356871c..3616375 100644
--- a/content/public/android/java/src/org/chromium/content/browser/TouchEventSynthesizer.java
+++ b/content/public/android/java/src/org/chromium/content/browser/MotionEventSynthesizer.java
@@ -4,6 +4,7 @@
 
 package org.chromium.content.browser;
 
+import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
 import android.view.MotionEvent.PointerProperties;
@@ -15,20 +16,21 @@
  * Provides a Java-side implementation for injecting synthetic touch events.
  */
 @JNINamespace("content")
-public class TouchEventSynthesizer {
+public class MotionEventSynthesizer {
     private static final int MAX_NUM_POINTERS = 16;
 
     private static final int ACTION_START = 0;
     private static final int ACTION_MOVE = 1;
     private static final int ACTION_CANCEL = 2;
     private static final int ACTION_END = 3;
+    private static final int ACTION_SCROLL = 4;
 
     private final ContentViewCore mContentViewCore;
     private final PointerProperties[] mPointerProperties;
     private final PointerCoords[] mPointerCoords;
     private long mDownTimeInMs;
 
-    TouchEventSynthesizer(ContentViewCore contentViewCore) {
+    MotionEventSynthesizer(ContentViewCore contentViewCore) {
         mContentViewCore = contentViewCore;
         mPointerProperties = new PointerProperties[MAX_NUM_POINTERS];
         mPointerCoords = new PointerCoords[MAX_NUM_POINTERS];
@@ -53,6 +55,15 @@
     }
 
     @CalledByNative
+    void setScrollDeltas(int x, int y, int dx, int dy) {
+        setPointer(0, x, y, 0);
+        // Convert coordinates from density independent pixels to density dependent pixels.
+        float scaleFactor = mContentViewCore.getRenderCoordinates().getDeviceScaleFactor();
+        mPointerCoords[0].setAxisValue(MotionEvent.AXIS_HSCROLL, scaleFactor * dx);
+        mPointerCoords[0].setAxisValue(MotionEvent.AXIS_VSCROLL, scaleFactor * dy);
+    }
+
+    @CalledByNative
     void inject(int action, int pointerCount, long timeInMs) {
         switch (action) {
             case ACTION_START: {
@@ -111,6 +122,19 @@
                 event.recycle();
                 break;
             }
+            case ACTION_SCROLL: {
+                assert pointerCount == 1;
+                MotionEvent event = MotionEvent.obtain(mDownTimeInMs, timeInMs,
+                        MotionEvent.ACTION_SCROLL, pointerCount, mPointerProperties, mPointerCoords,
+                        0, 0, 1, 1, 0, 0, InputDevice.SOURCE_CLASS_POINTER, 0);
+                mContentViewCore.onGenericMotionEvent(event);
+                event.recycle();
+                break;
+            }
+            default: {
+                assert false : "Unreached";
+                break;
+            }
         }
     }
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
index aba184a9..c4ce8450 100644
--- a/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/framehost/NavigationControllerImpl.java
@@ -241,6 +241,39 @@
         return false;
     }
 
+    @Override
+    public boolean canCopyStateOver() {
+        return mNativeNavigationControllerAndroid != 0
+                && nativeCanCopyStateOver(mNativeNavigationControllerAndroid);
+    }
+
+    @Override
+    public boolean canPruneAllButLastCommitted() {
+        return mNativeNavigationControllerAndroid != 0
+                && nativeCanPruneAllButLastCommitted(mNativeNavigationControllerAndroid);
+    }
+
+    @Override
+    public void copyStateFrom(NavigationController source) {
+        if (mNativeNavigationControllerAndroid == 0) return;
+        NavigationControllerImpl sourceImpl = (NavigationControllerImpl) source;
+        if (sourceImpl.mNativeNavigationControllerAndroid == 0) return;
+        nativeCopyStateFrom(
+                mNativeNavigationControllerAndroid,
+                sourceImpl.mNativeNavigationControllerAndroid);
+    }
+
+    @Override
+    public void copyStateFromAndPrune(NavigationController source, boolean replaceEntry) {
+        if (mNativeNavigationControllerAndroid == 0) return;
+        NavigationControllerImpl sourceImpl = (NavigationControllerImpl) source;
+        if (sourceImpl.mNativeNavigationControllerAndroid == 0) return;
+        nativeCopyStateFromAndPrune(
+                mNativeNavigationControllerAndroid,
+                sourceImpl.mNativeNavigationControllerAndroid,
+                replaceEntry);
+    }
+
     @CalledByNative
     private static void addToNavigationHistory(Object history, Object navigationEntry) {
         ((NavigationHistory) history).addEntry((NavigationEntry) navigationEntry);
@@ -301,4 +334,11 @@
     private native int nativeGetLastCommittedEntryIndex(long nativeNavigationControllerAndroid);
     private native boolean nativeRemoveEntryAtIndex(long nativeNavigationControllerAndroid,
             int index);
+    private native boolean nativeCanCopyStateOver(long nativeNavigationControllerAndroid);
+    private native boolean nativeCanPruneAllButLastCommitted(
+            long nativeNavigationControllerAndroid);
+    private native void nativeCopyStateFrom(long nativeNavigationControllerAndroid,
+            long sourceNavigationControllerAndroid);
+    private native void nativeCopyStateFromAndPrune(long nativeNavigationControllerAndroid,
+            long sourceNavigationControllerAndroid, boolean replaceEntry);
 }
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 75c8bd8..2e088a35 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
@@ -10,6 +10,7 @@
 import android.text.Selection;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.inputmethod.BaseInputConnection;
@@ -42,6 +43,7 @@
 
     private boolean mSingleLine;
     private int mNumNestedBatchEdits = 0;
+    private int mPendingAccent;
 
     private int mLastUpdateSelectionStart = INVALID_SELECTION;
     private int mLastUpdateSelectionEnd = INVALID_SELECTION;
@@ -242,6 +244,7 @@
     public boolean setComposingText(CharSequence text, int newCursorPosition) {
         if (DEBUG) Log.w(TAG, "setComposingText [" + text + "] [" + newCursorPosition + "]");
         if (maybePerformEmptyCompositionWorkaround(text)) return true;
+        mPendingAccent = 0;
         super.setComposingText(text, newCursorPosition);
         updateSelectionIfRequired();
         return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPosition, false);
@@ -254,6 +257,7 @@
     public boolean commitText(CharSequence text, int newCursorPosition) {
         if (DEBUG) Log.w(TAG, "commitText [" + text + "] [" + newCursorPosition + "]");
         if (maybePerformEmptyCompositionWorkaround(text)) return true;
+        mPendingAccent = 0;
         super.commitText(text, newCursorPosition);
         updateSelectionIfRequired();
         return mImeAdapter.checkCompositionQueueAndCallNative(text, newCursorPosition,
@@ -351,6 +355,11 @@
         if (DEBUG) {
             Log.w(TAG, "deleteSurroundingText [" + beforeLength + " " + afterLength + "]");
         }
+
+        if (mPendingAccent != 0) {
+            finishComposingText();
+        }
+
         int originalBeforeLength = beforeLength;
         int originalAfterLength = afterLength;
         int availableBefore = Selection.getSelectionStart(mEditable);
@@ -403,15 +412,22 @@
         int keycode = event.getKeyCode();
         int unicodeChar = event.getUnicodeChar();
 
+        // If this isn't a KeyDown event, no need to update composition state; just pass the key
+        // event through and return.
+        if (action != KeyEvent.ACTION_DOWN) {
+            mImeAdapter.translateAndSendNativeEvents(event);
+            return true;
+        }
+
         // If this is backspace/del or if the key has a character representation,
         // need to update the underlying Editable (i.e. the local representation of the text
         // being edited).  Some IMEs like Jellybean stock IME and Samsung IME mix in delete
         // KeyPress events instead of calling deleteSurroundingText.
-        if (action == KeyEvent.ACTION_DOWN && keycode == KeyEvent.KEYCODE_DEL) {
+        if (keycode == KeyEvent.KEYCODE_DEL) {
             deleteSurroundingTextImpl(1, 0, true);
-        } else if (action == KeyEvent.ACTION_DOWN && keycode == KeyEvent.KEYCODE_FORWARD_DEL) {
+        } else if (keycode == KeyEvent.KEYCODE_FORWARD_DEL) {
             deleteSurroundingTextImpl(0, 1, true);
-        } else if (action == KeyEvent.ACTION_DOWN && keycode == KeyEvent.KEYCODE_ENTER) {
+        } else if (keycode == KeyEvent.KEYCODE_ENTER) {
             // Finish text composition when pressing enter, as that may submit a form field.
             // TODO(aurimas): remove this workaround when crbug.com/278584 is fixed.
             beginBatchEdit();
@@ -419,7 +435,32 @@
             mImeAdapter.translateAndSendNativeEvents(event);
             endBatchEdit();
             return true;
-        } else if (action == KeyEvent.ACTION_UP && unicodeChar != 0) {
+        } else if ((unicodeChar & KeyCharacterMap.COMBINING_ACCENT) != 0) {
+            // Store a pending accent character and make it the current composition.
+            int pendingAccent = unicodeChar & KeyCharacterMap.COMBINING_ACCENT_MASK;
+            StringBuilder builder = new StringBuilder();
+            builder.appendCodePoint(pendingAccent);
+            setComposingText(builder.toString(), 1);
+            mPendingAccent = pendingAccent;
+            return true;
+        }
+
+        if (unicodeChar != 0) {
+            if (mPendingAccent != 0) {
+                int combined = KeyEvent.getDeadChar(mPendingAccent, unicodeChar);
+                if (combined != 0) {
+                    StringBuilder builder = new StringBuilder();
+                    builder.appendCodePoint(combined);
+                    commitText(builder.toString(), 1);
+                    return true;
+                }
+                // Noncombinable character; commit the accent character and fall through to sending
+                // the key event for the character afterwards.
+                finishComposingText();
+            }
+
+            // Update the mEditable state to reflect what Blink will do in response to the KeyDown
+            // for a unicode-mapped key event.
             int selectionStart = Selection.getSelectionStart(mEditable);
             int selectionEnd = Selection.getSelectionEnd(mEditable);
             if (selectionStart > selectionEnd) {
@@ -430,6 +471,7 @@
             mEditable.replace(selectionStart, selectionEnd,
                     Character.toString((char) unicodeChar));
         }
+
         mImeAdapter.translateAndSendNativeEvents(event);
         return true;
     }
@@ -440,6 +482,9 @@
     @Override
     public boolean finishComposingText() {
         if (DEBUG) Log.w(TAG, "finishComposingText");
+
+        mPendingAccent = 0;
+
         if (getComposingSpanStart(mEditable) == getComposingSpanEnd(mEditable)) {
             return true;
         }
@@ -472,6 +517,7 @@
         if (DEBUG) Log.w(TAG, "restartInput");
         getInputMethodManagerWrapper().restartInput(mInternalView);
         mNumNestedBatchEdits = 0;
+        mPendingAccent = 0;
     }
 
     /**
@@ -488,17 +534,26 @@
         if (a > textLength) a = textLength;
         if (b > textLength) b = textLength;
 
+        CharSequence regionText = null;
         if (a == b) {
             removeComposingSpans(mEditable);
         } else {
+            if (a == 0 && b == mEditable.length()) {
+                regionText = mEditable.subSequence(a, b);
+                // If setting composing region that matches, at least in length, of the entire
+                // editable region then check it for image placeholders.  If any are found,
+                // don't continue this operation.
+                // This fixes the problem where, on Android 4.3, pasting an image is followed
+                // by setting the composing region which then causes the image to be deleted.
+                // http://crbug.com/466755
+                for (int i = a; i < b; ++i) {
+                    if (regionText.charAt(i) == '\uFFFC') return true;
+                }
+            }
             super.setComposingRegion(a, b);
         }
         updateSelectionIfRequired();
 
-        CharSequence regionText = null;
-        if (b > a) {
-            regionText = mEditable.subSequence(a, b);
-        }
         return mImeAdapter.setComposingRegion(regionText, a, b);
     }
 
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/NavigationController.java b/content/public/android/java/src/org/chromium/content_public/browser/NavigationController.java
index 2999606..e6632ed 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/NavigationController.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/NavigationController.java
@@ -165,4 +165,29 @@
      *         call discards any transient or pending entries.
      */
     public boolean removeEntryAtIndex(int index);
+
+    /**
+     * @return Whether it is safe to call CopyStateFrom (i.e. the navigation state is empty).
+     */
+    public boolean canCopyStateOver();
+
+    /**
+     * @return Whether it is safe to call CopyStateFromAndPrune.
+     */
+    public boolean canPruneAllButLastCommitted();
+
+    /**
+     * Copies the navigation state from the given controller to this one. This one should be empty.
+     * @param source A source of the navigation state
+     */
+    public void copyStateFrom(NavigationController source);
+
+    /**
+     * A variant of CopyStateFrom. Removes all entries from this except the last committed entry,
+     * and inserts all entries from |source| before and including its last committed entry.
+     * See navigation_controller.h for more detailed description.
+     * @param source A source of the navigation state
+     * @param replaceEntry Whether to replace the current entry in source
+     */
+    public void copyStateFromAndPrune(NavigationController source, boolean replaceEntry);
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/BackgroundSyncLauncherTest.java b/content/public/android/javatests/src/org/chromium/content/browser/BackgroundSyncLauncherTest.java
index 25f7bd6..74a821bb 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/BackgroundSyncLauncherTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/BackgroundSyncLauncherTest.java
@@ -156,4 +156,11 @@
         deleteLauncherInstance();
         startOnReceiveAndVerify(true);
     }
+
+    @SmallTest
+    @Feature({"BackgroundSync"})
+    public void testStartingService() {
+        Intent serviceIntent = new Intent(mContext, BackgroundSyncLauncherService.class);
+        mLauncherServiceReceiver.startWakefulService(mContext, serviceIntent);
+    }
 }
\ No newline at end of file
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 8484bd9..e95e71b9 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
@@ -702,6 +702,86 @@
 
     @SmallTest
     @Feature({"TextInput", "Main"})
+    public void testAccentKeyCodesFromPhysicalKeyboard() throws Throwable {
+        DOMUtils.focusNode(mWebContents, "textarea");
+        assertWaitForKeyboardStatus(true);
+
+        mConnection = (TestAdapterInputConnection) getAdapterInputConnection();
+        waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 0, "", 0, 0, -1, -1);
+
+        // h
+        dispatchKeyEvent(mConnection, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_H));
+        dispatchKeyEvent(mConnection, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_H));
+        assertEquals("h", mConnection.getTextBeforeCursor(9, 0));
+
+        // ALT-i  (circumflex accent key on virtual keyboard)
+        dispatchKeyEvent(
+                mConnection, new KeyEvent(
+                        0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON));
+        assertUpdateStateCall(mConnection, 1000);
+        assertEquals("hˆ", mConnection.getTextBeforeCursor(9, 0));
+        dispatchKeyEvent(
+                mConnection, new KeyEvent(
+                        0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON));
+        assertEquals("hˆ", mConnection.getTextBeforeCursor(9, 0));
+
+        // o
+        dispatchKeyEvent(mConnection, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_O));
+        assertUpdateStateCall(mConnection, 1000);
+        assertEquals("hô", mConnection.getTextBeforeCursor(9, 0));
+        dispatchKeyEvent(mConnection, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_O));
+        assertEquals("hô", mConnection.getTextBeforeCursor(9, 0));
+        assertEquals(-1, mConnection.getComposingSpanEnd(mConnection.getEditable()));
+
+        // ALT-i
+        dispatchKeyEvent(
+                mConnection, new KeyEvent(
+                        0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON));
+        assertUpdateStateCall(mConnection, 1000);
+        dispatchKeyEvent(
+                mConnection, new KeyEvent(
+                        0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON));
+        assertEquals("hôˆ", mConnection.getTextBeforeCursor(9, 0));
+
+        // ALT-i again should have no effect
+        dispatchKeyEvent(
+                mConnection, new KeyEvent(
+                        0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON));
+        assertUpdateStateCall(mConnection, 1000);
+        dispatchKeyEvent(
+                mConnection, new KeyEvent(
+                        0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON));
+        assertEquals("hôˆ", mConnection.getTextBeforeCursor(9, 0));
+
+        // b (cannot be accented, should just appear after)
+        dispatchKeyEvent(mConnection, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B));
+        assertUpdateStateCall(mConnection, 1000);
+        assertEquals("hôˆb", mConnection.getTextBeforeCursor(9, 0));
+        dispatchKeyEvent(mConnection, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_B));
+        assertEquals("hôˆb", mConnection.getTextBeforeCursor(9, 0));
+        assertEquals(-1, mConnection.getComposingSpanEnd(mConnection.getEditable()));
+
+        // ALT-i
+        dispatchKeyEvent(
+                mConnection, new KeyEvent(
+                        0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON));
+        assertUpdateStateCall(mConnection, 1000);
+        dispatchKeyEvent(
+                mConnection, new KeyEvent(
+                        0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I, 0, KeyEvent.META_ALT_ON));
+        assertEquals("hôˆbˆ", mConnection.getTextBeforeCursor(9, 0));
+
+        // Backspace
+        dispatchKeyEvent(mConnection, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
+        assertUpdateStateCall(mConnection, 1000);
+        assertEquals("hôˆb", mConnection.getTextBeforeCursor(9, 0));
+        dispatchKeyEvent(mConnection, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
+        assertEquals("hôˆb", mConnection.getTextBeforeCursor(9, 0));
+        assertEquals(-1, mConnection.getComposingSpanEnd(mConnection.getEditable()));
+    }
+
+    @SmallTest
+    @Feature({"TextInput", "Main"})
     public void testSetComposingRegionOutOfBounds() throws Throwable {
         DOMUtils.focusNode(mWebContents, "textarea");
         assertWaitForKeyboardStatus(true);
@@ -1056,6 +1136,15 @@
         });
     }
 
+    private void dispatchKeyEvent(final AdapterInputConnection connection, final KeyEvent event) {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mImeAdapter.dispatchKeyEvent(event);
+            }
+        });
+    }
+
     private static class TestAdapterInputConnectionFactory extends
             ImeAdapter.AdapterInputConnectionFactory {
         @Override
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index a0c7f91..ebe488e 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -50,6 +50,7 @@
 
     # We expose skia headers in the public API.
     "//skia",
+    "//third_party/mojo/src/mojo/public/cpp/bindings",
     "//third_party/mojo/src/mojo/public/cpp/system",
   ]
   deps = [
diff --git a/content/public/browser/background_tracing_manager.h b/content/public/browser/background_tracing_manager.h
index 87f32798..75e2d34 100644
--- a/content/public/browser/background_tracing_manager.h
+++ b/content/public/browser/background_tracing_manager.h
@@ -39,8 +39,8 @@
   //     );
   // }
   //
-  typedef base::Callback<void(const base::RefCountedString*, base::Closure)>
-      ReceiveCallback;
+  typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&,
+                              base::Closure)> ReceiveCallback;
 
   // Set the triggering rules for when to start recording.
   //
@@ -57,9 +57,13 @@
   // Calls to SetActiveScenario() with a config will fail if tracing is
   // currently on. Use WhenIdle to register a callback to get notified when
   // the manager is idle and a config can be set again.
+  enum DataFiltering {
+    NO_DATA_FILTERING,
+    ANONYMIZE_DATA,
+  };
   virtual bool SetActiveScenario(scoped_ptr<BackgroundTracingConfig> config,
                                  const ReceiveCallback& receive_callback,
-                                 bool requires_anonymized_data) = 0;
+                                 DataFiltering data_filtering) = 0;
 
   // Notifies the caller when the manager is idle (not recording or uploading),
   // so that a call to SetActiveScenario() is likely to succeed.
@@ -84,7 +88,8 @@
   virtual void GetTriggerNameList(std::vector<std::string>* trigger_names) = 0;
 
   virtual void InvalidateTriggerHandlesForTesting() = 0;
-
+  virtual void SetTracingEnabledCallbackForTesting(
+      const base::Closure& callback) = 0;
   virtual void FireTimerForTesting() = 0;
 
  protected:
diff --git a/content/public/browser/browser_thread.h b/content/public/browser/browser_thread.h
index 9473c2cd..a68903d 100644
--- a/content/public/browser/browser_thread.h
+++ b/content/public/browser/browser_thread.h
@@ -11,7 +11,7 @@
 #include "base/callback.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/task_runner_util.h"
 #include "base/time/time.h"
 #include "content/common/content_export.h"
@@ -88,7 +88,7 @@
 
     // NOTE: do not add new threads here that are only used by a small number of
     // files. Instead you should just use a Thread class and pass its
-    // MessageLoopProxy around. Named threads there are only for threads that
+    // task runner around. Named threads there are only for threads that
     // are used in many places.
 
     // This identifier does not represent a thread.  Instead it counts the
@@ -130,10 +130,10 @@
       const tracked_objects::Location& from_here,
       const base::Callback<ReturnType(void)>& task,
       const base::Callback<void(ReplyArgType)>& reply) {
-    scoped_refptr<base::MessageLoopProxy> message_loop_proxy =
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner =
         GetMessageLoopProxyForThread(identifier);
-    return base::PostTaskAndReplyWithResult(
-        message_loop_proxy.get(), from_here, task, reply);
+    return base::PostTaskAndReplyWithResult(task_runner.get(), from_here, task,
+                                            reply);
   }
 
   template <class T>
@@ -216,10 +216,10 @@
   // sets identifier to its ID.  Otherwise returns false.
   static bool GetCurrentThreadIdentifier(ID* identifier) WARN_UNUSED_RESULT;
 
-  // Callers can hold on to a refcounted MessageLoopProxy beyond the lifetime
+  // Callers can hold on to a refcounted task runner beyond the lifetime
   // of the thread.
-  static scoped_refptr<base::MessageLoopProxy> GetMessageLoopProxyForThread(
-      ID identifier);
+  static scoped_refptr<base::SingleThreadTaskRunner>
+  GetMessageLoopProxyForThread(ID identifier);
 
   // Returns a pointer to the thread's message loop, which will become
   // invalid during shutdown, so you probably shouldn't hold onto it.
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index eff374d1..3b050ff 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -53,6 +53,10 @@
 class ImageSkia;
 }
 
+namespace mojo {
+class ApplicationDelegate;
+}
+
 namespace net {
 class CookieOptions;
 class NetLog;
@@ -270,6 +274,12 @@
   virtual void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
                                               int child_process_id) {}
 
+  // This is called on the process launching thread, when files that should be
+  // passed to the client have been opened.  It allows command line switches to
+  // be added to tell the client where to find its files.
+  virtual void AppendMappedFileCommandLineSwitches(
+      base::CommandLine* command_line) {}
+
   // Returns the locale used by the application.
   // This is called on the UI and IO threads.
   virtual std::string GetApplicationLocale();
@@ -578,6 +588,13 @@
       ServiceRegistry* registry,
       RenderFrameHost* render_frame_host) {}
 
+  using StaticMojoApplicationMap =
+      std::map<GURL, base::Callback<scoped_ptr<mojo::ApplicationDelegate>()>>;
+
+  // Registers in-process Mojo application loaders with the browser's global
+  // Mojo shell.
+  virtual void RegisterMojoApplications(StaticMojoApplicationMap* apps) {}
+
   // Registers additional navigator.connect service factories available in a
   // particular NavigatorConnectContext.
   virtual void GetAdditionalNavigatorConnectServices(
diff --git a/content/public/browser/devtools_agent_host.h b/content/public/browser/devtools_agent_host.h
index fd27ea1..419bbd3 100644
--- a/content/public/browser/devtools_agent_host.h
+++ b/content/public/browser/devtools_agent_host.h
@@ -12,11 +12,14 @@
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/devtools_agent_host_client.h"
 #include "url/gurl.h"
 
+namespace base {
+class SingleThreadTaskRunner;
+}
+
 namespace net {
 class ServerSocket;
 }
diff --git a/content/public/browser/mojo_app_connection.h b/content/public/browser/mojo_app_connection.h
new file mode 100644
index 0000000..f7c0272
--- /dev/null
+++ b/content/public/browser/mojo_app_connection.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 CONTENT_PUBLIC_BROWSER_MOJO_APP_CONNECTION_H_
+#define CONTENT_PUBLIC_BROWSER_MOJO_APP_CONNECTION_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
+#include "third_party/mojo/src/mojo/public/cpp/system/message_pipe.h"
+
+class GURL;
+
+namespace content {
+
+// This provides a way for arbitrary browser code to connect to Mojo apps. These
+// objects are not thread-safe but may be constructed and used on any single
+// thread.
+class CONTENT_EXPORT MojoAppConnection {
+ public:
+  virtual ~MojoAppConnection() {}
+
+  // Creates a new connection to the application at |url|. This may be called
+  // from any thread.
+  static scoped_ptr<MojoAppConnection> Create(const GURL& url);
+
+  // Connects to a service within the application.
+  template <typename Interface>
+  void ConnectToService(mojo::InterfacePtr<Interface>* proxy) {
+    ConnectToService(Interface::Name_, mojo::GetProxy(proxy).PassMessagePipe());
+  }
+
+  virtual void ConnectToService(const std::string& service_name,
+                                mojo::ScopedMessagePipeHandle handle) = 0;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_BROWSER_MOJO_APP_CONNECTION_H_
diff --git a/content/public/browser/permission_manager.h b/content/public/browser/permission_manager.h
index a0b9512..5a2e0787 100644
--- a/content/public/browser/permission_manager.h
+++ b/content/public/browser/permission_manager.h
@@ -14,10 +14,18 @@
 enum class PermissionType;
 class RenderFrameHost;
 
+// This class allows the content layer to manipulate permissions. It has to be
+// implemented by the embedder which ultimately handles the permission
+// management for the content layer.
 class CONTENT_EXPORT PermissionManager {
  public:
   virtual ~PermissionManager() = default;
 
+  // Requests a permission on behalf of a frame identified by render_frame_host.
+  // The |request_id| is an identifier that can later be used if the request is
+  // cancelled (see CancelPermissionRequest).
+  // When the permission request is handled, whether it failed, timed out or
+  // succeeded, the |callback| will be run.
   virtual void RequestPermission(
       PermissionType permission,
       RenderFrameHost* render_frame_host,
@@ -26,20 +34,29 @@
       bool user_gesture,
       const base::Callback<void(PermissionStatus)>& callback) = 0;
 
+  // Cancels a previously requested permission. The given parameter must match
+  // the ones passed to the RequestPermission call.
   virtual void CancelPermissionRequest(PermissionType permission,
                                        RenderFrameHost* render_frame_host,
                                        int request_id,
                                        const GURL& requesting_origin) = 0;
 
+  // Returns the permission status of a given requesting_origin/embedding_origin
+  // tuple. This is not taking a RenderFrameHost because the call might happen
+  // outside of a frame context.
   virtual PermissionStatus GetPermissionStatus(
       PermissionType permission,
       const GURL& requesting_origin,
       const GURL& embedding_origin) = 0;
 
+  // Sets the permission back to its default for the requesting_origin/
+  // embedding_origin tuple.
   virtual void ResetPermission(PermissionType permission,
                                const GURL& requesting_origin,
                                const GURL& embedding_origin) = 0;
 
+  // Registers a permission usage.
+  // TODO(mlamouri): see if we can remove this from the PermissionManager.
   virtual void RegisterPermissionUsage(PermissionType permission,
                                        const GURL& requesting_origin,
                                        const GURL& embedding_origin) = 0;
@@ -53,6 +70,9 @@
       const GURL& embedding_origin,
       const base::Callback<void(PermissionStatus)>& callback) = 0;
 
+  // Unregisters from permission status change notifications.
+  // The |subscription_id| must match the value returned by the
+  // SubscribePermissionStatusChange call.
   virtual void UnsubscribePermissionStatusChange(int subscription_id) = 0;
 };
 
diff --git a/content/public/browser/render_frame_host.h b/content/public/browser/render_frame_host.h
index cc02139..46f43913 100644
--- a/content/public/browser/render_frame_host.h
+++ b/content/public/browser/render_frame_host.h
@@ -94,6 +94,7 @@
   virtual void AccessibilityDoDefaultAction(int acc_obj_id) = 0;
   virtual void AccessibilityScrollToMakeVisible(
       int acc_obj_id, const gfx::Rect& subfocus) = 0;
+  virtual void AccessibilityShowContextMenu(int acc_obj_id) = 0;
   virtual void AccessibilitySetTextSelection(
       int acc_obj_id, int start_offset, int end_offset) = 0;
 
diff --git a/content/public/browser/tracing_delegate.cc b/content/public/browser/tracing_delegate.cc
new file mode 100644
index 0000000..4880574
--- /dev/null
+++ b/content/public/browser/tracing_delegate.cc
@@ -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.
+
+#include "content/public/browser/tracing_delegate.h"
+
+namespace content {
+
+bool TracingDelegate::IsAllowedToBeginBackgroundScenario(
+    const BackgroundTracingConfig& config,
+    bool requires_anonymized_data) {
+  return false;
+}
+
+bool TracingDelegate::IsAllowedToEndBackgroundScenario(
+    const content::BackgroundTracingConfig& config,
+    bool requires_anonymized_data) {
+  return false;
+}
+
+}  // namespace content
diff --git a/content/public/browser/tracing_delegate.h b/content/public/browser/tracing_delegate.h
index 5fab907..b7cfa2d4 100644
--- a/content/public/browser/tracing_delegate.h
+++ b/content/public/browser/tracing_delegate.h
@@ -6,23 +6,38 @@
 #define CONTENT_PUBLIC_BROWSER_TRACING_DELEGATE_H_
 
 #include "base/memory/scoped_ptr.h"
+#include "content/common/content_export.h"
+
+namespace base {
+class Time;
+}
 
 namespace net {
 class URLRequestContextGetter;
 }
 
 namespace content {
+struct BackgroundTracingConfig;
 class TraceUploader;
 
 // This can be implemented by the embedder to provide functionality for the
 // about://tracing WebUI.
-class TracingDelegate {
+class CONTENT_EXPORT TracingDelegate {
  public:
   virtual ~TracingDelegate() {}
 
   // Provide trace uploading functionality; see trace_uploader.h.
   virtual scoped_ptr<TraceUploader> GetTraceUploader(
       net::URLRequestContextGetter* request_context) = 0;
+
+  // This can be used to veto a particular background tracing scenario.
+  virtual bool IsAllowedToBeginBackgroundScenario(
+      const BackgroundTracingConfig& config,
+      bool requires_anonymized_data);
+
+  virtual bool IsAllowedToEndBackgroundScenario(
+      const content::BackgroundTracingConfig& config,
+      bool requires_anonymized_data);
 };
 
 }  // namespace content
diff --git a/content/public/child/fixed_received_data.cc b/content/public/child/fixed_received_data.cc
index 773a3fd9..96599c2 100644
--- a/content/public/child/fixed_received_data.cc
+++ b/content/public/child/fixed_received_data.cc
@@ -12,7 +12,7 @@
     : data_(data, data + length), encoded_length_(encoded_length) {
 }
 
-FixedReceivedData::FixedReceivedData(scoped_ptr<ReceivedData> data)
+FixedReceivedData::FixedReceivedData(ReceivedData* data)
     : FixedReceivedData(data->payload(),
                         data->encoded_length(),
                         data->encoded_length()) {
diff --git a/content/public/child/fixed_received_data.h b/content/public/child/fixed_received_data.h
index beb2c41..8acba46 100644
--- a/content/public/child/fixed_received_data.h
+++ b/content/public/child/fixed_received_data.h
@@ -7,17 +7,16 @@
 
 #include <vector>
 
-#include "base/memory/scoped_ptr.h"
 #include "content/common/content_export.h"
 #include "content/public/child/request_peer.h"
 
 namespace content {
 
 class CONTENT_EXPORT FixedReceivedData final
-    : public RequestPeer::ReceivedData {
+    : public RequestPeer::ThreadSafeReceivedData {
  public:
   FixedReceivedData(const char* data, size_t length, int encoded_length);
-  explicit FixedReceivedData(scoped_ptr<ReceivedData> data);
+  explicit FixedReceivedData(ReceivedData* data);
   FixedReceivedData(const std::vector<char>& data, int encoded_length);
   ~FixedReceivedData() override;
 
diff --git a/content/public/child/request_peer.h b/content/public/child/request_peer.h
index 2322792..a6149b74 100644
--- a/content/public/child/request_peer.h
+++ b/content/public/child/request_peer.h
@@ -52,6 +52,9 @@
     virtual int encoded_length() const = 0;
   };
 
+  // A ThreadSafeReceivedData can be deleted on ANY thread.
+  class CONTENT_EXPORT ThreadSafeReceivedData : public ReceivedData {};
+
   // Called as upload progress is made.
   // note: only for requests with upload progress enabled.
   virtual void OnUploadProgress(uint64 position, uint64 size) = 0;
diff --git a/content/public/common/resource_response.cc b/content/public/common/resource_response.cc
index 79471640..12f1dd7 100644
--- a/content/public/common/resource_response.cc
+++ b/content/public/common/resource_response.cc
@@ -47,6 +47,8 @@
       head.response_type_via_service_worker;
   new_response->head.service_worker_start_time =
       head.service_worker_start_time;
+  new_response->head.service_worker_ready_time =
+      head.service_worker_ready_time;
   return new_response;
 }
 
diff --git a/content/public/common/resource_response_info.h b/content/public/common/resource_response_info.h
index e023b308..8616539 100644
--- a/content/public/common/resource_response_info.h
+++ b/content/public/common/resource_response_info.h
@@ -120,11 +120,15 @@
   // The type of the response which was fetched by the ServiceWorker.
   blink::WebServiceWorkerResponseType response_type_via_service_worker;
 
-  // The time immediately before starting ServiceWorker, or if the worker is
-  // already running, the time immediately before dispatching fetch event.
-  // If the response is not provided by the ServiceWorker, it is kept empty.
+  // The time immediately before starting ServiceWorker. If the response is not
+  // provided by the ServiceWorker, kept empty.
   // TODO(ksakamoto): Move this to net::LoadTimingInfo.
   base::TimeTicks service_worker_start_time;
+
+  // The time immediately before dispatching fetch event in ServiceWorker.
+  // If the response is not provided by the ServiceWorker, kept empty.
+  // TODO(ksakamoto): Move this to net::LoadTimingInfo.
+  base::TimeTicks service_worker_ready_time;
 };
 
 }  // namespace content
diff --git a/content/public/renderer/render_thread.h b/content/public/renderer/render_thread.h
index d22126c..3a2f9b0 100644
--- a/content/public/renderer/render_thread.h
+++ b/content/public/renderer/render_thread.h
@@ -17,7 +17,6 @@
 
 namespace base {
 class MessageLoop;
-class MessageLoopProxy;
 class WaitableEvent;
 }
 
diff --git a/content/public/test/DEPS b/content/public/test/DEPS
index fbe84ed7..88c3916 100644
--- a/content/public/test/DEPS
+++ b/content/public/test/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "-content",
   "+content/public",
+  "+mojo/application",
   "+v8/include/v8.h",
 ]
 
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index 9892f2e3..c5078fc1 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -8,7 +8,8 @@
 #include "base/command_line.h"
 #include "base/debug/stack_trace.h"
 #include "base/i18n/icu_util.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/sys_info.h"
 #include "base/test/test_timeouts.h"
@@ -335,7 +336,7 @@
       RenderProcessHostImpl::GetInProcessRendererThreadForTesting();
   CHECK(renderer_loop);
 
-  renderer_loop->PostTask(
+  renderer_loop->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(&RunTaskOnRendererThread, task, runner->QuitClosure()));
   runner->Run();
diff --git a/content/public/test/content_test_suite_base.cc b/content/public/test/content_test_suite_base.cc
index 7598b0d..6ced225 100644
--- a/content/public/test/content_test_suite_base.cc
+++ b/content/public/test/content_test_suite_base.cc
@@ -74,6 +74,7 @@
 
 #if !defined(OS_IOS) && defined(V8_USE_EXTERNAL_STARTUP_DATA)
   gin::V8Initializer::LoadV8Snapshot();
+  gin::V8Initializer::LoadV8Natives();
 #endif
 
 #if defined(OS_ANDROID)
diff --git a/content/public/test/fake_speech_recognition_manager.cc b/content/public/test/fake_speech_recognition_manager.cc
index e728ee2..dbaf365 100644
--- a/content/public/test/fake_speech_recognition_manager.cc
+++ b/content/public/test/fake_speech_recognition_manager.cc
@@ -5,8 +5,10 @@
 #include "content/public/test/fake_speech_recognition_manager.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/browser/speech_recognition_event_listener.h"
 #include "content/public/browser/speech_recognition_manager_delegate.h"
 #include "content/public/common/speech_recognition_result.h"
@@ -79,7 +81,7 @@
 
   if (should_send_fake_response_) {
     // Give the fake result in a short while.
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(
             &FakeSpeechRecognitionManager::SetFakeRecognitionResult,
diff --git a/content/public/test/frame_load_waiter.cc b/content/public/test/frame_load_waiter.cc
index 6da69afb..c9cee10 100644
--- a/content/public/test/frame_load_waiter.cc
+++ b/content/public/test/frame_load_waiter.cc
@@ -5,7 +5,8 @@
 #include "content/public/test/frame_load_waiter.h"
 
 #include "base/location.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 
 namespace content {
 
@@ -21,7 +22,8 @@
 void FrameLoadWaiter::DidFinishLoad() {
   // Post a task to quit instead of quitting directly, since the load completion
   // may trigger other IPCs that tests are expecting.
-  base::MessageLoop::current()->PostTask(FROM_HERE, run_loop_.QuitClosure());
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                run_loop_.QuitClosure());
 }
 
 }  // namespace content
diff --git a/content/public/test/mock_blob_url_request_context.cc b/content/public/test/mock_blob_url_request_context.cc
index f0cd5461..e2c6fa3 100644
--- a/content/public/test/mock_blob_url_request_context.cc
+++ b/content/public/test/mock_blob_url_request_context.cc
@@ -4,6 +4,7 @@
 
 #include "content/public/test/mock_blob_url_request_context.h"
 
+#include "base/thread_task_runner_handle.h"
 #include "storage/browser/blob/blob_data_builder.h"
 #include "storage/browser/blob/blob_storage_context.h"
 #include "storage/browser/blob/blob_url_request_job.h"
@@ -16,10 +17,9 @@
     : blob_storage_context_(new storage::BlobStorageContext) {
   // Job factory owns the protocol handler.
   job_factory_.SetProtocolHandler(
-      "blob",
-      new storage::BlobProtocolHandler(blob_storage_context_.get(),
-                                       file_system_context,
-                                       base::MessageLoopProxy::current()));
+      "blob", new storage::BlobProtocolHandler(
+                  blob_storage_context_.get(), file_system_context,
+                  base::ThreadTaskRunnerHandle::Get()));
   set_job_factory(&job_factory_);
 }
 
diff --git a/content/public/test/mock_render_thread.cc b/content/public/test/mock_render_thread.cc
index 9d3c51b..60f19f05 100644
--- a/content/public/test/mock_render_thread.cc
+++ b/content/public/test/mock_render_thread.cc
@@ -4,7 +4,8 @@
 
 #include "content/public/test/mock_render_thread.h"
 
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/common/frame_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/renderer/render_process_observer.h"
@@ -63,7 +64,7 @@
 }
 
 scoped_refptr<base::SingleThreadTaskRunner> MockRenderThread::GetTaskRunner() {
-  return base::MessageLoopProxy::current();
+  return base::ThreadTaskRunnerHandle::Get();
 }
 
 IPC::SyncChannel* MockRenderThread::GetChannel() {
diff --git a/content/public/test/mock_storage_client.cc b/content/public/test/mock_storage_client.cc
index 7342855..8370e6c 100644
--- a/content/public/test/mock_storage_client.cc
+++ b/content/public/test/mock_storage_client.cc
@@ -6,10 +6,12 @@
 
 #include "base/basictypes.h"
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/singleton.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "net/base/net_util.h"
 #include "storage/browser/quota/quota_manager_proxy.h"
 
@@ -92,7 +94,7 @@
 void MockStorageClient::GetOriginUsage(const GURL& origin_url,
                                        StorageType type,
                                        const GetUsageCallback& callback) {
-  base::MessageLoopProxy::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&MockStorageClient::RunGetOriginUsage,
                  weak_factory_.GetWeakPtr(), origin_url, type, callback));
@@ -100,25 +102,23 @@
 
 void MockStorageClient::GetOriginsForType(
     StorageType type, const GetOriginsCallback& callback) {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&MockStorageClient::RunGetOriginsForType,
-                 weak_factory_.GetWeakPtr(), type, callback));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&MockStorageClient::RunGetOriginsForType,
+                            weak_factory_.GetWeakPtr(), type, callback));
 }
 
 void MockStorageClient::GetOriginsForHost(
     StorageType type, const std::string& host,
     const GetOriginsCallback& callback) {
-  base::MessageLoopProxy::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&MockStorageClient::RunGetOriginsForHost,
-                 weak_factory_.GetWeakPtr(), type, host, callback));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&MockStorageClient::RunGetOriginsForHost,
+                            weak_factory_.GetWeakPtr(), type, host, callback));
 }
 
 void MockStorageClient::DeleteOriginData(
     const GURL& origin, StorageType type,
     const DeletionCallback& callback) {
-  base::MessageLoopProxy::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&MockStorageClient::RunDeleteOriginData,
                  weak_factory_.GetWeakPtr(), origin, type, callback));
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index e6925e2..2626240 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -6,7 +6,9 @@
 
 #include <cctype>
 
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "components/scheduler/renderer/renderer_scheduler.h"
 #include "content/common/dom_storage/dom_storage_types.h"
 #include "content/common/frame_messages.h"
@@ -133,7 +135,8 @@
 }
 
 void RenderViewTest::ProcessPendingMessages() {
-  msg_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
+  msg_loop_.task_runner()->PostTask(FROM_HERE,
+                                    base::MessageLoop::QuitClosure());
   msg_loop_.Run();
 }
 
diff --git a/content/public/test/sandbox_file_system_test_helper.cc b/content/public/test/sandbox_file_system_test_helper.cc
index 38af9df..9e52ee86 100644
--- a/content/public/test/sandbox_file_system_test_helper.cc
+++ b/content/public/test/sandbox_file_system_test_helper.cc
@@ -5,7 +5,6 @@
 #include "content/public/test/sandbox_file_system_test_helper.h"
 
 #include "base/files/file_util.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
 #include "content/public/test/mock_special_storage_policy.h"
 #include "content/public/test/test_file_system_context.h"
diff --git a/content/public/test/test_file_system_context.cc b/content/public/test/test_file_system_context.cc
index d44765b..7f60250 100644
--- a/content/public/test/test_file_system_context.cc
+++ b/content/public/test/test_file_system_context.cc
@@ -5,6 +5,7 @@
 #include "content/public/test/test_file_system_context.h"
 
 #include "base/memory/scoped_vector.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/test/mock_special_storage_policy.h"
 #include "content/public/test/test_file_system_backend.h"
 #include "content/public/test/test_file_system_options.h"
@@ -19,7 +20,7 @@
     const base::FilePath& base_path) {
   ScopedVector<storage::FileSystemBackend> additional_providers;
   additional_providers.push_back(new TestFileSystemBackend(
-      base::MessageLoopProxy::current().get(), base_path));
+      base::ThreadTaskRunnerHandle::Get().get(), base_path));
   return CreateFileSystemContextWithAdditionalProvidersForTesting(
       quota_manager_proxy, additional_providers.Pass(), base_path);
 }
@@ -30,14 +31,12 @@
     ScopedVector<storage::FileSystemBackend> additional_providers,
     const base::FilePath& base_path) {
   return new storage::FileSystemContext(
-      base::MessageLoopProxy::current().get(),
-      base::MessageLoopProxy::current().get(),
+      base::ThreadTaskRunnerHandle::Get().get(),
+      base::ThreadTaskRunnerHandle::Get().get(),
       storage::ExternalMountPoints::CreateRefCounted().get(),
       make_scoped_refptr(new MockSpecialStoragePolicy()).get(),
-      quota_manager_proxy,
-      additional_providers.Pass(),
-      std::vector<storage::URLRequestAutoMountHandler>(),
-      base_path,
+      quota_manager_proxy, additional_providers.Pass(),
+      std::vector<storage::URLRequestAutoMountHandler>(), base_path,
       CreateAllowFileAccessOptions());
 }
 
@@ -47,15 +46,12 @@
     const std::vector<storage::URLRequestAutoMountHandler>& auto_mounters,
     const base::FilePath& base_path) {
   return new storage::FileSystemContext(
-      base::MessageLoopProxy::current().get(),
-      base::MessageLoopProxy::current().get(),
+      base::ThreadTaskRunnerHandle::Get().get(),
+      base::ThreadTaskRunnerHandle::Get().get(),
       storage::ExternalMountPoints::CreateRefCounted().get(),
       make_scoped_refptr(new MockSpecialStoragePolicy()).get(),
-      quota_manager_proxy,
-      additional_providers.Pass(),
-      auto_mounters,
-      base_path,
-      CreateAllowFileAccessOptions());
+      quota_manager_proxy, additional_providers.Pass(), auto_mounters,
+      base_path, CreateAllowFileAccessOptions());
 }
 
 storage::FileSystemContext* CreateIncognitoFileSystemContextForTesting(
@@ -63,14 +59,12 @@
     const base::FilePath& base_path) {
   ScopedVector<storage::FileSystemBackend> additional_providers;
   return new storage::FileSystemContext(
-      base::MessageLoopProxy::current().get(),
-      base::MessageLoopProxy::current().get(),
+      base::ThreadTaskRunnerHandle::Get().get(),
+      base::ThreadTaskRunnerHandle::Get().get(),
       storage::ExternalMountPoints::CreateRefCounted().get(),
       make_scoped_refptr(new MockSpecialStoragePolicy()).get(),
-      quota_manager_proxy,
-      additional_providers.Pass(),
-      std::vector<storage::URLRequestAutoMountHandler>(),
-      base_path,
+      quota_manager_proxy, additional_providers.Pass(),
+      std::vector<storage::URLRequestAutoMountHandler>(), base_path,
       CreateIncognitoFileSystemOptions());
 }
 
diff --git a/content/public/test/test_mojo_app.cc b/content/public/test/test_mojo_app.cc
new file mode 100644
index 0000000..bebb7a7
--- /dev/null
+++ b/content/public/test/test_mojo_app.cc
@@ -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.
+
+#include "content/public/test/test_mojo_app.h"
+
+#include "base/logging.h"
+#include "mojo/application/public/cpp/application_connection.h"
+#include "mojo/application/public/cpp/application_impl.h"
+
+namespace content {
+
+const char kTestMojoAppUrl[] = "system:content_mojo_test";
+
+TestMojoApp::TestMojoApp() : service_binding_(this), app_(nullptr) {
+}
+
+TestMojoApp::~TestMojoApp() {
+}
+
+void TestMojoApp::Initialize(mojo::ApplicationImpl* app) {
+  app_ = app;
+}
+
+bool TestMojoApp::ConfigureIncomingConnection(
+    mojo::ApplicationConnection* connection) {
+  connection->AddService<TestMojoService>(this);
+  return true;
+}
+
+void TestMojoApp::Create(mojo::ApplicationConnection* connection,
+                         mojo::InterfaceRequest<TestMojoService> request) {
+  DCHECK(!service_binding_.is_bound());
+  service_binding_.Bind(request.Pass());
+}
+
+void TestMojoApp::DoSomething(const DoSomethingCallback& callback) {
+  callback.Run();
+  DCHECK(app_);
+  app_->Terminate();
+}
+
+}  // namespace content
diff --git a/content/public/test/test_mojo_app.h b/content/public/test/test_mojo_app.h
new file mode 100644
index 0000000..e01e7b50
--- /dev/null
+++ b/content/public/test/test_mojo_app.h
@@ -0,0 +1,50 @@
+// 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 CONTENT_PUBLIC_TEST_TEST_MOJO_APP_H_
+#define CONTENT_PUBLIC_TEST_TEST_MOJO_APP_H_
+
+#include "base/macros.h"
+#include "content/public/test/test_mojo_service.mojom.h"
+#include "mojo/application/public/cpp/application_delegate.h"
+#include "mojo/application/public/cpp/interface_factory.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
+
+namespace content {
+
+extern const char kTestMojoAppUrl[];
+
+// Simple Mojo app which provides a TestMojoService impl. The app terminates
+// itself after its TestService fulfills a single DoSomething call.
+class TestMojoApp : public mojo::ApplicationDelegate,
+                    public mojo::InterfaceFactory<TestMojoService>,
+                    public TestMojoService {
+ public:
+  TestMojoApp();
+  ~TestMojoApp() override;
+
+ private:
+  // mojo::ApplicationDelegate:
+  void Initialize(mojo::ApplicationImpl* app) override;
+  bool ConfigureIncomingConnection(
+      mojo::ApplicationConnection* connection) override;
+
+  // mojo::InterfaceFactory<TestMojoService>:
+  void Create(mojo::ApplicationConnection* connection,
+              mojo::InterfaceRequest<TestMojoService> request) override;
+
+  // TestMojoService:
+  void DoSomething(const DoSomethingCallback& callback) override;
+
+  mojo::Binding<TestMojoService> service_binding_;
+
+  // Not owned.
+  mojo::ApplicationImpl* app_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestMojoApp);
+};
+
+}  // namespace
+
+#endif  // CONTENT_PUBLIC_TEST_TEST_MOJO_APP_H_
diff --git a/content/public/test/test_mojo_service.mojom b/content/public/test/test_mojo_service.mojom
new file mode 100644
index 0000000..e417916
--- /dev/null
+++ b/content/public/test/test_mojo_service.mojom
@@ -0,0 +1,9 @@
+// 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 content;
+
+interface TestMojoService {
+  DoSomething() => ();
+};
diff --git a/content/public/test/test_renderer_host.h b/content/public/test/test_renderer_host.h
index 9945d87..fc12cbeb 100644
--- a/content/public/test/test_renderer_host.h
+++ b/content/public/test/test_renderer_host.h
@@ -132,11 +132,12 @@
   virtual ~RenderViewHostTester() {}
 
   // Gives tests access to RenderViewHostImpl::CreateRenderView.
-  virtual bool CreateRenderView(const base::string16& frame_name,
-                                int opener_route_id,
-                                int proxy_routing_id,
-                                int32 max_page_id,
-                                bool created_with_opener) = 0;
+  virtual bool CreateTestRenderView(
+      const base::string16& frame_name,
+      int opener_route_id,
+      int proxy_routing_id,
+      int32 max_page_id,
+      bool created_with_opener) = 0;
 
   // Makes the WasHidden/WasShown calls to the RenderWidget that
   // tell it it has been hidden or restored from having been hidden.
diff --git a/content/public/test/test_utils.cc b/content/public/test/test_utils.cc
index 2fa45c0..4293f39 100644
--- a/content/public/test/test_utils.cc
+++ b/content/public/test/test_utils.cc
@@ -5,9 +5,11 @@
 #include "content/public/test/test_utils.h"
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "content/public/browser/browser_child_process_host_iterator.h"
 #include "content/public/browser/notification_service.h"
@@ -37,7 +39,7 @@
   if (num_quit_deferrals <= 0) {
     quit_task.Run();
   } else {
-    base::MessageLoop::current()->PostTask(
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&DeferredQuitRunLoop, quit_task, num_quit_deferrals - 1));
   }
@@ -127,8 +129,8 @@
 
 void RunAllPendingInMessageLoop() {
   base::RunLoop run_loop;
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,  GetQuitTaskForRunLoop(&run_loop));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, GetQuitTaskForRunLoop(&run_loop));
   RunThisRunLoop(&run_loop);
 }
 
diff --git a/content/public/utility/BUILD.gn b/content/public/utility/BUILD.gn
index 999549a..1f3e987 100644
--- a/content/public/utility/BUILD.gn
+++ b/content/public/utility/BUILD.gn
@@ -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("//content/utility/utility.gni")
+
 # See //content/BUILD.gn for how this works.
 group("utility") {
   if (is_component_build) {
@@ -18,12 +20,9 @@
 source_set("utility_sources") {
   visibility = [ "//content/*" ]
 
-  sources = [
-    "content_utility_client.cc",
-    "content_utility_client.h",
-    "utility_thread.cc",
-    "utility_thread.h",
-  ]
+  sources = rebase_path(content_utility_gypi_values.public_utility_sources,
+                        ".",
+                        "//content")
 
   configs += [ "//content:content_implementation" ]
 
diff --git a/content/public/utility/content_utility_client.h b/content/public/utility/content_utility_client.h
index 8a333e7e..b326eae 100644
--- a/content/public/utility/content_utility_client.h
+++ b/content/public/utility/content_utility_client.h
@@ -5,8 +5,18 @@
 #ifndef CONTENT_PUBLIC_UTILITY_CONTENT_UTILITY_CLIENT_H_
 #define CONTENT_PUBLIC_UTILITY_CONTENT_UTILITY_CLIENT_H_
 
+#include <map>
+
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
 #include "content/public/common/content_client.h"
 
+class GURL;
+
+namespace mojo {
+class ApplicationDelegate;
+}
+
 namespace content {
 
 class ServiceRegistry;
@@ -14,6 +24,9 @@
 // Embedder API for participating in renderer logic.
 class CONTENT_EXPORT ContentUtilityClient {
  public:
+  using StaticMojoApplicationMap =
+      std::map<GURL, base::Callback<scoped_ptr<mojo::ApplicationDelegate>()>>;
+
   virtual ~ContentUtilityClient() {}
 
   // Notifies us that the UtilityThread has been created.
@@ -24,6 +37,9 @@
 
   // Registers Mojo services.
   virtual void RegisterMojoServices(ServiceRegistry* registry) {}
+
+  // Registers Mojo applications.
+  virtual void RegisterMojoApplications(StaticMojoApplicationMap* apps) {}
 };
 
 }  // namespace content
diff --git a/content/renderer/accessibility/renderer_accessibility.cc b/content/renderer/accessibility/renderer_accessibility.cc
index 609348fa..ad1967e 100644
--- a/content/renderer/accessibility/renderer_accessibility.cc
+++ b/content/renderer/accessibility/renderer_accessibility.cc
@@ -96,6 +96,7 @@
     IPC_MESSAGE_HANDLER(AccessibilityMsg_ScrollToPoint, OnScrollToPoint)
     IPC_MESSAGE_HANDLER(AccessibilityMsg_SetTextSelection, OnSetTextSelection)
     IPC_MESSAGE_HANDLER(AccessibilityMsg_SetValue, OnSetValue)
+    IPC_MESSAGE_HANDLER(AccessibilityMsg_ShowContextMenu, OnShowContextMenu)
     IPC_MESSAGE_HANDLER(AccessibilityMsg_HitTest, OnHitTest)
     IPC_MESSAGE_HANDLER(AccessibilityMsg_SetAccessibilityFocus,
                         OnSetAccessibilityFocus)
@@ -505,4 +506,20 @@
   HandleAXEvent(obj, ui::AX_EVENT_VALUE_CHANGED);
 }
 
+void RendererAccessibility::OnShowContextMenu(int acc_obj_id) {
+  const WebDocument& document = GetMainDocument();
+  if (document.isNull())
+    return;
+
+  WebAXObject obj = document.accessibilityObjectFromID(acc_obj_id);
+  if (obj.isDetached()) {
+#ifndef NDEBUG
+    LOG(WARNING) << "ShowContextMenu on invalid object id " << acc_obj_id;
+#endif
+    return;
+  }
+
+  obj.showContextMenu();
+}
+
 }  // namespace content
diff --git a/content/renderer/accessibility/renderer_accessibility.h b/content/renderer/accessibility/renderer_accessibility.h
index 5ab857f..9f8d63f 100644
--- a/content/renderer/accessibility/renderer_accessibility.h
+++ b/content/renderer/accessibility/renderer_accessibility.h
@@ -108,6 +108,7 @@
   void OnSetFocus(int acc_obj_id);
   void OnSetTextSelection(int acc_obj_id, int start_offset, int end_offset);
   void OnSetValue(int acc_obj_id, base::string16 value);
+  void OnShowContextMenu(int acc_obj_id);
 
   // Events from Blink are collected until they are ready to be
   // sent to the browser.
diff --git a/content/renderer/accessibility/renderer_accessibility_browsertest.cc b/content/renderer/accessibility/renderer_accessibility_browsertest.cc
index b237d23..b1d4c0b0 100644
--- a/content/renderer/accessibility/renderer_accessibility_browsertest.cc
+++ b/content/renderer/accessibility/renderer_accessibility_browsertest.cc
@@ -6,6 +6,7 @@
 #include "base/time/time.h"
 #include "content/common/frame_messages.h"
 #include "content/common/view_message_enums.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/test/render_view_test.h"
 #include "content/renderer/accessibility/renderer_accessibility.h"
 #include "content/renderer/render_frame_impl.h"
@@ -156,6 +157,14 @@
 
 TEST_F(RendererAccessibilityTest,
        MAYBE_AccessibilityMessagesQueueWhileSwappedOut) {
+  // This test breaks down in --site-per-process, as swapping out destroys
+  // the main frame and it cannot be further navigated.
+  // TODO(nasko): Figure out what this behavior looks like when swapped out
+  // no longer exists.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    return;
+  }
   std::string html =
       "<body>"
       "  <p>Hello, world.</p>"
diff --git a/content/renderer/child_frame_compositing_helper.cc b/content/renderer/child_frame_compositing_helper.cc
index de018b0..d72b3e9 100644
--- a/content/renderer/child_frame_compositing_helper.cc
+++ b/content/renderer/child_frame_compositing_helper.cc
@@ -14,6 +14,7 @@
 #include "cc/output/copy_output_request.h"
 #include "cc/output/copy_output_result.h"
 #include "cc/resources/single_release_callback.h"
+#include "content/child/thread_safe_sender.h"
 #include "content/common/browser_plugin/browser_plugin_messages.h"
 #include "content/common/frame_messages.h"
 #include "content/common/gpu/client/context_provider_command_buffer.h"
@@ -61,8 +62,7 @@
       opaque_(true),
       browser_plugin_(browser_plugin),
       render_frame_proxy_(render_frame_proxy),
-      frame_(frame),
-      weak_factory_(this) {
+      frame_(frame) {
 }
 
 ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {
@@ -271,23 +271,21 @@
 
 // static
 void ChildFrameCompositingHelper::SatisfyCallback(
-    base::WeakPtr<ChildFrameCompositingHelper> helper,
+    scoped_refptr<ThreadSafeSender> sender,
+    int host_routing_id,
     cc::SurfaceSequence sequence) {
-  if (helper && helper->render_frame_proxy_) {
-    helper->render_frame_proxy_->Send(
-        new FrameHostMsg_SatisfySequence(helper->host_routing_id_, sequence));
-  }
+  // This may be called on either the main or impl thread.
+  sender->Send(new FrameHostMsg_SatisfySequence(host_routing_id, sequence));
 }
 
 // static
 void ChildFrameCompositingHelper::RequireCallback(
-    base::WeakPtr<ChildFrameCompositingHelper> helper,
+    scoped_refptr<ThreadSafeSender> sender,
+    int host_routing_id,
     cc::SurfaceId id,
     cc::SurfaceSequence sequence) {
-  if (helper && helper->render_frame_proxy_) {
-    helper->render_frame_proxy_->Send(new FrameHostMsg_RequireSequence(
-        helper->host_routing_id_, id, sequence));
-  }
+  // This may be called on either the main or impl thread.
+  sender->Send(new FrameHostMsg_RequireSequence(host_routing_id, id, sequence));
 }
 
 void ChildFrameCompositingHelper::OnSetSurface(
@@ -304,10 +302,14 @@
     return;
 
   if (!surface_layer_.get()) {
+    scoped_refptr<ThreadSafeSender> sender(
+        RenderThreadImpl::current()->thread_safe_sender());
     cc::SurfaceLayer::SatisfyCallback satisfy_callback =
-        base::Bind(&ChildFrameCompositingHelper::SatisfyCallback, GetWeakPtr());
+        base::Bind(&ChildFrameCompositingHelper::SatisfyCallback, sender,
+                   host_routing_id_);
     cc::SurfaceLayer::RequireCallback require_callback =
-        base::Bind(&ChildFrameCompositingHelper::RequireCallback, GetWeakPtr());
+        base::Bind(&ChildFrameCompositingHelper::RequireCallback, sender,
+                   host_routing_id_);
     surface_layer_ =
         cc::SurfaceLayer::Create(cc_blink::WebLayerImpl::LayerSettings(),
                                  satisfy_callback, require_callback);
diff --git a/content/renderer/child_frame_compositing_helper.h b/content/renderer/child_frame_compositing_helper.h
index dd822c0..7442472 100644
--- a/content/renderer/child_frame_compositing_helper.h
+++ b/content/renderer/child_frame_compositing_helper.h
@@ -52,6 +52,7 @@
 class BrowserPlugin;
 class BrowserPluginManager;
 class RenderFrameProxy;
+class ThreadSafeSender;
 
 class CONTENT_EXPORT ChildFrameCompositingHelper
     : public base::RefCounted<ChildFrameCompositingHelper>,
@@ -106,16 +107,14 @@
                                          float device_scale_factor,
                                          cc::Layer* layer);
   void SendReturnedDelegatedResources();
-  static void SatisfyCallback(base::WeakPtr<ChildFrameCompositingHelper> helper,
+  static void SatisfyCallback(scoped_refptr<ThreadSafeSender> sender,
+                              int host_routing_id,
                               cc::SurfaceSequence sequence);
-  static void RequireCallback(base::WeakPtr<ChildFrameCompositingHelper> helper,
+  static void RequireCallback(scoped_refptr<ThreadSafeSender> sender,
+                              int host_routing_id,
                               cc::SurfaceId id,
                               cc::SurfaceSequence sequence);
 
-  base::WeakPtr<ChildFrameCompositingHelper> GetWeakPtr() {
-    return weak_factory_.GetWeakPtr();
-  }
-
   int host_routing_id_;
   int last_route_id_;
   uint32 last_output_surface_id_;
@@ -142,8 +141,6 @@
   scoped_ptr<blink::WebLayer> web_layer_;
   blink::WebFrame* frame_;
 
-  base::WeakPtrFactory<ChildFrameCompositingHelper> weak_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(ChildFrameCompositingHelper);
 };
 
diff --git a/content/renderer/gpu/gpu_benchmarking_extension.cc b/content/renderer/gpu/gpu_benchmarking_extension.cc
index 366d0a8b..27038d73 100644
--- a/content/renderer/gpu/gpu_benchmarking_extension.cc
+++ b/content/renderer/gpu/gpu_benchmarking_extension.cc
@@ -289,6 +289,22 @@
   if (!context.Init(false))
     return false;
 
+  // Convert coordinates from CSS pixels to density independent pixels (DIPs).
+  float page_scale_factor = context.web_view()->pageScaleFactor();
+
+  if (gesture_source_type == SyntheticGestureParams::MOUSE_INPUT) {
+    // Ensure the mouse is centered and visible, in case it will
+    // trigger any hover or mousemove effects.
+    blink::WebRect contentRect =
+        context.web_view()->mainFrame()->visibleContentRect();
+    blink::WebMouseEvent mouseMove;
+    mouseMove.type = blink::WebInputEvent::MouseMove;
+    mouseMove.x = (contentRect.x + contentRect.width / 2) * page_scale_factor;
+    mouseMove.y = (contentRect.y + contentRect.height / 2) * page_scale_factor;
+    context.web_view()->handleInputEvent(mouseMove);
+    context.web_view()->setCursorVisibilityState(true);
+  }
+
   scoped_refptr<CallbackAndContext> callback_and_context =
       new CallbackAndContext(
           isolate, callback, context.web_frame()->mainWorldScriptContext());
@@ -296,9 +312,6 @@
   scoped_ptr<SyntheticSmoothScrollGestureParams> gesture_params(
       new SyntheticSmoothScrollGestureParams);
 
-  // Convert coordinates from CSS pixels to density independent pixels (DIPs).
-  float page_scale_factor = context.web_view()->pageScaleFactor();
-
   if (gesture_source_type < 0 ||
       gesture_source_type > SyntheticGestureParams::GESTURE_SOURCE_TYPE_MAX) {
     return false;
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index abc1139..99f2121 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -178,6 +178,14 @@
   return gfx::Size(default_tile_size, default_tile_size);
 }
 
+int GetMaxBytesPerCopyOperation() {
+  const int kMegabyte = 1024 * 1024;
+
+  // 4MiB is the size of 4 512x512 tiles, which has proven to be a good
+  // default batch size for copy operations.
+  return kMegabyte * 4;
+}
+
 // Check cc::TopControlsState, and blink::WebTopControlsState
 // are kept in sync.
 static_assert(int(blink::WebTopControlsBoth) == int(cc::BOTH),
@@ -456,6 +464,8 @@
     settings.use_external_begin_frame_source = false;
   }
 
+  settings.max_bytes_per_copy_operation = GetMaxBytesPerCopyOperation();
+
   scoped_refptr<base::SingleThreadTaskRunner> compositor_thread_task_runner =
       compositor_deps_->GetCompositorImplThreadTaskRunner();
   scoped_refptr<base::SingleThreadTaskRunner>
@@ -954,6 +964,38 @@
   widget_->OnSwapBuffersAborted();
 }
 
+void RenderWidgetCompositor::RecordFrameTimingEvents(
+    scoped_ptr<cc::FrameTimingTracker::CompositeTimingSet> composite_events,
+    scoped_ptr<cc::FrameTimingTracker::MainFrameTimingSet> main_frame_events) {
+  for (const auto& composite_event : *composite_events ) {
+    int64_t frameId = composite_event.first;
+    const std::vector<cc::FrameTimingTracker::CompositeTimingEvent>& events =
+        composite_event.second;
+    std::vector<blink::WebFrameTimingEvent> webEvents;
+    for (size_t i = 0; i < events.size(); ++i) {
+      webEvents.push_back(blink::WebFrameTimingEvent(
+          events[i].frame_id,
+          (events[i].timestamp - base::TimeTicks()).InSecondsF()));
+    }
+    widget_->webwidget()->recordFrameTimingEvent(
+        blink::WebWidget::CompositeEvent, frameId, webEvents);
+  }
+  for (const auto& main_frame_event : *main_frame_events ) {
+    int64_t frameId = main_frame_event.first;
+    const std::vector<cc::FrameTimingTracker::MainFrameTimingEvent>& events =
+        main_frame_event.second;
+    std::vector<blink::WebFrameTimingEvent> webEvents;
+    for (size_t i = 0; i < events.size(); ++i) {
+      webEvents.push_back(blink::WebFrameTimingEvent(
+          events[i].frame_id,
+          (events[i].timestamp - base::TimeTicks()).InSecondsF(),
+          (events[i].end_time - base::TimeTicks()).InSecondsF()));
+    }
+    widget_->webwidget()->recordFrameTimingEvent(
+        blink::WebWidget::RenderEvent, frameId, webEvents);
+  }
+}
+
 void RenderWidgetCompositor::RateLimitSharedMainThreadContext() {
   cc::ContextProvider* provider =
       compositor_deps_->GetSharedMainThreadContextProvider();
diff --git a/content/renderer/gpu/render_widget_compositor.h b/content/renderer/gpu/render_widget_compositor.h
index 0ab2dbb8..4ad38bd3 100644
--- a/content/renderer/gpu/render_widget_compositor.h
+++ b/content/renderer/gpu/render_widget_compositor.h
@@ -154,6 +154,10 @@
   void DidCompleteSwapBuffers() override;
   void DidCompletePageScaleAnimation() override;
   void RateLimitSharedMainThreadContext() override;
+  void RecordFrameTimingEvents(
+      scoped_ptr<cc::FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<cc::FrameTimingTracker::MainFrameTimingSet> main_frame_events)
+      override;
 
   // cc::LayerTreeHostSingleThreadClient implementation.
   void ScheduleAnimation() override;
@@ -161,8 +165,8 @@
   void DidAbortSwapBuffers() override;
 
   enum {
-   OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK = 4,
-   MAX_OUTPUT_SURFACE_RETRIES = 5,
+    OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK = 4,
+    MAX_OUTPUT_SURFACE_RETRIES = 5,
   };
 
  protected:
diff --git a/content/renderer/history_entry.cc b/content/renderer/history_entry.cc
index efd6fb5..24d6aea4 100644
--- a/content/renderer/history_entry.cc
+++ b/content/renderer/history_entry.cc
@@ -69,7 +69,10 @@
         item_.documentSequenceNumber());
   }
 
-  if (clone_children_of_target || !is_target_frame) {
+  // TODO(creis): This needs to be updated to handle HistoryEntry in
+  // subframe processes, where the main frame isn't guaranteed to be in the
+  // same process.
+  if (current_frame && (clone_children_of_target || !is_target_frame)) {
     for (WebFrame* child = current_frame->GetWebFrame()->firstChild(); child;
          child = child->nextSibling()) {
       RenderFrameImpl* child_render_frame =
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc
index b7adc06df..ccab496 100644
--- a/content/renderer/media/android/webmediaplayer_android.cc
+++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -1658,12 +1658,13 @@
     blink::WebContentDecryptionModuleResult result) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
 
-  // TODO(xhwang): Support setMediaKeys(0) if necessary: http://crbug.com/330324
+  // Once the CDM is set it can't be cleared as there may be frames being
+  // decrypted on other threads. So fail this request.
+  // http://crbug.com/462365#c7.
   if (!cdm) {
     result.completeWithError(
-        blink::WebContentDecryptionModuleExceptionNotSupportedError,
-        0,
-        "Null MediaKeys object is not supported.");
+        blink::WebContentDecryptionModuleExceptionInvalidStateError, 0,
+        "The existing MediaKeys object cannot be removed at this time.");
     return;
   }
 
diff --git a/content/renderer/media/render_media_log.cc b/content/renderer/media/render_media_log.cc
index dacf1cf..eae60c0 100644
--- a/content/renderer/media/render_media_log.cc
+++ b/content/renderer/media/render_media_log.cc
@@ -40,11 +40,16 @@
 }
 
 void RenderMediaLog::AddEvent(scoped_ptr<media::MediaLogEvent> event) {
-  if (!task_runner_->BelongsToCurrentThread()) {
-    task_runner_->PostTask(FROM_HERE, base::Bind(&RenderMediaLog::AddEvent,
-                                                 this, base::Passed(&event)));
-    return;
-  }
+  // Always post to preserve the correct order of events.
+  // TODO(xhwang): Consider using sorted containers to keep the order and
+  // avoid extra posting.
+  task_runner_->PostTask(FROM_HERE,
+                         base::Bind(&RenderMediaLog::AddEventInternal, this,
+                                    base::Passed(&event)));
+}
+
+void RenderMediaLog::AddEventInternal(scoped_ptr<media::MediaLogEvent> event) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
 
   Log(event.get());
 
diff --git a/content/renderer/media/render_media_log.h b/content/renderer/media/render_media_log.h
index 31b9973..b5e41a56 100644
--- a/content/renderer/media/render_media_log.h
+++ b/content/renderer/media/render_media_log.h
@@ -35,6 +35,9 @@
  private:
   ~RenderMediaLog() override;
 
+  // Add event on the |task_runner_|.
+  void AddEventInternal(scoped_ptr<media::MediaLogEvent> event);
+
   // Posted as a delayed task to throttle ipc message frequency.
   void SendQueuedMediaEvents();
 
diff --git a/content/renderer/media/render_media_log_unittest.cc b/content/renderer/media/render_media_log_unittest.cc
index d1820341..fd192639 100644
--- a/content/renderer/media/render_media_log_unittest.cc
+++ b/content/renderer/media/render_media_log_unittest.cc
@@ -27,6 +27,8 @@
 
   void AddEvent(media::MediaLogEvent::Type type) {
     log_->AddEvent(log_->CreateEvent(type));
+    // AddEvent() could post. Run the task runner to make sure it's executed.
+    task_runner_->RunUntilIdle();
   }
 
   void Advance(base::TimeDelta delta) {
diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc
index 2fec5880..c95f052 100644
--- a/content/renderer/media/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/rtc_peer_connection_handler.cc
@@ -1306,9 +1306,18 @@
     // If the state becomes connected, send the time needed for PC to become
     // connected from checking to UMA. UMA data will help to know how much
     // time needed for PC to connect with remote peer.
+    if (ice_connection_checking_start_.is_null()) {
+      // From UMA, we have observed a large number of calls falling into the
+      // overflow buckets. One possibility is that the Checking is not signaled
+      // before Connected. This is to guard against that situation to make the
+      // metric more robust.
+      UMA_HISTOGRAM_MEDIUM_TIMES("WebRTC.PeerConnection.TimeToConnect",
+                                 base::TimeDelta());
+    } else {
     UMA_HISTOGRAM_MEDIUM_TIMES(
         "WebRTC.PeerConnection.TimeToConnect",
         base::TimeTicks::Now() - ice_connection_checking_start_);
+    }
   }
 
   track_metrics_.IceConnectionChange(new_state);
diff --git a/content/renderer/media/rtc_video_decoder.cc b/content/renderer/media/rtc_video_decoder.cc
index 979d194..2556dc6 100644
--- a/content/renderer/media/rtc_video_decoder.cc
+++ b/content/renderer/media/rtc_video_decoder.cc
@@ -12,6 +12,7 @@
 #include "base/stl_util.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task_runner_util.h"
+#include "content/renderer/media/webrtc/webrtc_video_frame_adapter.h"
 #include "gpu/command_buffer/common/mailbox_holder.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/renderers/gpu_video_accelerator_factories.h"
@@ -20,9 +21,6 @@
 #include "third_party/webrtc/system_wrappers/interface/ref_count.h"
 #include "third_party/webrtc/video_frame.h"
 
-static void ReleaseFrame(scoped_refptr<media::VideoFrame> frame) {
-}
-
 namespace content {
 
 const int32 RTCVideoDecoder::ID_LAST = 0x3FFFFFFF;
@@ -400,13 +398,9 @@
   DCHECK(inserted);
 
   // Create a WebRTC video frame.
-  webrtc::VideoFrame decoded_image(frame.get(),
-                                   picture.visible_rect().width(),
-                                   picture.visible_rect().height(),
-                                   timestamp,
-                                   0,
-                                   webrtc::kVideoRotation_0,
-                                   rtc::Bind(&ReleaseFrame, frame));
+  webrtc::VideoFrame decoded_image(
+      new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(frame), timestamp, 0,
+      webrtc::kVideoRotation_0);
 
   // Invoke decode callback. WebRTC expects no callback after Reset or Release.
   {
diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc
index 007b0bc6d..e5791356 100644
--- a/content/renderer/media/video_capture_impl.cc
+++ b/content/renderer/media/video_capture_impl.cc
@@ -22,6 +22,20 @@
 
 namespace content {
 
+namespace {
+
+// This is called on an unknown thread when the VideoFrame destructor executes.
+// As of this writing, this callback mechanism is the only interface in
+// VideoFrame to provide the final value for |release_sync_point|.
+// VideoCaptureImpl::DidFinishConsumingFrame() will read the value saved here,
+// and pass it back to the IO thread to pass back to the host via the
+// BufferReady IPC.
+void SaveReleaseSyncPoint(uint32* storage, uint32 release_sync_point) {
+  *storage = release_sync_point;
+}
+
+}  // namespace
+
 class VideoCaptureImpl::ClientBuffer
     : public base::RefCountedThreadSafe<ClientBuffer> {
  public:
@@ -220,7 +234,7 @@
   DCHECK(io_task_runner_->BelongsToCurrentThread());
 
   if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) {
-    Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0));
+    Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0, -1.0));
     return;
   }
 
@@ -249,12 +263,14 @@
           0,
           timestamp - first_frame_timestamp_);
   frame->AddDestructionObserver(
-      media::BindToCurrentLoop(
-          base::Bind(&VideoCaptureImpl::OnClientBufferFinished,
-                     weak_factory_.GetWeakPtr(),
-                     buffer_id,
-                     buffer,
-                     0)));
+      base::Bind(&VideoCaptureImpl::DidFinishConsumingFrame,
+                 frame->metadata(),
+                 nullptr,
+                 media::BindToCurrentLoop(
+                     base::Bind(&VideoCaptureImpl::OnClientBufferFinished,
+                                weak_factory_.GetWeakPtr(),
+                                buffer_id,
+                                buffer))));
   frame->metadata()->MergeInternalValuesFrom(metadata);
 
   for (const auto& client : clients_)
@@ -270,21 +286,31 @@
   DCHECK(io_task_runner_->BelongsToCurrentThread());
 
   if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) {
-    Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0));
+    Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0, -1.0));
     return;
   }
 
   if (first_frame_timestamp_.is_null())
     first_frame_timestamp_ = timestamp;
 
+  uint32* const release_sync_point_storage =
+      new uint32(0);  // Deleted in DidFinishConsumingFrame().
   scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapNativeTexture(
       mailbox_holder,
-      media::BindToCurrentLoop(base::Bind(
-          &VideoCaptureImpl::OnClientBufferFinished, weak_factory_.GetWeakPtr(),
-          buffer_id, scoped_refptr<ClientBuffer>())),
+      base::Bind(&SaveReleaseSyncPoint, release_sync_point_storage),
       packed_frame_size, gfx::Rect(packed_frame_size), packed_frame_size,
       timestamp - first_frame_timestamp_, false /* allow_overlay */,
       true /* has_alpha */);
+  frame->AddDestructionObserver(
+      base::Bind(&VideoCaptureImpl::DidFinishConsumingFrame,
+                 frame->metadata(),
+                 release_sync_point_storage,
+                 media::BindToCurrentLoop(base::Bind(
+                     &VideoCaptureImpl::OnClientBufferFinished,
+                     weak_factory_.GetWeakPtr(),
+                     buffer_id,
+                     scoped_refptr<ClientBuffer>()))));
+
   frame->metadata()->MergeInternalValuesFrom(metadata);
 
   for (const auto& client : clients_)
@@ -294,10 +320,13 @@
 void VideoCaptureImpl::OnClientBufferFinished(
     int buffer_id,
     const scoped_refptr<ClientBuffer>& /* ignored_buffer */,
-    uint32 release_sync_point) {
+    uint32 release_sync_point,
+    double consumer_resource_utilization) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
-  Send(new VideoCaptureHostMsg_BufferReady(
-      device_id_, buffer_id, release_sync_point));
+  Send(new VideoCaptureHostMsg_BufferReady(device_id_,
+                                           buffer_id,
+                                           release_sync_point,
+                                           consumer_resource_utilization));
 }
 
 void VideoCaptureImpl::OnStateChanged(VideoCaptureState state) {
@@ -429,4 +458,27 @@
   return found;
 }
 
+// static
+void VideoCaptureImpl::DidFinishConsumingFrame(
+    const media::VideoFrameMetadata* metadata,
+    uint32* release_sync_point_storage,
+    const base::Callback<void(uint32, double)>& callback_to_io_thread) {
+  // Note: This function may be called on any thread by the VideoFrame
+  // destructor.  |metadata| is still valid for read-access at this point.
+
+  uint32 release_sync_point = 0u;
+  if (release_sync_point_storage) {
+    release_sync_point = *release_sync_point_storage;
+    delete release_sync_point_storage;
+  }
+
+  double consumer_resource_utilization = -1.0;
+  if (!metadata->GetDouble(media::VideoFrameMetadata::RESOURCE_UTILIZATION,
+                           &consumer_resource_utilization)) {
+    consumer_resource_utilization = -1.0;
+  }
+
+  callback_to_io_thread.Run(release_sync_point, consumer_resource_utilization);
+}
+
 }  // namespace content
diff --git a/content/renderer/media/video_capture_impl.h b/content/renderer/media/video_capture_impl.h
index 51933a8..39b3af9d 100644
--- a/content/renderer/media/video_capture_impl.h
+++ b/content/renderer/media/video_capture_impl.h
@@ -129,7 +129,8 @@
   // buffer.
   void OnClientBufferFinished(int buffer_id,
                               const scoped_refptr<ClientBuffer>& buffer,
-                              uint32 release_sync_point);
+                              uint32 release_sync_point,
+                              double consumer_resource_utilization);
 
   void StopDevice();
   void RestartCapture();
@@ -140,6 +141,15 @@
   // Helpers.
   bool RemoveClient(int client_id, ClientInfoMap* clients);
 
+  // Called (by an unknown thread) when all consumers are done with a VideoFrame
+  // and its ref-count has gone to zero.  This helper function grabs the
+  // RESOURCE_UTILIZATION value from the |metadata| and then runs the given
+  // callback, to trampoline back to the IO thread with the values.
+  static void DidFinishConsumingFrame(
+    const media::VideoFrameMetadata* metadata,
+    uint32* release_sync_point_storage,  // Takes ownership.
+    const base::Callback<void(uint32, double)>& callback_to_io_thread);
+
   const scoped_refptr<VideoCaptureMessageFilter> message_filter_;
   int device_id_;
   const int session_id_;
diff --git a/content/renderer/media/video_capture_impl_unittest.cc b/content/renderer/media/video_capture_impl_unittest.cc
index 282cc3e3..2c1d875 100644
--- a/content/renderer/media/video_capture_impl_unittest.cc
+++ b/content/renderer/media/video_capture_impl_unittest.cc
@@ -80,7 +80,8 @@
 
     void DeviceReceiveEmptyBuffer(int device_id,
                                   int buffer_id,
-                                  uint32 sync_point) {}
+                                  uint32 sync_point,
+                                  double consumer_resource_utilization) {}
 
     void DeviceGetSupportedFormats(int device_id,
                                    media::VideoCaptureSessionId session_id) {
diff --git a/content/renderer/media/video_capture_message_filter.cc b/content/renderer/media/video_capture_message_filter.cc
index 80fd570..076f151 100644
--- a/content/renderer/media/video_capture_message_filter.cc
+++ b/content/renderer/media/video_capture_message_filter.cc
@@ -113,7 +113,7 @@
     // Send the buffer back to Host in case it's waiting for all buffers
     // to be returned.
     base::SharedMemory::CloseHandle(handle);
-    Send(new VideoCaptureHostMsg_BufferReady(device_id, buffer_id, 0));
+    Send(new VideoCaptureHostMsg_BufferReady(device_id, buffer_id, 0, -1.0));
     return;
   }
 
@@ -130,7 +130,7 @@
     // Send the buffer back to Host in case it's waiting for all buffers
     // to be returned.
     Send(new VideoCaptureHostMsg_BufferReady(
-        params.device_id, params.buffer_id, 0));
+        params.device_id, params.buffer_id, 0, -1.0));
     return;
   }
 
@@ -152,7 +152,7 @@
     // Send the buffer back to Host in case it's waiting for all buffers
     // to be returned.
     Send(new VideoCaptureHostMsg_BufferReady(
-        params.device_id, params.buffer_id, 0));
+        params.device_id, params.buffer_id, 0, -1.0));
     return;
   }
 
diff --git a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc
index 6689ddf81..cb1a832 100644
--- a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc
+++ b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/memory/aligned_memory.h"
 #include "base/trace_event/trace_event.h"
+#include "content/renderer/media/webrtc/webrtc_video_frame_adapter.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_frame_pool.h"
 #include "third_party/libjingle/source/talk/media/base/videoframefactory.h"
@@ -24,55 +25,6 @@
 void ReleaseOriginalFrame(const scoped_refptr<media::VideoFrame>& frame) {
 }
 
-int WebRtcToMediaPlaneType(webrtc::PlaneType type) {
-  switch (type) {
-    case webrtc::kYPlane:
-      return media::VideoFrame::kYPlane;
-    case webrtc::kUPlane:
-      return media::VideoFrame::kUPlane;
-    case webrtc::kVPlane:
-      return media::VideoFrame::kVPlane;
-    default:
-      NOTREACHED();
-      return media::VideoFrame::kMaxPlanes;
-  }
-}
-
-// Thin adapter from media::VideoFrame to webrtc::VideoFrameBuffer. This
-// implementation is read-only and will return null if trying to get a
-// non-const pointer to the pixel data. This object will be accessed from
-// different threads, but that's safe since it's read-only.
-class VideoFrameWrapper : public webrtc::VideoFrameBuffer {
- public:
-  VideoFrameWrapper(const scoped_refptr<media::VideoFrame>& frame)
-      : frame_(frame) {}
-
- private:
-  int width() const override { return frame_->visible_rect().width(); }
-
-  int height() const override { return frame_->visible_rect().height(); }
-
-  const uint8_t* data(webrtc::PlaneType type) const override {
-    return frame_->visible_data(WebRtcToMediaPlaneType(type));
-  }
-
-  uint8_t* data(webrtc::PlaneType type) override {
-    NOTREACHED();
-    return nullptr;
-  }
-
-  int stride(webrtc::PlaneType type) const override {
-    return frame_->stride(WebRtcToMediaPlaneType(type));
-  }
-
-  void* native_handle() const override { return nullptr; }
-
-  ~VideoFrameWrapper() override {}
-  friend class rtc::RefCountedObject<VideoFrameWrapper>;
-
-  scoped_refptr<media::VideoFrame> frame_;
-};
-
 }  // anonymous namespace
 
 // A cricket::VideoFrameFactory for media::VideoFrame. The purpose of this
@@ -138,7 +90,7 @@
     // If no scaling is needed, return a wrapped version of |frame_| directly.
     if (video_frame->natural_size() == video_frame->visible_rect().size()) {
       return new cricket::WebRtcVideoFrame(
-          new rtc::RefCountedObject<VideoFrameWrapper>(video_frame),
+          new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(video_frame),
           captured_frame_.elapsed_time, timestamp_ns);
     }
 
@@ -163,7 +115,7 @@
                       scaled_frame->stride(media::VideoFrame::kVPlane),
                       output_width, output_height, libyuv::kFilterBilinear);
     return new cricket::WebRtcVideoFrame(
-        new rtc::RefCountedObject<VideoFrameWrapper>(scaled_frame),
+        new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(scaled_frame),
         captured_frame_.elapsed_time, timestamp_ns);
   }
 
diff --git a/content/renderer/media/webrtc/webrtc_video_frame_adapter.cc b/content/renderer/media/webrtc/webrtc_video_frame_adapter.cc
new file mode 100644
index 0000000..f265e625
--- /dev/null
+++ b/content/renderer/media/webrtc/webrtc_video_frame_adapter.cc
@@ -0,0 +1,67 @@
+// 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 "content/renderer/media/webrtc/webrtc_video_frame_adapter.h"
+
+#include "base/logging.h"
+
+namespace content {
+namespace {
+int WebRtcToMediaPlaneType(webrtc::PlaneType type) {
+  switch (type) {
+    case webrtc::kYPlane:
+      return media::VideoFrame::kYPlane;
+    case webrtc::kUPlane:
+      return media::VideoFrame::kUPlane;
+    case webrtc::kVPlane:
+      return media::VideoFrame::kVPlane;
+    default:
+      NOTREACHED();
+      return media::VideoFrame::kMaxPlanes;
+  }
+}
+}  // anonymous namespace
+
+WebRtcVideoFrameAdapter::WebRtcVideoFrameAdapter(
+    const scoped_refptr<media::VideoFrame>& frame)
+    : frame_(frame) {
+}
+
+WebRtcVideoFrameAdapter::~WebRtcVideoFrameAdapter() {
+}
+
+int WebRtcVideoFrameAdapter::width() const {
+  return frame_->visible_rect().width();
+}
+
+int WebRtcVideoFrameAdapter::height() const {
+  return frame_->visible_rect().height();
+}
+
+const uint8_t* WebRtcVideoFrameAdapter::data(webrtc::PlaneType type) const {
+  return frame_->visible_data(WebRtcToMediaPlaneType(type));
+}
+
+uint8_t* WebRtcVideoFrameAdapter::data(webrtc::PlaneType type) {
+  NOTREACHED();
+  return nullptr;
+}
+
+int WebRtcVideoFrameAdapter::stride(webrtc::PlaneType type) const {
+  return frame_->stride(WebRtcToMediaPlaneType(type));
+}
+
+void* WebRtcVideoFrameAdapter::native_handle() const {
+  return frame_->storage_type() == media::VideoFrame::STORAGE_TEXTURE
+             ? frame_.get()
+             : nullptr;
+}
+
+rtc::scoped_refptr<webrtc::VideoFrameBuffer>
+WebRtcVideoFrameAdapter::NativeToI420Buffer() {
+  NOTREACHED();
+  return nullptr;
+}
+
+}  // namespace content
diff --git a/content/renderer/media/webrtc/webrtc_video_frame_adapter.h b/content/renderer/media/webrtc/webrtc_video_frame_adapter.h
new file mode 100644
index 0000000..2534e24
--- /dev/null
+++ b/content/renderer/media/webrtc/webrtc_video_frame_adapter.h
@@ -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.
+
+#ifndef CONTENT_RENDERER_MEDIA_WEBRTC_WEBRTC_VIDEO_FRAME_ADAPTER_H_
+#define CONTENT_RENDERER_MEDIA_WEBRTC_WEBRTC_VIDEO_FRAME_ADAPTER_H_
+
+#include "media/base/video_frame.h"
+#include "third_party/webrtc/common_video/interface/video_frame_buffer.h"
+
+namespace content {
+// Thin adapter from media::VideoFrame to webrtc::VideoFrameBuffer. This
+// implementation is read-only and will return null if trying to get a
+// non-const pointer to the pixel data. This object will be accessed from
+// different threads, but that's safe since it's read-only.
+class WebRtcVideoFrameAdapter : public webrtc::VideoFrameBuffer {
+ public:
+  explicit WebRtcVideoFrameAdapter(
+      const scoped_refptr<media::VideoFrame>& frame);
+
+ private:
+  int width() const override;
+  int height() const override;
+
+  const uint8_t* data(webrtc::PlaneType type) const override;
+
+  uint8_t* data(webrtc::PlaneType type) override;
+
+  int stride(webrtc::PlaneType type) const override;
+
+  void* native_handle() const override;
+
+  rtc::scoped_refptr<VideoFrameBuffer> NativeToI420Buffer() override;
+
+  friend class rtc::RefCountedObject<WebRtcVideoFrameAdapter>;
+
+ protected:
+  ~WebRtcVideoFrameAdapter() override;
+
+  scoped_refptr<media::VideoFrame> frame_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_MEDIA_WEBRTC_WEBRTC_VIDEO_FRAME_ADAPTER_H_
diff --git a/content/renderer/pepper/pepper_proxy_channel_delegate_impl.cc b/content/renderer/pepper/pepper_proxy_channel_delegate_impl.cc
index aa0cac40..7a5a0c1 100644
--- a/content/renderer/pepper/pepper_proxy_channel_delegate_impl.cc
+++ b/content/renderer/pepper/pepper_proxy_channel_delegate_impl.cc
@@ -7,6 +7,10 @@
 #include "content/child/child_process.h"
 #include "content/common/sandbox_util.h"
 
+#if defined(OS_WIN) || defined(OS_MACOSX)
+#include "content/public/common/sandbox_init.h"
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
+
 namespace content {
 
 PepperProxyChannelDelegateImpl::~PepperProxyChannelDelegateImpl() {}
@@ -35,15 +39,16 @@
 PepperProxyChannelDelegateImpl::ShareSharedMemoryHandleWithRemote(
     const base::SharedMemoryHandle& handle,
     base::ProcessId remote_pid) {
-  base::PlatformFile local_platform_file =
-#if defined(OS_POSIX)
-      handle.fd;
-#elif defined(OS_WIN)
-      handle;
+#if defined(OS_WIN) || defined(OS_MACOSX)
+  base::SharedMemoryHandle duped_handle;
+  bool success =
+      BrokerDuplicateSharedMemoryHandle(handle, remote_pid, &duped_handle);
+  if (success)
+    return duped_handle;
+  return base::SharedMemory::NULLHandle();
 #else
-#error Not implemented.
-#endif
-  return ShareHandleWithRemote(local_platform_file, remote_pid, false);
+  return base::SharedMemory::DuplicateHandle(handle);
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
 }
 
 }  // namespace content
diff --git a/content/renderer/pepper/pepper_websocket_host.cc b/content/renderer/pepper/pepper_websocket_host.cc
index b5f1e959..ad016f3 100644
--- a/content/renderer/pepper/pepper_websocket_host.cc
+++ b/content/renderer/pepper/pepper_websocket_host.cc
@@ -213,8 +213,10 @@
     return PP_ERROR_BADARGUMENT;
   if (gurl.has_ref())
     return PP_ERROR_BADARGUMENT;
-  if (!net::IsPortAllowedByDefault(gurl.EffectiveIntPort()))
+  if (!net::IsPortAllowedForScheme(gurl.EffectiveIntPort(), gurl.scheme(),
+                                   net::PORT_OVERRIDES_IGNORED)) {
     return PP_ERROR_BADARGUMENT;
+  }
   WebURL web_url(gurl);
 
   // Validate protocols.
diff --git a/content/renderer/pepper/renderer_ppapi_host_impl.cc b/content/renderer/pepper/renderer_ppapi_host_impl.cc
index 2aa2c34..ff8e819 100644
--- a/content/renderer/pepper/renderer_ppapi_host_impl.cc
+++ b/content/renderer/pepper/renderer_ppapi_host_impl.cc
@@ -234,15 +234,11 @@
 base::SharedMemoryHandle
 RendererPpapiHostImpl::ShareSharedMemoryHandleWithRemote(
     const base::SharedMemoryHandle& handle) {
-  base::PlatformFile local_platform_file =
-#if defined(OS_POSIX)
-      handle.fd;
-#elif defined(OS_WIN)
-      handle;
-#else
-#error Not implemented.
-#endif
-  return ShareHandleWithRemote(local_platform_file, false);
+  if (!dispatcher_) {
+    DCHECK(is_running_in_process_);
+    return base::SharedMemory::DuplicateHandle(handle);
+  }
+  return dispatcher_->ShareSharedMemoryHandleWithRemote(handle);
 }
 
 bool RendererPpapiHostImpl::IsRunningInProcess() const {
diff --git a/content/renderer/pepper/video_decoder_shim.cc b/content/renderer/pepper/video_decoder_shim.cc
index cfc23d3..b7bd4ce 100644
--- a/content/renderer/pepper/video_decoder_shim.cc
+++ b/content/renderer/pepper/video_decoder_shim.cc
@@ -37,7 +37,7 @@
 static const uint32_t kGrInvalidateState =
     kRenderTarget_GrGLBackendState | kTextureBinding_GrGLBackendState |
     kView_GrGLBackendState | kVertex_GrGLBackendState |
-    kProgram_GrGLBackendState;
+    kProgram_GrGLBackendState | kPixelStore_GrGLBackendState;
 
 // YUV->RGB converter class using a shader and FBO.
 class VideoDecoderShim::YUVConverter {
@@ -52,7 +52,6 @@
   GLuint CompileShader(const char* name, GLuint type, const char* code);
   GLuint CreateProgram(const char* name, GLuint vshader, GLuint fshader);
   GLuint CreateTexture();
-  void SetTexcoordClamp(uint32_t stride, uint32_t width);
 
   scoped_refptr<cc_blink::ContextProviderWebContext> context_provider_;
   gpu::gles2::GLES2Interface* gl_;
@@ -75,10 +74,7 @@
   GLuint uv_width_;
   GLuint uv_height_;
   uint32_t uv_height_divisor_;
-
-  GLfloat clamp_value_;
-  GLuint clamp_width_;
-  GLint clamp_width_loc_;
+  uint32_t uv_width_divisor_;
 
   GLint yuv_matrix_loc_;
   GLint yuv_adjust_loc_;
@@ -105,9 +101,7 @@
       uv_width_(2),
       uv_height_(2),
       uv_height_divisor_(1),
-      clamp_value_(1.f),
-      clamp_width_(0),
-      clamp_width_loc_(0),
+      uv_width_divisor_(1),
       yuv_matrix_loc_(0),
       yuv_adjust_loc_(0) {
   DCHECK(gl_);
@@ -223,12 +217,10 @@
       "precision mediump float;\n"
       "attribute vec2 position;\n"
       "varying vec2 texcoord;\n"
-      "uniform float clamp_width;\n"
       "void main()\n"
       "{\n"
       "    gl_Position = vec4( position.xy, 0, 1 );\n"
-      "    vec2 tmp = position*0.5+0.5;\n"
-      "    texcoord = vec2(min(tmp.x, clamp_width), tmp.y);\n"
+      "    texcoord = position*0.5+0.5;\n"
       "}";
 
   const char* frag_shader =
@@ -292,10 +284,6 @@
   DCHECK(uniform_location != -1);
   gl_->Uniform1i(uniform_location, 3);
 
-  clamp_width_loc_ = gl_->GetUniformLocation(program, "clamp_width");
-  DCHECK(clamp_width_loc_ != -1);
-  gl_->Uniform1f(clamp_width_loc_, clamp_value_);
-
   gl_->UseProgram(0);
 
   yuv_matrix_loc_ = gl_->GetUniformLocation(program, "yuv_matrix");
@@ -351,20 +339,6 @@
   return (program_ != 0);
 }
 
-void VideoDecoderShim::YUVConverter::SetTexcoordClamp(uint32_t stride,
-                                                      uint32_t width) {
-  clamp_width_ = width;
-  if (width != stride) {
-    // Clamp texcoord width to avoid sampling padding pixels.
-    clamp_value_ = static_cast<float>(width) / static_cast<float>(stride);
-    // Further clamp to 1/2 pixel inside to avoid bilinear sampling errors.
-    clamp_value_ -= (1.f / (2.f * static_cast<float>(stride)));
-  } else {
-    // No clamping necessary if width and stride are equal.
-    clamp_value_ = 1.f;
-  }
-}
-
 void VideoDecoderShim::YUVConverter::Convert(
     const scoped_refptr<media::VideoFrame>& frame,
     GLuint tex_out) {
@@ -405,6 +379,7 @@
       case media::VideoFrame::YV12A:
       case media::VideoFrame::I420:
         uv_height_divisor_ = 2;
+        uv_width_divisor_ = 2;
         yuv_adjust = yuv_adjust_constrained;
         int result;
         if (frame->metadata()->GetInteger(
@@ -420,7 +395,13 @@
         }
         break;
       case media::VideoFrame::YV16:  // 422
+        uv_width_divisor_ = 2;
+        uv_height_divisor_ = 1;
+        yuv_matrix = yuv_to_rgb_rec601;
+        yuv_adjust = yuv_adjust_constrained;
+        break;
       case media::VideoFrame::YV24:  // 444
+        uv_width_divisor_ = 1;
         uv_height_divisor_ = 1;
         yuv_matrix = yuv_to_rgb_rec601;
         yuv_adjust = yuv_adjust_constrained;
@@ -438,8 +419,6 @@
 
   gl_->PushGroupMarkerEXT(0, "YUVConverterContext");
 
-  bool set_clamp = false;
-
   uint32_t ywidth = frame->coded_size().width();
   uint32_t yheight = frame->coded_size().height();
 
@@ -450,39 +429,24 @@
   uint32_t uvstride = frame->stride(media::VideoFrame::kUPlane);
 
   // The following code assumes that extended GLES 2.0 state like
-  // UNPACK_SKIP* and UNPACK_ROW_LENGTH (if available) are set to defaults.
+  // UNPACK_SKIP* (if available) are set to defaults.
   gl_->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
-  if (ystride != y_width_ || yheight != y_height_) {
-    // Choose width based on the stride.  Clamp texcoords below.
-    y_width_ = ystride;
+  if (ywidth != y_width_ || yheight != y_height_) {
+    y_width_ = ywidth;
     y_height_ = yheight;
 
-    uv_width_ = uvstride;
+    uv_width_ = y_width_ / uv_width_divisor_;
     uv_height_ = y_height_ / uv_height_divisor_;
 
-    SetTexcoordClamp(ystride, ywidth);
-    set_clamp = true;
-
     // Re-create to resize the textures and upload data.
+    gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, ystride);
     gl_->ActiveTexture(GL_TEXTURE0);
     gl_->BindTexture(GL_TEXTURE_2D, y_texture_);
     gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, y_width_, y_height_, 0,
                     format_, GL_UNSIGNED_BYTE,
                     frame->data(media::VideoFrame::kYPlane));
 
-    gl_->ActiveTexture(GL_TEXTURE1);
-    gl_->BindTexture(GL_TEXTURE_2D, u_texture_);
-    gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, uv_width_, uv_height_,
-                    0, format_, GL_UNSIGNED_BYTE,
-                    frame->data(media::VideoFrame::kUPlane));
-
-    gl_->ActiveTexture(GL_TEXTURE2);
-    gl_->BindTexture(GL_TEXTURE_2D, v_texture_);
-    gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, uv_width_, uv_height_,
-                    0, format_, GL_UNSIGNED_BYTE,
-                    frame->data(media::VideoFrame::kVPlane));
-
     if (video_format_ == media::VideoFrame::YV12A) {
       DCHECK_EQ(frame->stride(media::VideoFrame::kYPlane),
                 frame->stride(media::VideoFrame::kAPlane));
@@ -494,38 +458,35 @@
     } else {
       // if there is no alpha channel, then create a 2x2 texture with full
       // alpha.
+      gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
       const uint8_t alpha[4] = {0xff, 0xff, 0xff, 0xff};
       gl_->ActiveTexture(GL_TEXTURE3);
       gl_->BindTexture(GL_TEXTURE_2D, a_texture_);
       gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, 2, 2, 0, format_,
                       GL_UNSIGNED_BYTE, alpha);
     }
-  } else {
-    // Width may have changed even though stride remained the same.
-    if (clamp_width_ != ywidth) {
-      SetTexcoordClamp(ystride, ywidth);
-      set_clamp = true;
-    }
 
+    gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, uvstride);
+    gl_->ActiveTexture(GL_TEXTURE1);
+    gl_->BindTexture(GL_TEXTURE_2D, u_texture_);
+    gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, uv_width_, uv_height_,
+                    0, format_, GL_UNSIGNED_BYTE,
+                    frame->data(media::VideoFrame::kUPlane));
+
+    gl_->ActiveTexture(GL_TEXTURE2);
+    gl_->BindTexture(GL_TEXTURE_2D, v_texture_);
+    gl_->TexImage2D(GL_TEXTURE_2D, 0, internal_format_, uv_width_, uv_height_,
+                    0, format_, GL_UNSIGNED_BYTE,
+                    frame->data(media::VideoFrame::kVPlane));
+  } else {
     // Bind textures and upload texture data
+    gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, ystride);
     gl_->ActiveTexture(GL_TEXTURE0);
     gl_->BindTexture(GL_TEXTURE_2D, y_texture_);
     gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, y_width_, y_height_, format_,
                        GL_UNSIGNED_BYTE,
                        frame->data(media::VideoFrame::kYPlane));
 
-    gl_->ActiveTexture(GL_TEXTURE1);
-    gl_->BindTexture(GL_TEXTURE_2D, u_texture_);
-    gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, uv_width_, uv_height_, format_,
-                       GL_UNSIGNED_BYTE,
-                       frame->data(media::VideoFrame::kUPlane));
-
-    gl_->ActiveTexture(GL_TEXTURE2);
-    gl_->BindTexture(GL_TEXTURE_2D, v_texture_);
-    gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, uv_width_, uv_height_, format_,
-                       GL_UNSIGNED_BYTE,
-                       frame->data(media::VideoFrame::kVPlane));
-
     if (video_format_ == media::VideoFrame::YV12A) {
       DCHECK_EQ(frame->stride(media::VideoFrame::kYPlane),
                 frame->stride(media::VideoFrame::kAPlane));
@@ -538,6 +499,19 @@
       gl_->ActiveTexture(GL_TEXTURE3);
       gl_->BindTexture(GL_TEXTURE_2D, a_texture_);
     }
+
+    gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, uvstride);
+    gl_->ActiveTexture(GL_TEXTURE1);
+    gl_->BindTexture(GL_TEXTURE_2D, u_texture_);
+    gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, uv_width_, uv_height_, format_,
+                       GL_UNSIGNED_BYTE,
+                       frame->data(media::VideoFrame::kUPlane));
+
+    gl_->ActiveTexture(GL_TEXTURE2);
+    gl_->BindTexture(GL_TEXTURE_2D, v_texture_);
+    gl_->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, uv_width_, uv_height_, format_,
+                       GL_UNSIGNED_BYTE,
+                       frame->data(media::VideoFrame::kVPlane));
   }
 
   gl_->BindFramebuffer(GL_FRAMEBUFFER, frame_buffer_);
@@ -557,10 +531,6 @@
 
   gl_->UseProgram(program_);
 
-  if (set_clamp) {
-    gl_->Uniform1f(clamp_width_loc_, clamp_value_);
-  }
-
   if (yuv_matrix) {
     gl_->UniformMatrix3fv(yuv_matrix_loc_, 1, 0, yuv_matrix);
     gl_->Uniform3fv(yuv_adjust_loc_, 1, yuv_adjust);
@@ -596,6 +566,7 @@
 
   gl_->ActiveTexture(GL_TEXTURE0);
   gl_->BindTexture(GL_TEXTURE_2D, 0);
+  gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
 
   gl_->PopGroupMarkerEXT();
 
@@ -662,7 +633,7 @@
   void Stop();
 
  private:
-  void OnPipelineStatus(media::PipelineStatus status);
+  void OnInitDone(bool success);
   void DoDecode();
   void OnDecodeComplete(media::VideoDecoder::Status status);
   void OnOutputComplete(const scoped_refptr<media::VideoFrame>& frame);
@@ -721,7 +692,7 @@
 
   decoder_->Initialize(
       config, true /* low_delay */,
-      base::Bind(&VideoDecoderShim::DecoderImpl::OnPipelineStatus,
+      base::Bind(&VideoDecoderShim::DecoderImpl::OnInitDone,
                  weak_ptr_factory_.GetWeakPtr()),
       base::Bind(&VideoDecoderShim::DecoderImpl::OnOutputComplete,
                  weak_ptr_factory_.GetWeakPtr()));
@@ -760,20 +731,8 @@
   // This instance is deleted once we exit this scope.
 }
 
-void VideoDecoderShim::DecoderImpl::OnPipelineStatus(
-    media::PipelineStatus status) {
-  int32_t result;
-  switch (status) {
-    case media::PIPELINE_OK:
-      result = PP_OK;
-      break;
-    case media::DECODER_ERROR_NOT_SUPPORTED:
-      result = PP_ERROR_NOTSUPPORTED;
-      break;
-    default:
-      result = PP_ERROR_FAILED;
-      break;
-  }
+void VideoDecoderShim::DecoderImpl::OnInitDone(bool success) {
+  int32_t result = success ? PP_OK : PP_ERROR_NOTSUPPORTED;
 
   // Calculate how many textures the shim should create.
   uint32_t shim_texture_pool_size = media::limits::kMaxVideoFrames + 1;
@@ -829,11 +788,10 @@
   DCHECK(awaiting_decoder_);
 
   scoped_ptr<PendingFrame> pending_frame;
-  if (!frame->end_of_stream()) {
+  if (!frame->IsEndOfStream())
     pending_frame.reset(new PendingFrame(decode_id_, frame));
-  } else {
+  else
     pending_frame.reset(new PendingFrame(decode_id_));
-  }
 
   main_task_runner_->PostTask(
       FROM_HERE, base::Bind(&VideoDecoderShim::OnOutputComplete, shim_,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index f67a40a..aba81ee 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -537,11 +537,6 @@
     const FrameReplicationState& replicated_state,
     CompositorDependencies* compositor_deps,
     const FrameMsg_NewFrame_WidgetParams& widget_params) {
-  // TODO(nasko): For now, this message is only sent for subframes, as the
-  // top level frame is created when the RenderView is created through the
-  // ViewMsg_New IPC.
-  CHECK_NE(MSG_ROUTING_NONE, parent_routing_id);
-
   blink::WebLocalFrame* web_frame;
   RenderFrameImpl* render_frame;
   if (proxy_routing_id == MSG_ROUTING_NONE) {
@@ -578,6 +573,7 @@
         replicated_state.sandbox_flags);
   }
   render_frame->SetWebFrame(web_frame);
+  CHECK_IMPLIES(parent_routing_id == MSG_ROUTING_NONE, !web_frame->parent());
 
   if (widget_params.routing_id != MSG_ROUTING_NONE) {
     CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -700,7 +696,9 @@
     }
 
     // Ensure the RenderView doesn't point to this object, once it is destroyed.
-    CHECK_EQ(render_view_->main_render_frame_, this);
+    // TODO(nasko): Add a check that the |main_render_frame_| of |render_view_|
+    // is |this|, once the object is no longer leaked.
+    // See https://crbug.com/464764.
     render_view_->main_render_frame_ = nullptr;
   }
 
@@ -1152,7 +1150,8 @@
     // TODO(creis): Should we be stopping all frames here and using
     // StopAltErrorPageFetcher with RenderView::OnStop, or just stopping this
     // frame?
-    OnStop();
+    if (!is_site_per_process)
+      OnStop();
 
     // Transfer settings such as initial drawing parameters to the remote frame,
     // if one is created, that will replace this frame.
@@ -1163,7 +1162,7 @@
     // run a second time, thanks to a check in FrameLoader::stopLoading.
     // TODO(creis): Need to add a better way to do this that avoids running the
     // beforeunload handler. For now, we just run it a second time silently.
-    if (!is_site_per_process || is_main_frame)
+    if (!is_site_per_process)
       NavigateToSwappedOutURL();
 
     // Let WebKit know that this view is hidden so it can drop resources and
@@ -1182,19 +1181,16 @@
 
   Send(new FrameHostMsg_SwapOut_ACK(routing_id_));
 
+  RenderViewImpl* render_view = render_view_.get();
+
   // Now that all of the cleanup is complete and the browser side is notified,
   // start using the RenderFrameProxy, if one is created.
   if (proxy) {
-    if (!is_main_frame) {
+    if (is_site_per_process || !is_main_frame) {
       frame_->swap(proxy->web_frame());
 
       if (is_loading)
         proxy->OnDidStartLoading();
-
-      if (is_site_per_process) {
-        // TODO(nasko): delete the frame here, since we've replaced it with a
-        // proxy.
-      }
     }
   }
 
@@ -1206,12 +1202,24 @@
   // in proxy->web_frame(), the RemoteFrame will not exist for main frames.
   // When we do an unconditional swap for all frames, we can remove
   // !is_main_frame below.
-  if (is_site_per_process && proxy && !is_main_frame)
+  if (is_site_per_process && proxy)
     proxy->SetReplicatedState(replicated_frame_state);
 
   // Safe to exit if no one else is using the process.
-  if (is_main_frame)
-    render_view_->WasSwappedOut();
+  // TODO(nasko): Remove the dependency on RenderViewImpl here and ref count
+  // the process based on the lifetime of this RenderFrameImpl object.
+  if (is_main_frame) {
+    render_view->WasSwappedOut();
+
+    // TODO(nasko): Currently, this RenderFrame is leaked due to
+    // https://crbug.com/464764, therefore the destructor won't be invoked to
+    // destroy this object. Until this bug is fixed, set the main frame of the
+    // RenderView to null here.
+    if (is_site_per_process) {
+      CHECK_EQ(render_view_->main_render_frame_, this);
+      render_view->main_render_frame_ = nullptr;
+    }
+  }
 }
 
 void RenderFrameImpl::OnContextMenuClosed(
@@ -2593,10 +2601,13 @@
     proxy_routing_id_ = MSG_ROUTING_NONE;
 
     // If this is the main frame going from a remote frame to a local frame,
-    // it needs to set RenderViewImpl's pointer for the main frame to itself.
+    // it needs to set RenderViewImpl's pointer for the main frame to itself
+    // and ensure RenderWidget is no longer in swapped out mode.
     if (!is_subframe_) {
       CHECK(!render_view_->main_render_frame_);
       render_view_->main_render_frame_ = this;
+      if (render_view_->is_swapped_out())
+        render_view_->SetSwappedOut(false);
     }
   }
 
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc
index 9c0e3b20..3ca5975e 100644
--- a/content/renderer/render_frame_impl_browsertest.cc
+++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
+#include "base/debug/leak_annotations.h"
 #include "content/common/frame_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/common/content_switches.h"
@@ -61,6 +62,15 @@
     EXPECT_TRUE(frame_->is_subframe_);
   }
 
+  void TearDown() override {
+#if defined(LEAK_SANITIZER)
+     // Do this before shutting down V8 in RenderViewTest::TearDown().
+     // http://crbug.com/328552
+     __lsan_do_leak_check();
+#endif
+     RenderViewTest::TearDown();
+  }
+
   // Loads the given HTML into the frame as a data: URL and blocks until
   // the navigation is committed.
   void LoadHTMLInFrame(const char* html) {
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index 66baaf7..fda7b784 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -6,12 +6,14 @@
 
 #include <map>
 
+#include "base/command_line.h"
 #include "base/lazy_instance.h"
 #include "content/child/webmessageportchannel_impl.h"
 #include "content/common/frame_messages.h"
 #include "content/common/frame_replication_state.h"
 #include "content/common/swapped_out_messages.h"
 #include "content/common/view_messages.h"
+#include "content/public/common/content_switches.h"
 #include "content/renderer/child_frame_compositing_helper.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_thread_impl.h"
@@ -65,7 +67,7 @@
   RenderViewImpl* render_view = NULL;
   blink::WebRemoteFrame* web_frame = NULL;
   if (parent_routing_id == MSG_ROUTING_NONE) {
-    // Create a top level frame.
+    // Create a top level WebRemoteFrame.
     render_view = RenderViewImpl::FromRoutingID(render_view_routing_id);
     web_frame =
         blink::WebRemoteFrame::create(replicated_state.scope, proxy.get());
@@ -292,12 +294,15 @@
   // When there is a RenderFrame for this proxy, tell it to disown its opener.
   // TODO(creis): Remove this when we only have WebRemoteFrames and make sure
   // they know they have an opener.
-  RenderFrameImpl* render_frame =
-      RenderFrameImpl::FromRoutingID(frame_routing_id_);
-  if (render_frame) {
-    if (render_frame->GetWebFrame()->opener())
-      render_frame->GetWebFrame()->setOpener(NULL);
-    return;
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    RenderFrameImpl* render_frame =
+        RenderFrameImpl::FromRoutingID(frame_routing_id_);
+    if (render_frame) {
+      if (render_frame->GetWebFrame()->opener())
+        render_frame->GetWebFrame()->setOpener(NULL);
+      return;
+    }
   }
 
   if (web_frame_->opener())
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index d64ad77..8fe83ef2 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -135,7 +135,6 @@
 #include "third_party/WebKit/public/web/WebImageCache.h"
 #include "third_party/WebKit/public/web/WebKit.h"
 #include "third_party/WebKit/public/web/WebNetworkStateNotifier.h"
-#include "third_party/WebKit/public/web/WebPopupMenu.h"
 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
 #include "third_party/WebKit/public/web/WebScriptController.h"
 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index b29bb7d4..ca040045 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -640,6 +640,12 @@
 // Ensure the RenderViewImpl sends an ACK to a SwapOut request, even if it is
 // already swapped out.  http://crbug.com/93427.
 TEST_F(RenderViewImplTest, SendSwapOutACK) {
+  // This test is invalid in --site-per-process mode, as swapped-out is no
+  // longer used.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    return;
+  }
   LoadHTML("<div>Page A</div>");
   int initial_page_id = view_page_id();
 
@@ -686,6 +692,13 @@
 // Ensure the RenderViewImpl reloads the previous page if a reload request
 // arrives while it is showing swappedout://.  http://crbug.com/143155.
 TEST_F(RenderViewImplTest, ReloadWhileSwappedOut) {
+  // This test is invalid in --site-per-process mode, as swapped-out is no
+  // longer used.
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess)) {
+    return;
+  }
+
   // Load page A.
   LoadHTML("<div>Page A</div>");
 
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 53ba225..1c4f8098 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -638,6 +638,7 @@
       top_controls_constraints_(TOP_CONTROLS_STATE_BOTH),
 #endif
       has_scrolled_focused_editable_node_into_rect_(false),
+      main_render_frame_(nullptr),
       speech_recognition_dispatcher_(NULL),
       mouse_lock_dispatcher_(NULL),
 #if defined(OS_ANDROID)
@@ -668,24 +669,58 @@
   // Ensure we start with a valid next_page_id_ from the browser.
   DCHECK_GE(next_page_id_, 0);
 
-  main_render_frame_ = RenderFrameImpl::Create(
-      this, params.main_frame_routing_id);
-  // The main frame WebLocalFrame object is closed by
-  // RenderFrameImpl::frameDetached().
-  WebLocalFrame* web_frame = WebLocalFrame::create(
-      blink::WebTreeScopeType::Document, main_render_frame_);
-  main_render_frame_->SetWebFrame(web_frame);
+  if (params.main_frame_routing_id != MSG_ROUTING_NONE) {
+    main_render_frame_ = RenderFrameImpl::Create(
+        this, params.main_frame_routing_id);
+    // The main frame WebLocalFrame object is closed by
+    // RenderFrameImpl::frameDetached().
+    WebLocalFrame* web_frame = WebLocalFrame::create(
+        blink::WebTreeScopeType::Document, main_render_frame_);
+    main_render_frame_->SetWebFrame(web_frame);
+  }
 
   compositor_deps_ = compositor_deps;
   webwidget_ = WebView::create(this);
   webwidget_mouse_lock_target_.reset(new WebWidgetLockTarget(webwidget_));
 
+  g_view_map.Get().insert(std::make_pair(webview(), this));
+  g_routing_id_view_map.Get().insert(std::make_pair(routing_id_, this));
+
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
 
   if (command_line.HasSwitch(switches::kStatsCollectionController))
     stats_collection_observer_.reset(new StatsCollectionObserver(this));
 
+  RenderFrameProxy* proxy = NULL;
+  if (params.proxy_routing_id != MSG_ROUTING_NONE) {
+    CHECK(params.swapped_out);
+    if (main_render_frame_) {
+      proxy = RenderFrameProxy::CreateProxyToReplaceFrame(
+          main_render_frame_, params.proxy_routing_id,
+          blink::WebTreeScopeType::Document);
+      main_render_frame_->set_render_frame_proxy(proxy);
+    } else {
+      proxy = RenderFrameProxy::CreateFrameProxy(
+          params.proxy_routing_id,
+          MSG_ROUTING_NONE,
+          routing_id_,
+          params.replicated_frame_state);
+    }
+  }
+
+  // In --site-per-process, just use the WebRemoteFrame as the main frame.
+  if (command_line.HasSwitch(switches::kSitePerProcess) && proxy) {
+    webview()->setMainFrame(proxy->web_frame());
+    // Initialize the WebRemoteFrame with information replicated from the
+    // browser process.
+    proxy->SetReplicatedState(params.replicated_frame_state);
+  } else {
+    webview()->setMainFrame(main_render_frame_->GetWebFrame());
+  }
+  if (main_render_frame_)
+    main_render_frame_->Initialize();
+
 #if defined(OS_ANDROID)
   content_detectors_.push_back(linked_ptr<ContentDetector>(
       new AddressDetector()));
@@ -717,8 +752,6 @@
     CompleteInit();
   }
 
-  g_view_map.Get().insert(std::make_pair(webview(), this));
-  g_routing_id_view_map.Get().insert(std::make_pair(routing_id_, this));
   webview()->setDeviceScaleFactor(device_scale_factor_);
   webview()->setDisplayMode(display_mode_);
   webview()->settings()->setPreferCompositingToLCDTextEnabled(
@@ -730,26 +763,6 @@
 
   ApplyWebPreferences(webkit_preferences_, webview());
 
-  RenderFrameProxy* proxy = NULL;
-  if (params.proxy_routing_id != MSG_ROUTING_NONE) {
-    CHECK(params.swapped_out);
-    proxy = RenderFrameProxy::CreateProxyToReplaceFrame(
-        main_render_frame_, params.proxy_routing_id,
-        blink::WebTreeScopeType::Document);
-    main_render_frame_->set_render_frame_proxy(proxy);
-  }
-
-  // In --site-per-process, just use the WebRemoteFrame as the main frame.
-  if (command_line.HasSwitch(switches::kSitePerProcess) && proxy) {
-    webview()->setMainFrame(proxy->web_frame());
-    // Initialize the WebRemoteFrame with information replicated from the
-    // browser process.
-    proxy->SetReplicatedState(params.replicated_frame_state);
-  } else {
-    webview()->setMainFrame(main_render_frame_->GetWebFrame());
-  }
-  main_render_frame_->Initialize();
-
   if (switches::IsTouchDragDropEnabled())
     webview()->settings()->setTouchDragDropEnabled(true);
 
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 2b2dbf58..9a206983 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -65,7 +65,6 @@
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebNode.h"
 #include "third_party/WebKit/public/web/WebPagePopup.h"
-#include "third_party/WebKit/public/web/WebPopupMenu.h"
 #include "third_party/WebKit/public/web/WebPopupMenuInfo.h"
 #include "third_party/WebKit/public/web/WebRange.h"
 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
@@ -104,8 +103,6 @@
 using blink::WebNode;
 using blink::WebPagePopup;
 using blink::WebPoint;
-using blink::WebPopupMenu;
-using blink::WebPopupMenuInfo;
 using blink::WebPopupType;
 using blink::WebRange;
 using blink::WebRect;
@@ -577,9 +574,6 @@
   switch (render_widget->popup_type_) {
     case blink::WebPopupTypeNone:  // Nothing to create.
       break;
-    case blink::WebPopupTypeSelect:
-    case blink::WebPopupTypeSuggestion:
-      return WebPopupMenu::create(render_widget);
     case blink::WebPopupTypePage:
       return WebPagePopup::create(render_widget);
     default:
diff --git a/content/renderer/service_worker/embedded_worker_context_client.cc b/content/renderer/service_worker/embedded_worker_context_client.cc
index 4cf1941..abbb66a 100644
--- a/content/renderer/service_worker/embedded_worker_context_client.cc
+++ b/content/renderer/service_worker/embedded_worker_context_client.cc
@@ -334,9 +334,16 @@
   script_context_->DidHandlePushEvent(request_id, result);
 }
 
+// TODO(chasej): crbug.com/486890 - Remove when matching blink changes land
 void EmbeddedWorkerContextClient::didHandleSyncEvent(int request_id) {
+  didHandleSyncEvent(request_id, blink::WebServiceWorkerEventResultCompleted);
+}
+
+void EmbeddedWorkerContextClient::didHandleSyncEvent(
+    int request_id,
+    blink::WebServiceWorkerEventResult result) {
   DCHECK(script_context_);
-  script_context_->DidHandleSyncEvent(request_id);
+  script_context_->DidHandleSyncEvent(request_id, result);
 }
 
 void EmbeddedWorkerContextClient::didHandleCrossOriginConnectEvent(
diff --git a/content/renderer/service_worker/embedded_worker_context_client.h b/content/renderer/service_worker/embedded_worker_context_client.h
index cc1cba1..9511ac7 100644
--- a/content/renderer/service_worker/embedded_worker_context_client.h
+++ b/content/renderer/service_worker/embedded_worker_context_client.h
@@ -104,7 +104,10 @@
       blink::WebServiceWorkerEventResult result);
   virtual void didHandlePushEvent(int request_id,
                                   blink::WebServiceWorkerEventResult result);
+  // TODO(chasej): crbug.com/486890 - Remove when matching blink changes land
   virtual void didHandleSyncEvent(int request_id);
+  virtual void didHandleSyncEvent(int request_id,
+                                  blink::WebServiceWorkerEventResult result);
   virtual void didHandleCrossOriginConnectEvent(int request_id,
                                                 bool accept_connection);
 
diff --git a/content/renderer/service_worker/service_worker_script_context.cc b/content/renderer/service_worker/service_worker_script_context.cc
index 1930f93c..d314ce78 100644
--- a/content/renderer/service_worker/service_worker_script_context.cc
+++ b/content/renderer/service_worker/service_worker_script_context.cc
@@ -218,9 +218,11 @@
       GetRoutingID(), request_id, result));
 }
 
-void ServiceWorkerScriptContext::DidHandleSyncEvent(int request_id) {
-  Send(new ServiceWorkerHostMsg_SyncEventFinished(
-      GetRoutingID(), request_id));
+void ServiceWorkerScriptContext::DidHandleSyncEvent(
+    int request_id,
+    blink::WebServiceWorkerEventResult result) {
+  Send(new ServiceWorkerHostMsg_SyncEventFinished(GetRoutingID(), request_id,
+                                                  result));
 }
 
 void ServiceWorkerScriptContext::DidHandleCrossOriginConnectEvent(
diff --git a/content/renderer/service_worker/service_worker_script_context.h b/content/renderer/service_worker/service_worker_script_context.h
index 7203140..9013795 100644
--- a/content/renderer/service_worker/service_worker_script_context.h
+++ b/content/renderer/service_worker/service_worker_script_context.h
@@ -70,7 +70,8 @@
       blink::WebServiceWorkerEventResult result);
   void DidHandlePushEvent(int request_id,
                           blink::WebServiceWorkerEventResult result);
-  void DidHandleSyncEvent(int request_id);
+  void DidHandleSyncEvent(int request_id,
+                          blink::WebServiceWorkerEventResult result);
   void DidHandleCrossOriginConnectEvent(int request_id, bool accept_connection);
   void GetClients(
       const blink::WebServiceWorkerClientQueryOptions& options,
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index 6066718..d505da3 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -170,6 +170,8 @@
     "renderer/shell_content_renderer_client.h",
     "renderer/shell_render_view_observer.cc",
     "renderer/shell_render_view_observer.h",
+    "utility/shell_content_utility_client.cc",
+    "utility/shell_content_utility_client.h",
   ]
 
   # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc
index 42fb382..5858071 100644
--- a/content/shell/app/shell_main_delegate.cc
+++ b/content/shell/app/shell_main_delegate.cc
@@ -27,6 +27,7 @@
 #include "content/shell/common/shell_switches.h"
 #include "content/shell/renderer/layout_test/layout_test_content_renderer_client.h"
 #include "content/shell/renderer/shell_content_renderer_client.h"
+#include "content/shell/utility/shell_content_utility_client.h"
 #include "media/base/media_switches.h"
 #include "media/base/mime_util.h"
 #include "net/cookies/cookie_monster.h"
@@ -346,4 +347,9 @@
   return renderer_client_.get();
 }
 
+ContentUtilityClient* ShellMainDelegate::CreateContentUtilityClient() {
+  utility_client_.reset(new ShellContentUtilityClient);
+  return utility_client_.get();
+}
+
 }  // namespace content
diff --git a/content/shell/app/shell_main_delegate.h b/content/shell/app/shell_main_delegate.h
index 930009c..f8439bc 100644
--- a/content/shell/app/shell_main_delegate.h
+++ b/content/shell/app/shell_main_delegate.h
@@ -13,6 +13,7 @@
 namespace content {
 class ShellContentBrowserClient;
 class ShellContentRendererClient;
+class ShellContentUtilityClient;
 
 #if defined(OS_ANDROID)
 class BrowserMainRunner;
@@ -33,12 +34,14 @@
 #endif
   ContentBrowserClient* CreateContentBrowserClient() override;
   ContentRendererClient* CreateContentRendererClient() override;
+  ContentUtilityClient* CreateContentUtilityClient() override;
 
   static void InitializeResourceBundle();
 
  private:
   scoped_ptr<ShellContentBrowserClient> browser_client_;
   scoped_ptr<ShellContentRendererClient> renderer_client_;
+  scoped_ptr<ShellContentUtilityClient> utility_client_;
   ShellContentClient content_client_;
 
 #if defined(OS_ANDROID)
diff --git a/content/shell/browser/blink_test_controller.cc b/content/shell/browser/blink_test_controller.cc
index ef3eeb9..bdfcd1de 100644
--- a/content/shell/browser/blink_test_controller.cc
+++ b/content/shell/browser/blink_test_controller.cc
@@ -8,10 +8,12 @@
 
 #include "base/base64.h"
 #include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/dom_storage_context.h"
 #include "content/public/browser/gpu_data_manager.h"
@@ -400,7 +402,7 @@
   DCHECK(CalledOnValidThread());
   printer_->AddErrorMessage(
       base::StringPrintf("#CRASHED - plugin (pid %d)", plugin_pid));
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(base::IgnoreResult(&BlinkTestController::DiscardMainWindow),
                  base::Unretained(this)));
@@ -481,8 +483,8 @@
   WebContentsObserver::Observe(NULL);
   if (test_phase_ != BETWEEN_TESTS) {
     Shell::CloseAllWindows();
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::MessageLoop::QuitClosure());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::MessageLoop::QuitClosure());
     test_phase_ = CLEAN_UP;
   } else if (main_window_) {
     main_window_->Close();
@@ -515,7 +517,7 @@
   RenderViewHost* render_view_host =
       main_window_->web_contents()->GetRenderViewHost();
   main_window_->web_contents()->ExitFullscreen();
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(base::IgnoreResult(&BlinkTestController::Send),
                  base::Unretained(this),
@@ -680,15 +682,15 @@
     return;
   }
 
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-                                         base::MessageLoop::QuitClosure());
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::MessageLoop::QuitClosure());
 }
 
 void BlinkTestController::OnLeakDetectionDone(
     const LeakDetectionResult& result) {
   if (!result.leaked) {
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::MessageLoop::QuitClosure());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::MessageLoop::QuitClosure());
     return;
   }
 
diff --git a/content/shell/browser/layout_test/layout_test_browser_main.cc b/content/shell/browser/layout_test/layout_test_browser_main.cc
index 44f0549..ec34751 100644
--- a/content/shell/browser/layout_test/layout_test_browser_main.cc
+++ b/content/shell/browser/layout_test/layout_test_browser_main.cc
@@ -10,11 +10,13 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_restrictions.h"
 #include "content/public/browser/browser_main_runner.h"
 #include "content/public/common/url_constants.h"
@@ -170,8 +172,8 @@
       break;
   }
   if (!ran_at_least_once) {
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::MessageLoop::QuitClosure());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::MessageLoop::QuitClosure());
     main_runner->Run();
   }
 
@@ -212,8 +214,8 @@
 
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kCheckLayoutTestSysDeps)) {
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::MessageLoop::QuitClosure());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::MessageLoop::QuitClosure());
     main_runner->Run();
     content::Shell::CloseAllWindows();
     main_runner->Shutdown();
diff --git a/content/shell/browser/shell.cc b/content/shell/browser/shell.cc
index 67552c8..c1a445f9 100644
--- a/content/shell/browser/shell.cc
+++ b/content/shell/browser/shell.cc
@@ -6,11 +6,13 @@
 
 #include "base/auto_reset.h"
 #include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
@@ -89,8 +91,8 @@
   if (windows_.empty() && quit_message_loop_) {
     if (headless_)
       PlatformExit();
-    base::MessageLoop::current()->PostTask(FROM_HERE,
-                                           base::MessageLoop::QuitClosure());
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::MessageLoop::QuitClosure());
   }
 }
 
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
index 4a2e95c..ab722f4 100644
--- a/content/shell/browser/shell_content_browser_client.cc
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -206,19 +206,25 @@
   return false;
 }
 
-void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
-    base::CommandLine* command_line,
-    int child_process_id) {
+void ShellContentBrowserClient::AppendMappedFileCommandLineSwitches(
+    base::CommandLine* command_line) {
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
   std::string process_type =
       command_line->GetSwitchValueASCII(switches::kProcessType);
   if (process_type != switches::kZygoteProcess) {
+    DCHECK(natives_fd_exists());
     command_line->AppendSwitch(::switches::kV8NativesPassedByFD);
-    command_line->AppendSwitch(::switches::kV8SnapshotPassedByFD);
+    if (snapshot_fd_exists())
+      command_line->AppendSwitch(::switches::kV8SnapshotPassedByFD);
   }
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
 #endif  // OS_POSIX && !OS_MACOSX
+}
+
+void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
+    base::CommandLine* command_line,
+    int child_process_id) {
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kRunLayoutTest))
     command_line->AppendSwitch(switches::kRunLayoutTest);
@@ -343,7 +349,7 @@
     int child_process_id,
     FileDescriptorInfo* mappings) {
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
-  if (v8_natives_fd_.get() == -1 || v8_snapshot_fd_.get() == -1) {
+  if (!natives_fd_exists()) {
     int v8_natives_fd = -1;
     int v8_snapshot_fd = -1;
     if (gin::V8Initializer::OpenV8FilesForChildProcesses(&v8_natives_fd,
@@ -352,7 +358,9 @@
       v8_snapshot_fd_.reset(v8_snapshot_fd);
     }
   }
-  DCHECK(v8_natives_fd_.get() != -1 && v8_snapshot_fd_.get() != -1);
+  // V8 can't start up without the source of the natives, but it can
+  // start up (slower) without the snapshot.
+  DCHECK(natives_fd_exists());
   mappings->Share(kV8NativesDataDescriptor, v8_natives_fd_.get());
   mappings->Share(kV8SnapshotDataDescriptor, v8_snapshot_fd_.get());
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
diff --git a/content/shell/browser/shell_content_browser_client.h b/content/shell/browser/shell_content_browser_client.h
index 0dc59b2..fe843a6 100644
--- a/content/shell/browser/shell_content_browser_client.h
+++ b/content/shell/browser/shell_content_browser_client.h
@@ -46,6 +46,8 @@
   bool IsHandledURL(const GURL& url) override;
   void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
                                       int child_process_id) override;
+  void AppendMappedFileCommandLineSwitches(
+      base::CommandLine* command_line) override;
   void OverrideWebkitPrefs(RenderViewHost* render_view_host,
                            WebPreferences* prefs) override;
   void ResourceDispatcherHostCreated() override;
@@ -106,6 +108,8 @@
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
   base::ScopedFD v8_natives_fd_;
   base::ScopedFD v8_snapshot_fd_;
+  bool natives_fd_exists() { return v8_natives_fd_ != -1; }
+  bool snapshot_fd_exists() { return v8_snapshot_fd_ != -1; }
 #endif
 
   base::Closure select_client_certificate_callback_;
diff --git a/content/shell/browser/shell_url_request_context_getter.cc b/content/shell/browser/shell_url_request_context_getter.cc
index b6218ab..cafda2d 100644
--- a/content/shell/browser/shell_url_request_context_getter.cc
+++ b/content/shell/browser/shell_url_request_context_getter.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -93,7 +94,7 @@
 
 net::ProxyConfigService* ShellURLRequestContextGetter::GetProxyConfigService() {
   return net::ProxyService::CreateSystemProxyConfigService(
-      io_loop_->message_loop_proxy(), file_loop_->message_loop_proxy());
+      io_loop_->task_runner(), file_loop_->task_runner());
 }
 
 net::ProxyService* ShellURLRequestContextGetter::GetProxyService() {
diff --git a/content/shell/renderer/layout_test/blink_test_runner.cc b/content/shell/renderer/layout_test/blink_test_runner.cc
index b17da21..009f475 100644
--- a/content/shell/renderer/layout_test/blink_test_runner.cc
+++ b/content/shell/renderer/layout_test/blink_test_runner.cc
@@ -13,13 +13,15 @@
 #include "base/compiler_specific.h"
 #include "base/debug/debugger.h"
 #include "base/files/file_path.h"
+#include "base/location.h"
 #include "base/md5.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "components/test_runner/app_banner_client.h"
 #include "components/test_runner/gamepad_controller.h"
@@ -681,14 +683,14 @@
       int request_id, const std::string& platform) {
   test_runner::WebTestInterfaces* interfaces =
       LayoutTestRenderProcessObserver::GetInstance()->test_interfaces();
-  interfaces->GetTestInterfaces()->GetAppBannerClient()->ResolvePromise(
-      request_id, platform);
+  interfaces->GetAppBannerClient()->ResolvePromise(request_id, platform);
 }
 
 blink::WebPlugin* BlinkTestRunner::CreatePluginPlaceholder(
     blink::WebLocalFrame* frame, const blink::WebPluginParams& params) {
   if (params.mimeType == "application/x-plugin-placeholder-test")
-    return (new TestPluginPlaceholder(frame, params))->plugin();
+    return (new TestPluginPlaceholder(render_view()->GetMainRenderFrame(),
+                                      frame, params))->plugin();
   return 0;
 }
 
@@ -831,7 +833,7 @@
 void BlinkTestRunner::CaptureDumpComplete() {
   render_view()->GetWebView()->mainFrame()->stopLoading();
 
-  base::MessageLoop::current()->PostTask(
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(base::IgnoreResult(&BlinkTestRunner::Send),
                             base::Unretained(this),
                             new ShellViewHostMsg_TestFinished(routing_id())));
diff --git a/content/shell/renderer/layout_test/test_plugin_placeholder.cc b/content/shell/renderer/layout_test/test_plugin_placeholder.cc
index 3263cadf..5b5a071 100644
--- a/content/shell/renderer/layout_test/test_plugin_placeholder.cc
+++ b/content/shell/renderer/layout_test/test_plugin_placeholder.cc
@@ -10,9 +10,10 @@
 namespace content {
 
 TestPluginPlaceholder::TestPluginPlaceholder(
+    RenderFrame* render_frame,
     blink::WebLocalFrame* frame,
     const blink::WebPluginParams& params)
-    : PluginPlaceholder(nullptr,
+    : PluginPlaceholder(render_frame,
                         frame,
                         params,
                         "<div>Test content</div>",
diff --git a/content/shell/renderer/layout_test/test_plugin_placeholder.h b/content/shell/renderer/layout_test/test_plugin_placeholder.h
index 8fdc0e3..1424923f 100644
--- a/content/shell/renderer/layout_test/test_plugin_placeholder.h
+++ b/content/shell/renderer/layout_test/test_plugin_placeholder.h
@@ -11,7 +11,8 @@
 // A subclass of PluginPlaceholder for use in Blink layout tests.
 class TestPluginPlaceholder : public plugins::PluginPlaceholder {
  public:
-  TestPluginPlaceholder(blink::WebLocalFrame* frame,
+  TestPluginPlaceholder(RenderFrame* render_frame,
+                        blink::WebLocalFrame* frame,
                         const blink::WebPluginParams& params);
 
   void BindWebFrame(blink::WebFrame* frame) override;
diff --git a/content/shell/renderer/layout_test/test_video_frame_provider.cc b/content/shell/renderer/layout_test/test_video_frame_provider.cc
index 0989572..97ecb02 100644
--- a/content/shell/renderer/layout_test/test_video_frame_provider.cc
+++ b/content/shell/renderer/layout_test/test_video_frame_provider.cc
@@ -6,7 +6,8 @@
 
 #include "base/bind.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "media/base/video_frame.h"
 
 namespace content {
@@ -16,7 +17,7 @@
     const base::TimeDelta& frame_duration,
     const base::Closure& error_cb,
     const VideoFrameProvider::RepaintCB& repaint_cb)
-    : message_loop_proxy_(base::MessageLoopProxy::current()),
+    : task_runner_(base::ThreadTaskRunnerHandle::Get()),
       size_(size),
       state_(kStopped),
       frame_duration_(frame_duration),
@@ -28,36 +29,35 @@
 
 void TestVideoFrameProvider::Start() {
   DVLOG(1) << "TestVideoFrameProvider::Start";
-  DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+  DCHECK(task_runner_->BelongsToCurrentThread());
   state_ = kStarted;
-  message_loop_proxy_->PostTask(
-      FROM_HERE,
-      base::Bind(&TestVideoFrameProvider::GenerateFrame, this));
+  task_runner_->PostTask(
+      FROM_HERE, base::Bind(&TestVideoFrameProvider::GenerateFrame, this));
 }
 
 void TestVideoFrameProvider::Stop() {
   DVLOG(1) << "TestVideoFrameProvider::Stop";
-  DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+  DCHECK(task_runner_->BelongsToCurrentThread());
   state_ = kStopped;
 }
 
 void TestVideoFrameProvider::Play() {
   DVLOG(1) << "TestVideoFrameProvider::Play";
-  DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+  DCHECK(task_runner_->BelongsToCurrentThread());
   if (state_ == kPaused)
     state_ = kStarted;
 }
 
 void TestVideoFrameProvider::Pause() {
   DVLOG(1) << "TestVideoFrameProvider::Pause";
-  DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+  DCHECK(task_runner_->BelongsToCurrentThread());
   if (state_ == kStarted)
     state_ = kPaused;
 }
 
 void TestVideoFrameProvider::GenerateFrame() {
   DVLOG(1) << "TestVideoFrameProvider::GenerateFrame";
-  DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+  DCHECK(task_runner_->BelongsToCurrentThread());
   if (state_ == kStopped)
     return;
 
@@ -74,9 +74,8 @@
   }
 
   current_time_ += frame_duration_;
-  message_loop_proxy_->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&TestVideoFrameProvider::GenerateFrame, this),
+  task_runner_->PostDelayedTask(
+      FROM_HERE, base::Bind(&TestVideoFrameProvider::GenerateFrame, this),
       frame_duration_);
 }
 
diff --git a/content/shell/renderer/layout_test/test_video_frame_provider.h b/content/shell/renderer/layout_test/test_video_frame_provider.h
index 00ee3c8..ca09e3e 100644
--- a/content/shell/renderer/layout_test/test_video_frame_provider.h
+++ b/content/shell/renderer/layout_test/test_video_frame_provider.h
@@ -10,7 +10,7 @@
 #include "ui/gfx/geometry/size.h"
 
 namespace base {
-class MessageLoopProxy;
+class SingleThreadTaskRunner;
 }
 
 namespace content {
@@ -46,7 +46,7 @@
 
   void GenerateFrame();
 
-  scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   gfx::Size size_;
   State state_;
 
diff --git a/content/shell/utility/DEPS b/content/shell/utility/DEPS
new file mode 100644
index 0000000..72513eb
--- /dev/null
+++ b/content/shell/utility/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+mojo/shell",
+]
diff --git a/content/shell/utility/shell_content_utility_client.cc b/content/shell/utility/shell_content_utility_client.cc
new file mode 100644
index 0000000..d6c2982
--- /dev/null
+++ b/content/shell/utility/shell_content_utility_client.cc
@@ -0,0 +1,31 @@
+// 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 "content/shell/utility/shell_content_utility_client.h"
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/test/test_mojo_app.h"
+#include "mojo/shell/static_application_loader.h"
+
+namespace content {
+
+namespace {
+
+scoped_ptr<mojo::ApplicationDelegate> CreateTestApp() {
+  return scoped_ptr<mojo::ApplicationDelegate>(new TestMojoApp);
+}
+
+}  // namespace
+
+ShellContentUtilityClient::~ShellContentUtilityClient() {
+}
+
+void ShellContentUtilityClient::RegisterMojoApplications(
+    StaticMojoApplicationMap* apps) {
+  apps->insert(
+      std::make_pair(GURL(kTestMojoAppUrl), base::Bind(&CreateTestApp)));
+}
+
+}  // namespace content
diff --git a/content/shell/utility/shell_content_utility_client.h b/content/shell/utility/shell_content_utility_client.h
new file mode 100644
index 0000000..2479f58
--- /dev/null
+++ b/content/shell/utility/shell_content_utility_client.h
@@ -0,0 +1,22 @@
+// 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 CONTENT_SHELL_UTILITY_SHELL_CONTENT_UTILITY_CLIENT_H_
+#define CONTENT_SHELL_UTILITY_SHELL_CONTENT_UTILITY_CLIENT_H_
+
+#include "content/public/utility/content_utility_client.h"
+
+namespace content {
+
+class ShellContentUtilityClient : public ContentUtilityClient {
+ public:
+  ~ShellContentUtilityClient() override;
+
+  // ContentUtilityClient:
+  void RegisterMojoApplications(StaticMojoApplicationMap* apps) override;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_UTILITY_SHELL_CONTENT_UTILITY_CLIENT_H_
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 7a4377a..c254b4e 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -55,7 +55,9 @@
 
     public_deps += [ "//third_party/WebKit/public:blink" ]
     deps += [
+      ":content_test_mojo_bindings",
       "//components/scheduler:scheduler",
+      "//components/scheduler:test_support",
       "//content/browser/speech/proto",
       "//content/public/child",
       "//content/gpu",
@@ -67,6 +69,8 @@
       "//cc:test_support",
       "//ipc/mojo",
       "//media",
+      "//mojo/application/public/cpp:cpp_for_chromium",
+      "//mojo/environment:chromium",
       "//ppapi/host",
       "//ppapi/proxy",
       "//ppapi/proxy:test_support",
@@ -200,6 +204,12 @@
   }
 }
 
+mojom("content_test_mojo_bindings") {
+  sources = [
+    "../public/test/test_mojo_service.mojom",
+  ]
+}
+
 mojom("web_ui_test_mojo_bindings") {
   sources = [
     "data/web_ui_test_mojo_bindings.mojom",
@@ -278,6 +288,7 @@
       "//media/audio:test_support",
       "//media/base:test_support",
       "//media:shared_memory_support",
+      "//mojo/application/public/cpp:cpp_for_chromium",
       "//mojo/environment:chromium",
       "//net:test_support",
       "//ppapi/host",
diff --git a/content/test/DEPS b/content/test/DEPS
index 760b3586..e1d0d50 100644
--- a/content/test/DEPS
+++ b/content/test/DEPS
@@ -2,6 +2,7 @@
   # Allow inclusion of specific components that we depend on. We may only
   # depend on components which we share with the mojo html_viewer.
   "+components/scheduler/renderer",
+  "+components/scheduler/test",
 
   "+cc/blink",
   "+chromeos/audio", # For WebRTC tests.
diff --git a/content/test/content_browser_test_test.cc b/content/test/content_browser_test_test.cc
index 7b43385..f574f0ce 100644
--- a/content/test/content_browser_test_test.cc
+++ b/content/test/content_browser_test_test.cc
@@ -5,7 +5,10 @@
 #include "content/public/test/content_browser_test.h"
 
 #include "base/command_line.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test_utils.h"
@@ -58,7 +61,7 @@
 
 IN_PROC_BROWSER_TEST_F(ContentBrowserTestSanityTest, NonNestableTask) {
   bool non_nested_task_ran = false;
-  base::MessageLoop::current()->PostNonNestableTask(
+  base::ThreadTaskRunnerHandle::Get()->PostNonNestableTask(
       FROM_HERE, base::Bind(&CallbackChecker, &non_nested_task_ran));
   content::RunAllPendingInMessageLoop();
   ASSERT_TRUE(non_nested_task_ran);
diff --git a/content/test/content_test_launcher.cc b/content/test/content_test_launcher.cc
index 9b30fdb..46e6392 100644
--- a/content/test/content_test_launcher.cc
+++ b/content/test/content_test_launcher.cc
@@ -58,6 +58,7 @@
 
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
     gin::V8Initializer::LoadV8Snapshot();
+    gin::V8Initializer::LoadV8Natives();
 #endif
 
     // This needs to be done before base::TestSuite::Initialize() is called,
diff --git a/content/test/data/devtools/navigation.html b/content/test/data/devtools/navigation.html
new file mode 100644
index 0000000..90e246f0
--- /dev/null
+++ b/content/test/data/devtools/navigation.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+Dummy page.
+</body>
+</html>
diff --git a/content/test/data/media/peerconnection-call.html b/content/test/data/media/peerconnection-call.html
index 3c782bfe..8087884 100644
--- a/content/test/data/media/peerconnection-call.html
+++ b/content/test/data/media/peerconnection-call.html
@@ -115,8 +115,7 @@
 
   // The second set of constraints should request audio (e.g. audio:true) since
   // we expect audio to be playing after the second renegotiation.
-  function callAndRenegotiateToAudio(beLenient, constraints,
-                                     renegotiationConstraints) {
+  function callAndRenegotiateToAudio(constraints, renegotiationConstraints) {
     createConnections(null);
     navigator.webkitGetUserMedia(constraints,
         addStreamToBothConnectionsAndNegotiate, printGetUserMediaError);
@@ -129,7 +128,7 @@
           addStreamToTheFirstConnectionAndNegotiate, printGetUserMediaError);
 
       var onCallEstablished = function() {
-        ensureAudioPlaying(gSecondConnection, beLenient);
+        ensureAudioPlaying(gSecondConnection);
       };
 
       waitForConnectionToStabilize(gFirstConnection, onCallEstablished);
@@ -349,7 +348,7 @@
         offerOptions);
   }
 
-  function callAndEnsureAudioIsPlaying(beLenient, constraints) {
+  function callAndEnsureAudioIsPlaying(constraints) {
     createConnections(null);
 
     // Add the local stream to gFirstConnection to play one-way audio.
@@ -357,13 +356,13 @@
       addStreamToTheFirstConnectionAndNegotiate, printGetUserMediaError);
 
     var onCallEstablished = function() {
-      ensureAudioPlaying(gSecondConnection, beLenient);
+      ensureAudioPlaying(gSecondConnection);
     };
 
     waitForConnectionToStabilize(gFirstConnection, onCallEstablished);
   }
 
-  function callWithIsac16KAndEnsureAudioIsPlaying(beLenient, constraints) {
+  function callWithIsac16KAndEnsureAudioIsPlaying(constraints) {
     transformSdp = function(sdp) {
       sdp = sdp.replace(/m=audio (\d+) RTP\/SAVPF.*\r\n/g,
                         'm=audio $1 RTP/SAVPF 103 126\r\n');
@@ -373,7 +372,7 @@
 
       return sdp;
     }
-    callAndEnsureAudioIsPlaying(beLenient, constraints);
+    callAndEnsureAudioIsPlaying(constraints);
   }
 
   function enableRemoteVideo(peerConnection, enabled) {
@@ -396,8 +395,8 @@
     localStream.getAudioTracks()[0].enabled = enabled;
   }
 
-  function callAndEnsureRemoteAudioTrackMutingWorks(beLenient) {
-    callAndEnsureAudioIsPlaying(beLenient, {audio: true, video: true});
+  function callAndEnsureRemoteAudioTrackMutingWorks() {
+    callAndEnsureAudioIsPlaying({audio: true, video: true});
     setAllEventsOccuredHandler(function() {
       setAllEventsOccuredHandler(reportTestSuccess);
 
@@ -408,8 +407,8 @@
     });
   }
 
-  function callAndEnsureLocalAudioTrackMutingWorks(beLenient) {
-    callAndEnsureAudioIsPlaying(beLenient, {audio: true, video: true});
+  function callAndEnsureLocalAudioTrackMutingWorks() {
+    callAndEnsureAudioIsPlaying({audio: true, video: true});
     setAllEventsOccuredHandler(function() {
       setAllEventsOccuredHandler(reportTestSuccess);
 
@@ -420,8 +419,8 @@
     });
   }
 
-  function callAndEnsureAudioTrackUnmutingWorks(beLenient) {
-    callAndEnsureAudioIsPlaying(beLenient, {audio: true, video: true});
+  function callAndEnsureAudioTrackUnmutingWorks() {
+    callAndEnsureAudioIsPlaying({audio: true, video: true});
     setAllEventsOccuredHandler(function() {
       setAllEventsOccuredHandler(reportTestSuccess);
 
@@ -435,26 +434,26 @@
       }, 500);
 
       setTimeout(function() {
-        ensureAudioPlaying(gSecondConnection, beLenient);
+        ensureAudioPlaying(gSecondConnection);
       }, 1500);
     });
   }
 
-  function callAndEnsureLocalVideoMutingDoesntMuteAudio(beLenient) {
-    callAndEnsureAudioIsPlaying(beLenient, {audio: true, video: true});
+  function callAndEnsureLocalVideoMutingDoesntMuteAudio() {
+    callAndEnsureAudioIsPlaying({audio: true, video: true});
     setAllEventsOccuredHandler(function() {
       setAllEventsOccuredHandler(reportTestSuccess);
       enableLocalVideo(gFirstConnection, false);
-      ensureAudioPlaying(gSecondConnection, beLenient);
+      ensureAudioPlaying(gSecondConnection);
     });
   }
 
-  function callAndEnsureRemoteVideoMutingDoesntMuteAudio(beLenient) {
-    callAndEnsureAudioIsPlaying(beLenient, {audio: true, video: true});
+  function callAndEnsureRemoteVideoMutingDoesntMuteAudio() {
+    callAndEnsureAudioIsPlaying({audio: true, video: true});
     setAllEventsOccuredHandler(function() {
       setAllEventsOccuredHandler(reportTestSuccess);
       enableRemoteVideo(gSecondConnection, false);
-      ensureAudioPlaying(gSecondConnection, beLenient);
+      ensureAudioPlaying(gSecondConnection);
     });
   }
 
diff --git a/content/test/data/media/webrtc_test_audio.js b/content/test/data/media/webrtc_test_audio.js
index 836862d0..e47e08a 100644
--- a/content/test/data/media/webrtc_test_audio.js
+++ b/content/test/data/media/webrtc_test_audio.js
@@ -10,14 +10,20 @@
 // Queries WebRTC stats on |peerConnection| to find out whether audio is playing
 // on the connection. Note this does not necessarily mean the audio is actually
 // playing out (for instance if there's a bug in the WebRTC web media player).
-// If |beLenient| is true, we assume we're on a slow and unreliable bot and that
-// we should do a minimum of checking.
-function ensureAudioPlaying(peerConnection, beLenient) {
+function ensureAudioPlaying(peerConnection) {
   addExpectedEvent();
 
-  gatherAudioLevelSamples(peerConnection, 3 * 1000, function(samples) {
-    identifyFakeDeviceSignal_(samples, beLenient);
-    eventOccured();
+  var attempt = 1;
+  gatherAudioLevelSamples(peerConnection, function(samples) {
+    if (identifyFakeDeviceSignal_(samples)) {
+      eventOccured();
+      return true;
+    }
+    if (attempt++ % 5 == 0) {
+      console.log('Still waiting for the fake audio signal.');
+      console.log('Dumping samples so far for analysis: ' + samples);
+    }
+    return false;
   });
 }
 
@@ -25,12 +31,20 @@
 // on the connection.
 function ensureSilence(peerConnection) {
   addExpectedEvent();
-  setTimeout(function() {
-    gatherAudioLevelSamples(peerConnection, 1 * 1000, function(samples) {
-      identifySilence_(samples);
+
+  var attempt = 1;
+  gatherAudioLevelSamples(peerConnection, function(samples) {
+    if (identifySilence_(samples)) {
       eventOccured();
-    });
-  }, 500);
+      return true;
+    }
+    if (attempt++ % 5 == 0) {
+      console.log('Still waiting for audio to go silent.');
+      console.log('Dumping samples so far for analysis: ' + samples);
+    }
+    return false;
+  });
+
 }
 
 // Not sure if this is a bug, but sometimes we get several audio ssrc's where
@@ -47,19 +61,24 @@
   return Math.max(audioOutputLevels[0], audioOutputLevels[1]);
 }
 
-// Gathers samples from WebRTC stats as fast as possible for |durationMs|
-// milliseconds and calls back |callback| with an array with numbers in the
-// [0, 32768] range. There are no guarantees for how often we will be able to
-// collect values, but this function deliberately avoids setTimeout calls in
-// order be as insensitive as possible to starvation (particularly when this
-// code runs in parallel with other tests on a heavily loaded bot).
-function gatherAudioLevelSamples(peerConnection, durationMs, callback) {
-  console.log('Gathering audio samples for ' + durationMs + ' milliseconds...');
+// Gathers samples from WebRTC stats as fast as possible for and calls back
+// |callback| continuously with an array with numbers in the [0, 32768] range.
+// The array will grow continuously over time as we gather more samples. The
+// |callback| should return true when it is satisfied. It will be called about
+// once a second and can contain expensive processing (but faster = better).
+//
+// There are no guarantees for how often we will be able to collect values,
+// but this function deliberately avoids setTimeout calls in order be as
+// insensitive as possible to starvation (particularly when this code runs in
+// parallel with other tests on a heavily loaded bot).
+function gatherAudioLevelSamples(peerConnection, callback) {
+  console.log('Gathering audio samples...');
+  var callbackIntervalMs = 1000;
   var audioLevelSamples = []
 
   // If this times out and never found any audio output levels, the call
   // probably doesn't have an audio stream.
-  var startTime = new Date();
+  var lastRunAt = new Date();
   var gotStats = function(response) {
     audioOutputLevels = getAudioLevelFromStats_(response);
     if (audioOutputLevels.length == 0) {
@@ -70,12 +89,15 @@
     var outputLevel = workAroundSeveralReportsIssue(audioOutputLevels);
     audioLevelSamples.push(outputLevel);
 
-    var elapsed = new Date() - startTime;
-    if (elapsed > durationMs) {
-      console.log('Gathered all samples.');
-      callback(audioLevelSamples);
-      return;
+    var elapsed = new Date() - lastRunAt;
+    if (elapsed > callbackIntervalMs) {
+      if (callback(audioLevelSamples)) {
+        console.log('Done gathering samples: we found what we looked for.');
+        return;
+      }
+      lastRunAt = new Date();
     }
+    // Otherwise, continue as fast as we can.
     peerConnection.getStats(gotStats);
   }
   peerConnection.getStats(gotStats);
@@ -88,16 +110,11 @@
 * least two seconds since we expect to see at least three "peaks" in there
 * (we should see either 3 or 4 depending on how things line up).
 *
-* If |beLenient| is specified, we assume we're running on a slow device or
-* or under TSAN, and relax the checks quite a bit.
-*
 * @private
 */
-function identifyFakeDeviceSignal_(samples, beLenient) {
+function identifyFakeDeviceSignal_(samples) {
   var numPeaks = 0;
   var threshold = MAX_AUDIO_OUTPUT_ENERGY * 0.7;
-  if (beLenient)
-    threshold = MAX_AUDIO_OUTPUT_ENERGY * 0.6;
   var currentlyOverThreshold = false;
 
   // Detect when we have been been over the threshold and is going back again
@@ -108,16 +125,9 @@
     currentlyOverThreshold = samples[i] >= threshold;
   }
 
-  console.log('Number of peaks identified: ' + numPeaks);
-
-  var expectedPeaks = 2;
-  if (beLenient)
-    expectedPeaks = 1;
-
-  if (numPeaks < expectedPeaks)
-    failTest('Expected to see at least ' + expectedPeaks + ' peak(s) in ' +
-        'audio signal, got ' + numPeaks + '. Dumping samples for analysis: "' +
-        samples + '"');
+  var expectedPeaks = 3;
+  console.log(numPeaks + '/' + expectedPeaks + ' signal peaks identified.');
+  return numPeaks >= expectedPeaks;
 }
 
 /**
@@ -130,8 +140,8 @@
 
   // If silent (like when muted), we should get very near zero audio level.
   console.log('Average audio level: ' + average);
-  if (average > 500)
-    failTest('Expected silence, but avg audio level was ' + average);
+
+  return average < 0.01 * MAX_AUDIO_OUTPUT_ENERGY;
 }
 
 /**
diff --git a/content/test/fake_compositor_dependencies.cc b/content/test/fake_compositor_dependencies.cc
index a29312fa..37ef965 100644
--- a/content/test/fake_compositor_dependencies.cc
+++ b/content/test/fake_compositor_dependencies.cc
@@ -4,7 +4,8 @@
 
 #include "content/test/fake_compositor_dependencies.h"
 
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "cc/test/fake_external_begin_frame_source.h"
 #include "third_party/khronos/GLES2/gl2.h"
 
@@ -58,7 +59,7 @@
 
 scoped_refptr<base::SingleThreadTaskRunner>
 FakeCompositorDependencies::GetCompositorMainThreadTaskRunner() {
-  return base::MessageLoopProxy::current();
+  return base::ThreadTaskRunnerHandle::Get();
 }
 
 scoped_refptr<base::SingleThreadTaskRunner>
diff --git a/content/test/gpu/gpu_tests/context_lost_expectations.py b/content/test/gpu/gpu_tests/context_lost_expectations.py
index 9f4e6a9..e5c6a6c 100644
--- a/content/test/gpu/gpu_tests/context_lost_expectations.py
+++ b/content/test/gpu/gpu_tests/context_lost_expectations.py
@@ -15,3 +15,7 @@
     # AMD Radeon 6450
     self.Fail('ContextLost.WebGLContextLostFromGPUProcessExit',
         ['linux', ('amd', 0x6779)], bug=479975)
+
+    # Mac 10.8 (ideally should restrict this to Debug, too)
+    self.Fail('ContextLost.WebGLContextLostFromSelectElement',
+              ['mountainlion'], bug=497411)
diff --git a/content/test/gpu/gpu_tests/gpu_test_expectations.py b/content/test/gpu/gpu_tests/gpu_test_expectations.py
index baff064..9bb354172 100644
--- a/content/test/gpu/gpu_tests/gpu_test_expectations.py
+++ b/content/test/gpu/gpu_tests/gpu_test_expectations.py
@@ -17,8 +17,8 @@
 # Browser types:
 #     android-webview-shell
 #
-# Direct3D status:
-#     d3d9, d3d11
+# ANGLE renderer:
+#     d3d9, d3d11, opengl
 #
 # Specific GPUs can be listed as a tuple with vendor name and device ID.
 # Examples: ('nvidia', 0x1234), ('arm', 'Mali-T604')
@@ -28,14 +28,14 @@
 #   self.Fail('gl-enable-vertex-attrib.html',
 #       ['mac', 'amd', ('nvidia', 0x1234)], bug=123)
 
-D3D_MODIFIERS = ['d3d9', 'd3d11']
+ANGLE_MODIFIERS = ['d3d9', 'd3d11', 'opengl']
 
 BROWSER_TYPE_MODIFIERS = ['android-webview-shell']
 
 class GpuTestExpectations(test_expectations.TestExpectations):
   def IsValidUserDefinedCondition(self, condition):
-    # Add support for d3d9 and d3d11-specific expectations.
-    if condition in D3D_MODIFIERS:
+    # Add support for d3d9, d3d11 and opengl-specific expectations.
+    if condition in ANGLE_MODIFIERS:
       return True
     # Add support for browser-type-specific expectations.
     if condition in BROWSER_TYPE_MODIFIERS:
@@ -63,7 +63,7 @@
                        browser.browser_type in browser_expectations)
     if not browser_matches:
       return False
-    d3d_version = ''
+    angle_renderer = ''
     gpu_info = None
     if browser.supports_system_info:
       gpu_info = browser.GetSystemInfo().gpu
@@ -71,11 +71,13 @@
       gl_renderer = gpu_info.aux_attributes.get('gl_renderer')
       if gl_renderer:
         if 'Direct3D11' in gl_renderer:
-          d3d_version = 'd3d11'
+          angle_renderer = 'd3d11'
         elif 'Direct3D9' in gl_renderer:
-          d3d_version = 'd3d9'
-    d3d_expectations = [x for x in expectation.user_defined_conditions
-                        if x in D3D_MODIFIERS]
-    d3d_matches = ((not d3d_expectations) or
-                   d3d_version in d3d_expectations)
-    return d3d_matches
+          angle_renderer = 'd3d9'
+        elif 'OpenGL' in gl_renderer:
+          angle_renderer = 'opengl'
+    angle_expectations = [x for x in expectation.user_defined_conditions
+                        if x in ANGLE_MODIFIERS]
+    angle_matches = ((not angle_expectations) or
+                   angle_renderer in angle_expectations)
+    return angle_matches
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index 3ec86cb..4ec4450 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -32,10 +32,14 @@
     # Fails on all platforms
     self.Fail('deqp/data/gles2/shaders/constant_expressions.html',
         bug=478572)
+    self.Fail('deqp/data/gles2/shaders/constants.html',
+        bug=478572)
     self.Fail('deqp/data/gles2/shaders/fragdata.html',
         bug=478572)
     self.Fail('deqp/data/gles2/shaders/functions.html',
         bug=478572)
+    self.Fail('deqp/data/gles2/shaders/linkage.html',
+        bug=478572)
     self.Fail('deqp/data/gles2/shaders/preprocessor.html',
         bug=478572)
     self.Fail('deqp/data/gles2/shaders/scoping.html',
@@ -46,9 +50,6 @@
         bug=485634)
 
     # Win failures
-    self.Fail('conformance/glsl/misc/' +
-              'ternary-operators-in-global-initializers.html',
-        ['win'], bug=415694)
     self.Fail('conformance/glsl/bugs/' +
               'pow-of-small-constant-in-user-defined-function.html',
         ['win'], bug=485641)
@@ -64,8 +65,6 @@
         ['win7', 'intel'])
     self.Fail('conformance/rendering/gl-viewport-test.html',
         ['win7', 'intel'], bug=372511)
-    self.Fail('conformance/glsl/misc/shader-with-array-of-structs-uniform.html',
-        ['win7', 'intel', 'nvidia'], bug=373972)
 
     # Win / AMD flakiness seen on new tryservers (affecting most tests
     # randomly, must investigate ASAP)
@@ -106,6 +105,49 @@
     self.Skip('conformance/extensions/oes-texture-half-float-with-canvas.html',
         ['win', 'd3d9'], bug=896) # angle bug ID
 
+    # Win / OpenGL failures
+    self.Fail('conformance/attribs/gl-disabled-vertex-attrib.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/attribs/gl-disabled-vertex-attrib.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/canvas/canvas-test.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/canvas/draw-webgl-to-canvas-test.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/canvas/' +
+        'draw-static-webgl-to-multiple-canvas-test.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/canvas/to-data-url-test.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/context/' +
+        'context-attribute-preserve-drawing-buffer.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/context/'+
+        'context-attributes-alpha-depth-stencil-antialias.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/context/premultiplyalpha-test.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/extensions/ext-sRGB.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/extensions/oes-texture-float-with-canvas.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/extensions/oes-texture-float.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/extensions/oes-texture-half-float.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/extensions/oes-texture-half-float-with-canvas.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/glsl/variables/gl-pointcoord.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/reading/read-pixels-pack-alignment.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/renderbuffers/framebuffer-object-attachment.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/textures/gl-pixelstorei.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+    self.Fail('conformance/textures/tex-image-canvas-corruption.html',
+        ['win', 'opengl'], bug=1007) # angle bug ID
+
     # Mac failures
     self.Fail('conformance/glsl/misc/shaders-with-invariance.html',
         ['mac'], bug=421710)
@@ -397,9 +439,7 @@
 
     self.Fail('deqp/data/gles3/shaders/arrays.html', bug=483282)
     self.Fail('deqp/data/gles3/shaders/constants.html', bug=483282)
-    self.Fail('deqp/data/gles3/shaders/constant_expressions.html', bug=483282)
     self.Fail('deqp/data/gles3/shaders/conversions.html', bug=483282)
-    self.Fail('deqp/data/gles3/shaders/fragdata.html', bug=483282)
     self.Fail('deqp/data/gles3/shaders/functions.html', bug=483282)
     self.Fail('deqp/data/gles3/shaders/linkage.html', bug=483282)
     self.Fail('deqp/data/gles3/shaders/preprocessor.html', bug=483282)
@@ -415,26 +455,40 @@
     self.Fail('conformance2/attribs/gl-vertexattribipointer.html', bug=483282)
     self.Fail('conformance2/attribs/gl-vertexattribipointer-offsets.html',
         bug=483282)
-
-    self.Fail('conformance2/context/constants-and-properties-2.html',
-        bug=483282)
-
-    self.Fail('conformance2/core/draw-buffers.html', bug=483282)
-    self.Fail('conformance2/core/frag-depth.html', bug=483282)
-    self.Fail('conformance2/core/tex-mipmap-levels.html', bug=483282)
-
-    self.Fail('conformance2/core/tex-new-formats.html', bug=483282)
-    self.Fail('conformance2/core/tex-storage-2d.html', bug=483282)
-    self.Fail('conformance2/core/tex-storage-and-subimage-3d.html', bug=483282)
-    self.Fail('conformance2/core/texture-npot.html', bug=483282)
-
-    self.Fail('conformance2/glsl3/misplaced-version-directive.html', bug=483282)
-
-    self.Fail('conformance2/state/gl-get-calls.html', bug=483282)
-    self.Fail('conformance2/state/gl-object-get-calls.html', bug=483282)
-
     self.Fail('conformance2/buffers/buffer-copying-contents.html', bug=483282)
     self.Fail('conformance2/buffers/buffer-copying-restrictions.html',
         bug=483282)
     self.Fail('conformance2/buffers/buffer-type-restrictions.html', bug=483282)
     self.Fail('conformance2/buffers/getBufferSubData.html', bug=483282)
+    self.Fail('conformance2/context/constants-and-properties-2.html',
+        bug=483282)
+
+    self.Fail('conformance2/glsl3/array-complex-indexing.html', bug=483282)
+    self.Fail('conformance2/glsl3/frag-depth.html', bug=483282)
+    self.Fail('conformance2/glsl3/invalid-default-precision.html', bug=483282)
+    self.Fail('conformance2/glsl3/sequence-operator-returns-non-constant.html',
+        bug=483282)
+    self.Fail('conformance2/glsl3/ternary-operator-on-arrays-glsl3.html',
+        bug=483282)
+    self.Fail('conformance2/misc/instanceof-test.html', bug=483282)
+    self.Fail('conformance2/renderbuffers/framebuffer-test.html', bug=483282)
+    self.Fail('conformance2/rendering/draw-buffers.html', bug=483282)
+    self.Fail('conformance2/state/gl-get-calls.html', bug=483282)
+    self.Fail('conformance2/state/gl-object-get-calls.html', bug=483282)
+    self.Fail('conformance2/textures/gl-get-tex-parameter.html', bug=483282)
+    self.Fail('conformance2/textures/tex-input-validation.html', bug=483282)
+    self.Fail('conformance2/textures/tex-mipmap-levels.html', bug=483282)
+    self.Fail('conformance2/textures/tex-new-formats.html', bug=483282)
+    self.Fail('conformance2/textures/tex-storage-2d.html', bug=483282)
+    self.Fail('conformance2/textures/texture-npot.html', bug=483282)
+    self.Fail('conformance2/transform_feedback/transform_feedback.html',
+        bug=483282)
+
+    # Mac only.
+    self.Fail('conformance2/renderbuffers/' +
+        'multisampled-renderbuffer-initialization.html',
+        ['mac'], bug=483282)
+    self.Fail('conformance2/rendering/instanced-arrays.html',
+        ['mac'], bug=483282)
+    self.Fail('conformance2/textures/tex-storage-and-subimage-3d.html',
+        ['mac'], bug=483282)
diff --git a/content/test/net/url_request_abort_on_end_job.cc b/content/test/net/url_request_abort_on_end_job.cc
index cdaca32..8bfd7f9 100644
--- a/content/test/net/url_request_abort_on_end_job.cc
+++ b/content/test/net/url_request_abort_on_end_job.cc
@@ -7,7 +7,10 @@
 #include <cstring>
 
 #include "base/compiler_specific.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/test/net/url_request_abort_on_end_job.h"
 #include "net/base/io_buffer.h"
@@ -102,10 +105,9 @@
 }
 
 void URLRequestAbortOnEndJob::Start() {
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&URLRequestAbortOnEndJob::StartAsync,
-                 weak_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&URLRequestAbortOnEndJob::StartAsync,
+                            weak_factory_.GetWeakPtr()));
 }
 
 bool URLRequestAbortOnEndJob::ReadRawData(net::IOBuffer* buf,
diff --git a/content/test/test_blink_web_unit_test_support.cc b/content/test/test_blink_web_unit_test_support.cc
index 4dbce405..0739137 100644
--- a/content/test/test_blink_web_unit_test_support.cc
+++ b/content/test/test_blink_web_unit_test_support.cc
@@ -12,8 +12,9 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/platform_thread.h"
-#include "components/scheduler/renderer/renderer_scheduler.h"
+#include "components/scheduler/renderer/renderer_scheduler_impl.h"
 #include "components/scheduler/renderer/webthread_impl_for_renderer_scheduler.h"
+#include "components/scheduler/test/lazy_scheduler_message_loop_delegate_for_tests.h"
 #include "content/test/mock_webclipboard_impl.h"
 #include "content/test/web_gesture_curve_mock.h"
 #include "content/test/web_layer_tree_view_impl_for_testing.h"
@@ -24,7 +25,7 @@
 #include "storage/browser/database/vfs_backend.h"
 #include "third_party/WebKit/public/platform/WebData.h"
 #include "third_party/WebKit/public/platform/WebFileSystem.h"
-#include "third_party/WebKit/public/platform/WebScheduler.h"
+#include "third_party/WebKit/public/platform/WebPluginListBuilder.h"
 #include "third_party/WebKit/public/platform/WebStorageArea.h"
 #include "third_party/WebKit/public/platform/WebStorageNamespace.h"
 #include "third_party/WebKit/public/platform/WebString.h"
@@ -77,35 +78,6 @@
   DISALLOW_COPY_AND_ASSIGN(DummyTaskRunner);
 };
 
-class DummyWebThread : public blink::WebThread {
- public:
-  DummyWebThread()
-      : thread_id_(base::PlatformThread::CurrentId()),
-        m_dummyScheduler(new blink::WebScheduler()) {}
-
-  virtual void postTask(const blink::WebTraceLocation&, Task*) { NOTREACHED(); }
-
-  virtual void postDelayedTask(const blink::WebTraceLocation&,
-                               Task*,
-                               long long delayMs) {
-    NOTREACHED();
-  }
-
-  virtual bool isCurrentThread() const {
-    return thread_id_ == base::PlatformThread::CurrentId();
-  }
-
-  virtual blink::WebScheduler* scheduler() const {
-    return m_dummyScheduler.get();
-  }
-
- private:
-  base::PlatformThreadId thread_id_;
-  scoped_ptr<blink::WebScheduler> m_dummyScheduler;
-
-  DISALLOW_COPY_AND_ASSIGN(DummyWebThread);
-};
-
 }  // namespace
 
 namespace content {
@@ -120,15 +92,12 @@
 
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
   gin::V8Initializer::LoadV8Snapshot();
+  gin::V8Initializer::LoadV8Natives();
 #endif
 
   scoped_refptr<base::SingleThreadTaskRunner> dummy_task_runner;
   scoped_ptr<base::ThreadTaskRunnerHandle> dummy_task_runner_handle;
-  if (base::MessageLoopProxy::current()) {
-    renderer_scheduler_ = scheduler::RendererScheduler::Create();
-    web_thread_.reset(new scheduler::WebThreadImplForRendererScheduler(
-        renderer_scheduler_.get()));
-  } else {
+  if (!base::ThreadTaskRunnerHandle::IsSet()) {
     // Dummy task runner is initialized here because the blink::initialize
     // creates IsolateHolder which needs the current task runner handle. There
     // should be no task posted to this task runner. The message loop is not
@@ -139,8 +108,11 @@
     dummy_task_runner = make_scoped_refptr(new DummyTaskRunner());
     dummy_task_runner_handle.reset(
         new base::ThreadTaskRunnerHandle(dummy_task_runner));
-    web_thread_.reset(new DummyWebThread());
   }
+  renderer_scheduler_ = make_scoped_ptr(new scheduler::RendererSchedulerImpl(
+      scheduler::LazySchedulerMessageLoopDelegateForTests::Create()));
+  web_thread_.reset(new scheduler::WebThreadImplForRendererScheduler(
+      renderer_scheduler_.get()));
 
   blink::initialize(this);
   blink::setLayoutTestMode(true);
@@ -410,4 +382,10 @@
   base::MessageLoop::current()->Quit();
 }
 
+void TestBlinkWebUnitTestSupport::getPluginList(
+    bool refresh, blink::WebPluginListBuilder* builder) {
+  builder->addPlugin("pdf", "pdf", "pdf-files");
+  builder->addMediaTypeToLastPlugin("application/pdf", "pdf");
+}
+
 }  // namespace content
diff --git a/content/test/test_blink_web_unit_test_support.h b/content/test/test_blink_web_unit_test_support.h
index a466a77..0ed17bd 100644
--- a/content/test/test_blink_web_unit_test_support.h
+++ b/content/test/test_blink_web_unit_test_support.h
@@ -91,6 +91,9 @@
   virtual void enterRunLoop();
   virtual void exitRunLoop();
 
+  virtual void getPluginList(bool refresh,
+                             blink::WebPluginListBuilder* builder);
+
  private:
   MockWebBlobRegistryImpl blob_registry_;
   SimpleWebMimeRegistryImpl mime_registry_;
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index 6badf47b..504ac771 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -72,7 +72,7 @@
 
 void TestRenderFrameHost::InitializeRenderFrameIfNeeded() {
   if (!render_view_host()->IsRenderViewLive()) {
-    RenderViewHostTester::For(render_view_host())->CreateRenderView(
+    RenderViewHostTester::For(render_view_host())->CreateTestRenderView(
         base::string16(), MSG_ROUTING_NONE, MSG_ROUTING_NONE, -1, false);
   }
 }
diff --git a/content/test/test_render_view_host.cc b/content/test/test_render_view_host.cc
index d729fb6e..5e222d1 100644
--- a/content/test/test_render_view_host.cc
+++ b/content/test/test_render_view_host.cc
@@ -236,11 +236,23 @@
     ++*delete_counter_;
 }
 
+bool TestRenderViewHost::CreateTestRenderView(
+    const base::string16& frame_name,
+    int opener_route_id,
+    int proxy_route_id,
+    int32 max_page_id,
+    bool window_was_created_with_opener) {
+  return CreateRenderView(frame_name, opener_route_id, proxy_route_id,
+                          max_page_id, FrameReplicationState(),
+                          window_was_created_with_opener);
+}
+
 bool TestRenderViewHost::CreateRenderView(
     const base::string16& frame_name,
     int opener_route_id,
     int proxy_route_id,
     int32 max_page_id,
+    const FrameReplicationState& replicated_frame_state,
     bool window_was_created_with_opener) {
   DCHECK(!IsRenderViewLive());
   set_renderer_initialized(true);
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h
index d3869de..fc21a57 100644
--- a/content/test/test_render_view_host.h
+++ b/content/test/test_render_view_host.h
@@ -39,6 +39,7 @@
 class SiteInstance;
 class TestRenderFrameHost;
 class TestWebContents;
+struct FrameReplicationState;
 
 // Utility function to initialize FrameHostMsg_DidCommitProvisionalLoad_Params
 // with given parameters.
@@ -232,12 +233,19 @@
   // RenderWidgetHost overrides (same value, but in the Mock* type)
   MockRenderProcessHost* GetProcess() const override;
 
+  bool CreateTestRenderView(const base::string16& frame_name,
+                            int opener_route_id,
+                            int proxy_route_id,
+                            int32 max_page_id,
+                            bool window_was_created_with_opener) override;
+
   // RenderViewHost overrides --------------------------------------------------
 
   bool CreateRenderView(const base::string16& frame_name,
                         int opener_route_id,
                         int proxy_route_id,
                         int32 max_page_id,
+                        const FrameReplicationState& replicated_frame_state,
                         bool window_was_created_with_opener) override;
   bool IsFullscreenGranted() const override;
 
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index 2f35a8b..b852b0b 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -130,6 +130,7 @@
     RenderViewHost* render_view_host,
     int opener_route_id,
     int proxy_routing_id,
+    const FrameReplicationState& replicated_frame_state,
     bool for_main_frame) {
   UpdateMaxPageIDIfNecessary(render_view_host);
   // This will go to a TestRenderViewHost.
@@ -137,7 +138,9 @@
       render_view_host)->CreateRenderView(base::string16(),
                                           opener_route_id,
                                           proxy_routing_id,
-                                          -1, false);
+                                          -1,
+                                          replicated_frame_state,
+                                          false);
   return true;
 }
 
diff --git a/content/test/test_web_contents.h b/content/test/test_web_contents.h
index 53bc82a..de3a103 100644
--- a/content/test/test_web_contents.h
+++ b/content/test/test_web_contents.h
@@ -61,10 +61,12 @@
   bool CrossProcessNavigationPending();
 
   // Prevent interaction with views.
-  bool CreateRenderViewForRenderManager(RenderViewHost* render_view_host,
-                                        int opener_route_id,
-                                        int proxy_routing_id,
-                                        bool for_main_frame) override;
+  bool CreateRenderViewForRenderManager(
+      RenderViewHost* render_view_host,
+      int opener_route_id,
+      int proxy_routing_id,
+      const FrameReplicationState& replicated_frame_state,
+      bool for_main_frame) override;
   void UpdateRenderViewSizeForRenderManager() override {}
 
   // Returns a clone of this TestWebContents. The returned object is also a
diff --git a/content/test/web_contents_observer_sanity_checker.cc b/content/test/web_contents_observer_sanity_checker.cc
index 11e8674c..0b83474 100644
--- a/content/test/web_contents_observer_sanity_checker.cc
+++ b/content/test/web_contents_observer_sanity_checker.cc
@@ -5,6 +5,7 @@
 #include "content/test/web_contents_observer_sanity_checker.h"
 
 #include "base/strings/stringprintf.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/common/frame_messages.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
@@ -42,6 +43,15 @@
     CHECK(false) << "RenderFrameCreated called more than once for routing pair:"
                  << Format(render_frame_host);
   }
+
+  CHECK(render_frame_host->GetProcess()->HasConnection())
+      << "RenderFrameCreated was called for a RenderFrameHost whose render "
+         "process is not currently live, so there's no way for the RenderFrame "
+         "to have been created.";
+  CHECK(
+      static_cast<RenderFrameHostImpl*>(render_frame_host)->IsRenderFrameLive())
+      << "RenderFrameCreated called on for a RenderFrameHost that thinks it is "
+         "not alive.";
 }
 
 void WebContentsObserverSanityChecker::RenderFrameDeleted(
diff --git a/content/test/web_layer_tree_view_impl_for_testing.h b/content/test/web_layer_tree_view_impl_for_testing.h
index 539c3205..63ac66f 100644
--- a/content/test/web_layer_tree_view_impl_for_testing.h
+++ b/content/test/web_layer_tree_view_impl_for_testing.h
@@ -82,6 +82,10 @@
   void DidCommitAndDrawFrame() override {}
   void DidCompleteSwapBuffers() override {}
   void DidCompletePageScaleAnimation() override {}
+  void RecordFrameTimingEvents(
+      scoped_ptr<cc::FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<cc::FrameTimingTracker::MainFrameTimingSet> main_frame_events)
+      override {}
 
   // cc::LayerTreeHostSingleThreadClient implementation.
   void DidPostSwapBuffers() override {}
diff --git a/content/utility/BUILD.gn b/content/utility/BUILD.gn
index 5767b98f..93dae8f 100644
--- a/content/utility/BUILD.gn
+++ b/content/utility/BUILD.gn
@@ -19,8 +19,14 @@
     "//content:export",
     "//content/public/child:child_sources",
     "//content/public/common:common_sources",
+    "//content/public/common:mojo_bindings",
     "//courgette:courgette_lib",
+    "//mojo/application/public/cpp:cpp_for_chromium",
     "//mojo/application/public/interfaces",
+    "//mojo/common",
+    "//mojo/shell",
     "//third_party/WebKit/public:blink_headers",
+    "//third_party/mojo/src/mojo/public/cpp/bindings",
+    "//url",
   ]
 }
diff --git a/content/utility/DEPS b/content/utility/DEPS
index 47166e2..8b49f0ff 100644
--- a/content/utility/DEPS
+++ b/content/utility/DEPS
@@ -2,5 +2,7 @@
   "+components/scheduler/child",
   "+content/child",
   "+content/public/utility",
+  "+mojo/application",
+  "+mojo/shell",
   "+sandbox/win/src",
 ]
diff --git a/content/utility/in_process_utility_thread.cc b/content/utility/in_process_utility_thread.cc
index ab5a229..444b81d 100644
--- a/content/utility/in_process_utility_thread.cc
+++ b/content/utility/in_process_utility_thread.cc
@@ -4,6 +4,9 @@
 
 #include "content/utility/in_process_utility_thread.h"
 
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
 #include "content/child/child_process.h"
 #include "content/utility/utility_thread_impl.h"
 
@@ -28,10 +31,9 @@
 void InProcessUtilityThread::Init() {
   // We need to return right away or else the main thread that started us will
   // hang.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&InProcessUtilityThread::InitInternal,
-                 base::Unretained(this)));
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&InProcessUtilityThread::InitInternal,
+                            base::Unretained(this)));
 }
 
 void InProcessUtilityThread::CleanUp() {
diff --git a/content/utility/utility_process_control_impl.cc b/content/utility/utility_process_control_impl.cc
new file mode 100644
index 0000000..5d12a2e7
--- /dev/null
+++ b/content/utility/utility_process_control_impl.cc
@@ -0,0 +1,54 @@
+// 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 "content/utility/utility_process_control_impl.h"
+
+#include "base/bind.h"
+#include "base/stl_util.h"
+#include "content/public/common/content_client.h"
+#include "content/public/utility/content_utility_client.h"
+#include "content/public/utility/utility_thread.h"
+#include "mojo/shell/static_application_loader.h"
+#include "url/gurl.h"
+
+namespace content {
+
+namespace {
+
+// Called when a static application terminates.
+void QuitProcess() {
+  UtilityThread::Get()->ReleaseProcessIfNeeded();
+}
+
+}  // namespace
+
+UtilityProcessControlImpl::UtilityProcessControlImpl() {
+  ContentUtilityClient::StaticMojoApplicationMap apps;
+  GetContentClient()->utility()->RegisterMojoApplications(&apps);
+  for (const auto& entry : apps) {
+    url_to_loader_map_[entry.first] = new mojo::shell::StaticApplicationLoader(
+        entry.second, base::Bind(&QuitProcess));
+  }
+}
+
+UtilityProcessControlImpl::~UtilityProcessControlImpl() {
+  STLDeleteValues(&url_to_loader_map_);
+}
+
+void UtilityProcessControlImpl::LoadApplication(
+    const mojo::String& url,
+    mojo::InterfaceRequest<mojo::Application> request,
+    const LoadApplicationCallback& callback) {
+  GURL application_url = GURL(url.To<std::string>());
+  auto it = url_to_loader_map_.find(application_url);
+  if (it == url_to_loader_map_.end()) {
+    callback.Run(false);
+    return;
+  }
+
+  callback.Run(true);
+  it->second->Load(application_url, request.Pass());
+}
+
+}  // namespace content
diff --git a/content/utility/utility_process_control_impl.h b/content/utility/utility_process_control_impl.h
new file mode 100644
index 0000000..dcc0a4d6
--- /dev/null
+++ b/content/utility/utility_process_control_impl.h
@@ -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.
+
+#ifndef UTILITY_PROCESS_CONTROL_IMPL_H_
+#define UTILITY_PROCESS_CONTROL_IMPL_H_
+
+#include <map>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/common/process_control.mojom.h"
+#include "mojo/application/public/interfaces/application.mojom.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
+
+class GURL;
+
+namespace mojo {
+namespace shell {
+class ApplicationLoader;
+}  // namespace shell
+}  // namespace mojo
+
+namespace content {
+
+// Implementation of the ProcessControl interface. Exposed to the browser via
+// the utility process's ServiceRegistry.
+class UtilityProcessControlImpl : public ProcessControl {
+ public:
+  UtilityProcessControlImpl();
+  ~UtilityProcessControlImpl() override;
+
+  using URLToLoaderMap = std::map<GURL, mojo::shell::ApplicationLoader*>;
+
+  // ProcessControl:
+  void LoadApplication(const mojo::String& url,
+                       mojo::InterfaceRequest<mojo::Application> request,
+                       const LoadApplicationCallback& callback) override;
+
+ private:
+  URLToLoaderMap url_to_loader_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(UtilityProcessControlImpl);
+};
+
+}  // namespace content
+
+#endif  // UTILITY_PROCESS_CONTROL_IMPL_H_
diff --git a/content/utility/utility_thread_impl.cc b/content/utility/utility_thread_impl.cc
index 1a020ea..00ebc6e 100644
--- a/content/utility/utility_thread_impl.cc
+++ b/content/utility/utility_thread_impl.cc
@@ -15,6 +15,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/utility/content_utility_client.h"
 #include "content/utility/utility_blink_platform_impl.h"
+#include "content/utility/utility_process_control_impl.h"
 #include "ipc/ipc_sync_channel.h"
 #include "third_party/WebKit/public/web/WebKit.h"
 
@@ -85,6 +86,11 @@
     blink::initialize(blink_platform_impl_.get());
   }
   GetContentClient()->utility()->UtilityThreadStarted();
+
+  process_control_.reset(new UtilityProcessControlImpl);
+  service_registry()->AddService(base::Bind(
+      &UtilityThreadImpl::BindProcessControlRequest, base::Unretained(this)));
+
   GetContentClient()->utility()->RegisterMojoServices(service_registry());
 }
 
@@ -135,4 +141,10 @@
 }
 #endif
 
+void UtilityThreadImpl::BindProcessControlRequest(
+    mojo::InterfaceRequest<ProcessControl> request) {
+  DCHECK(process_control_);
+  process_control_bindings_.AddBinding(process_control_.get(), request.Pass());
+}
+
 }  // namespace content
diff --git a/content/utility/utility_thread_impl.h b/content/utility/utility_thread_impl.h
index 3b1d66d..74908cac 100644
--- a/content/utility/utility_thread_impl.h
+++ b/content/utility/utility_thread_impl.h
@@ -10,9 +10,12 @@
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
 #include "content/child/child_thread_impl.h"
 #include "content/common/content_export.h"
+#include "content/common/process_control.mojom.h"
 #include "content/public/utility/utility_thread.h"
+#include "mojo/common/weak_binding_set.h"
 
 namespace base {
 class FilePath;
@@ -21,6 +24,7 @@
 namespace content {
 class BlinkPlatformImpl;
 class UtilityBlinkPlatformImpl;
+class UtilityProcessControlImpl;
 
 #if defined(COMPILER_MSVC)
 // See explanation for other RenderViewHostImpl which is the same issue.
@@ -54,11 +58,20 @@
   void OnLoadPlugins(const std::vector<base::FilePath>& plugin_paths);
 #endif
 
+  void BindProcessControlRequest(
+      mojo::InterfaceRequest<content::ProcessControl> request);
+
   // True when we're running in batch mode.
   bool batch_mode_;
 
   scoped_ptr<UtilityBlinkPlatformImpl> blink_platform_impl_;
 
+  // Process control for Mojo application hosting.
+  scoped_ptr<UtilityProcessControlImpl> process_control_;
+
+  // Bindings to the ProcessControl impl.
+  mojo::WeakBindingSet<ProcessControl> process_control_bindings_;
+
   DISALLOW_COPY_AND_ASSIGN(UtilityThreadImpl);
 };
 
diff --git a/content/utility/webthread_impl_for_utility_thread.cc b/content/utility/webthread_impl_for_utility_thread.cc
index 12c4caa..f72456d 100644
--- a/content/utility/webthread_impl_for_utility_thread.cc
+++ b/content/utility/webthread_impl_for_utility_thread.cc
@@ -4,10 +4,12 @@
 
 #include "content/utility/webthread_impl_for_utility_thread.h"
 
+#include "base/thread_task_runner_handle.h"
+
 namespace content {
 
 WebThreadImplForUtilityThread::WebThreadImplForUtilityThread()
-    : task_runner_(base::MessageLoopProxy::current()),
+    : task_runner_(base::ThreadTaskRunnerHandle::Get()),
       thread_id_(base::PlatformThread::CurrentId()) {
 }
 
diff --git a/device/usb/usb_device.cc b/device/usb/usb_device.cc
index 2be93d9..bd7a7aa 100644
--- a/device/usb/usb_device.cc
+++ b/device/usb/usb_device.cc
@@ -25,12 +25,8 @@
 }
 
 void UsbDevice::CheckUsbAccess(const ResultCallback& callback) {
-  callback.Run(true);
-}
-
-// Like CheckUsbAccess but actually changes the ownership of the device node.
-void UsbDevice::RequestUsbAccess(int interface_id,
-                                 const ResultCallback& callback) {
+  // By default assume that access to the device is allowed. This is implemented
+  // on Chrome OS by checking with permission_broker.
   callback.Run(true);
 }
 
diff --git a/device/usb/usb_device.h b/device/usb/usb_device.h
index 1054a3b..cd5edd22 100644
--- a/device/usb/usb_device.h
+++ b/device/usb/usb_device.h
@@ -43,10 +43,6 @@
   // functions are no-ops and always return true.
   virtual void CheckUsbAccess(const ResultCallback& callback);
 
-  // Like CheckUsbAccess but actually changes the ownership of the device node.
-  virtual void RequestUsbAccess(int interface_id,
-                                const ResultCallback& callback);
-
   // Creates a UsbDeviceHandle for further manipulation.
   virtual void Open(const OpenCallback& callback) = 0;
 
diff --git a/device/usb/usb_device_impl.cc b/device/usb/usb_device_impl.cc
index 217c5c3a..931e505 100644
--- a/device/usb/usb_device_impl.cc
+++ b/device/usb/usb_device_impl.cc
@@ -132,22 +132,23 @@
   client->CheckPathAccess(devnode_, callback);
 }
 
-void UsbDeviceImpl::RequestUsbAccess(int interface_id,
-                                     const ResultCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  chromeos::PermissionBrokerClient* client =
-      chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
-  DCHECK(client) << "Could not get permission broker client.";
-  client->RequestPathAccess(devnode_, interface_id, callback);
-}
-
-#endif
+#endif  // defined(OS_CHROMEOS)
 
 void UsbDeviceImpl::Open(const OpenCallback& callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
+
+#if defined(OS_CHROMEOS)
+  chromeos::PermissionBrokerClient* client =
+      chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
+  DCHECK(client) << "Could not get permission broker client.";
+  client->RequestPathAccess(
+      devnode_, -1,
+      base::Bind(&UsbDeviceImpl::OnPathRequestComplete, this, callback));
+#else
   blocking_task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&UsbDeviceImpl::OpenOnBlockingThread, this, callback));
+#endif  // defined(OS_CHROMEOS)
 }
 
 bool UsbDeviceImpl::Close(scoped_refptr<UsbDeviceHandle> handle) {
@@ -247,6 +248,21 @@
   libusb_free_config_descriptor(platform_config);
 }
 
+#if defined(OS_CHROMEOS)
+
+void UsbDeviceImpl::OnPathRequestComplete(const OpenCallback& callback,
+                                          bool success) {
+  if (success) {
+    blocking_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&UsbDeviceImpl::OpenOnBlockingThread, this, callback));
+  } else {
+    callback.Run(nullptr);
+  }
+}
+
+#endif  // defined(OS_CHROMEOS)
+
 void UsbDeviceImpl::OpenOnBlockingThread(const OpenCallback& callback) {
   PlatformUsbDeviceHandle handle;
   const int rv = libusb_open(platform_device_, &handle);
diff --git a/device/usb/usb_device_impl.h b/device/usb/usb_device_impl.h
index 76ede337..5dd856a 100644
--- a/device/usb/usb_device_impl.h
+++ b/device/usb/usb_device_impl.h
@@ -34,10 +34,7 @@
  public:
 // UsbDevice implementation:
 #if defined(OS_CHROMEOS)
-  // Only overridden on Chrome OS.
   void CheckUsbAccess(const ResultCallback& callback) override;
-  void RequestUsbAccess(int interface_id,
-                        const ResultCallback& callback) override;
 #endif  // OS_CHROMEOS
   void Open(const OpenCallback& callback) override;
   bool Close(scoped_refptr<UsbDeviceHandle> handle) override;
@@ -70,6 +67,9 @@
   void RefreshConfiguration();
 
  private:
+#if defined(OS_CHROMEOS)
+  void OnPathRequestComplete(const OpenCallback& callback, bool success);
+#endif
   void OpenOnBlockingThread(const OpenCallback& callback);
   void Opened(PlatformUsbDeviceHandle platform_handle,
               const OpenCallback& callback);
diff --git a/extensions/browser/api/app_window/app_window_api.cc b/extensions/browser/api/app_window/app_window_api.cc
index 3901d34..81c963f 100644
--- a/extensions/browser/api/app_window/app_window_api.cc
+++ b/extensions/browser/api/app_window/app_window_api.cc
@@ -205,11 +205,14 @@
     if (!GetBoundsSpec(*options, &create_params, &error_))
       return false;
 
-    if (!AppWindowClient::Get()->IsCurrentChannelOlderThanDev() ||
-        extension()->location() == Manifest::COMPONENT) {
-      if (options->type == app_window::WINDOW_TYPE_PANEL) {
-        create_params.window_type = AppWindow::WINDOW_TYPE_PANEL;
-      }
+    if (options->type == app_window::WINDOW_TYPE_PANEL) {
+#if defined(USE_ASH)
+      // Currently panels for v2 apps are only implemented in Ash.
+      create_params.window_type = AppWindow::WINDOW_TYPE_PANEL;
+#else
+      WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_WARNING,
+                     "Panels are not supported on this platform");
+#endif
     }
 
     if (!GetFrameOptions(*options, &create_params))
diff --git a/extensions/browser/api/usb/usb_api.cc b/extensions/browser/api/usb/usb_api.cc
index e85a7a3..d02cadb 100644
--- a/extensions/browser/api/usb/usb_api.cc
+++ b/extensions/browser/api/usb/usb_api.cc
@@ -492,10 +492,10 @@
 
   vendor_id_ = parameters->options.vendor_id;
   product_id_ = parameters->options.product_id;
-  interface_id_ = parameters->options.interface_id.get()
-                      ? *parameters->options.interface_id.get()
-                      : UsbDevicePermissionData::ANY_INTERFACE;
-  UsbDevicePermission::CheckParam param(vendor_id_, product_id_, interface_id_);
+  int interface_id = parameters->options.interface_id.get()
+                         ? *parameters->options.interface_id.get()
+                         : UsbDevicePermissionData::ANY_INTERFACE;
+  UsbDevicePermission::CheckParam param(vendor_id_, product_id_, interface_id);
   if (!extension()->permissions_data()->CheckAPIPermissionWithParam(
           APIPermission::kUsbDevice, &param)) {
     return RespondNow(Error(kErrorPermissionDenied));
@@ -522,24 +522,11 @@
         device->product_id() != product_id_) {
       barrier_.Run();
     } else {
-      device->RequestUsbAccess(
-          interface_id_,
-          base::Bind(&UsbFindDevicesFunction::OnRequestAccessComplete, this,
-                     device));
+      device->Open(base::Bind(&UsbFindDevicesFunction::OnDeviceOpened, this));
     }
   }
 }
 
-void UsbFindDevicesFunction::OnRequestAccessComplete(
-    scoped_refptr<UsbDevice> device,
-    bool success) {
-  if (success) {
-    device->Open(base::Bind(&UsbFindDevicesFunction::OnDeviceOpened, this));
-  } else {
-    barrier_.Run();
-  }
-}
-
 void UsbFindDevicesFunction::OnDeviceOpened(
     scoped_refptr<UsbDeviceHandle> device_handle) {
   if (device_handle.get()) {
@@ -708,23 +695,10 @@
     return RespondNow(Error(kErrorNoDevice));
   }
 
-  device->RequestUsbAccess(
-      -1, /* any interface, unused by the permission broker */
-      base::Bind(&UsbOpenDeviceFunction::OnRequestAccessComplete, this,
-                 device));
+  device->Open(base::Bind(&UsbOpenDeviceFunction::OnDeviceOpened, this));
   return RespondLater();
 }
 
-void UsbOpenDeviceFunction::OnRequestAccessComplete(
-    scoped_refptr<UsbDevice> device,
-    bool success) {
-  if (success) {
-    device->Open(base::Bind(&UsbOpenDeviceFunction::OnDeviceOpened, this));
-  } else {
-    Respond(Error(kErrorPermissionDenied));
-  }
-}
-
 void UsbOpenDeviceFunction::OnDeviceOpened(
     scoped_refptr<UsbDeviceHandle> device_handle) {
   if (!device_handle.get()) {
diff --git a/extensions/browser/api/usb/usb_api.h b/extensions/browser/api/usb/usb_api.h
index c06c5577..f0f1e04 100644
--- a/extensions/browser/api/usb/usb_api.h
+++ b/extensions/browser/api/usb/usb_api.h
@@ -74,14 +74,11 @@
 
   void OnGetDevicesComplete(
       const std::vector<scoped_refptr<device::UsbDevice>>& devices);
-  void OnRequestAccessComplete(scoped_refptr<device::UsbDevice> device,
-                               bool success);
   void OnDeviceOpened(scoped_refptr<device::UsbDeviceHandle> device_handle);
   void OpenComplete();
 
   uint16_t vendor_id_;
   uint16_t product_id_;
-  int interface_id_;
   scoped_ptr<base::ListValue> result_;
   base::Closure barrier_;
 
@@ -156,8 +153,6 @@
   // ExtensionFunction:
   ResponseAction Run() override;
 
-  void OnRequestAccessComplete(scoped_refptr<device::UsbDevice> device,
-                               bool success);
   void OnDeviceOpened(scoped_refptr<device::UsbDeviceHandle> device_handle);
 
   DISALLOW_COPY_AND_ASSIGN(UsbOpenDeviceFunction);
diff --git a/extensions/browser/api/usb/usb_guid_map.h b/extensions/browser/api/usb/usb_guid_map.h
index 2f88bfa5..7ff8fe1 100644
--- a/extensions/browser/api/usb/usb_guid_map.h
+++ b/extensions/browser/api/usb/usb_guid_map.h
@@ -47,6 +47,7 @@
   // BrowserContextKeyedAPI implementation.
   static const char* service_name() { return "UsbGuidMap"; }
   static const bool kServiceIsCreatedWithBrowserContext = false;
+  static const bool kServiceRedirectedInIncognito = true;
 
   // UsbService::Observer implementation.
   void OnDeviceRemovedCleanup(scoped_refptr<device::UsbDevice> device) override;
diff --git a/extensions/browser/extension_host.cc b/extensions/browser/extension_host.cc
index 0b501a6..124a8fd 100644
--- a/extensions/browser/extension_host.cc
+++ b/extensions/browser/extension_host.cc
@@ -153,12 +153,9 @@
             "464206 ExtensionHost::CreateRenderViewNow2"));
     DCHECK(IsRenderViewLive());
     if (extension_) {
-      std::string group_name = base::FieldTrialList::FindFullName(
-          "ThrottleExtensionBackgroundPages");
-      if ((group_name == "ThrottlePersistent" &&
-           extensions::BackgroundInfo::HasPersistentBackgroundPage(
-               extension_)) ||
-          group_name == "ThrottleAll") {
+      if (extensions::BackgroundInfo::HasPersistentBackgroundPage(extension_) &&
+          base::FieldTrialList::FindFullName(
+              "ThrottleExtensionBackgroundPages") != "Disabled") {
         host_contents_->WasHidden();
       }
     }
diff --git a/extensions/browser/extension_registry.cc b/extensions/browser/extension_registry.cc
index 65c8b5e..c59d635 100644
--- a/extensions/browser/extension_registry.cc
+++ b/extensions/browser/extension_registry.cc
@@ -132,6 +132,11 @@
   return NULL;
 }
 
+const Extension* ExtensionRegistry::GetInstalledExtension(
+    const std::string& id) const {
+  return GetExtensionById(id, ExtensionRegistry::EVERYTHING);
+}
+
 bool ExtensionRegistry::AddEnabled(
     const scoped_refptr<const Extension>& extension) {
   return enabled_extensions_.Insert(extension);
diff --git a/extensions/browser/extension_registry.h b/extensions/browser/extension_registry.h
index fa5b4936..fb7a9a50 100644
--- a/extensions/browser/extension_registry.h
+++ b/extensions/browser/extension_registry.h
@@ -123,6 +123,10 @@
   const Extension* GetExtensionById(const std::string& id,
                                     int include_mask) const;
 
+  // Looks up an extension by ID, regardless of whether it's enabled,
+  // disabled, blacklisted, or terminated.
+  const Extension* GetInstalledExtension(const std::string& id) const;
+
   // Adds the specified extension to the enabled set. The registry becomes an
   // owner. Any previous extension with the same ID is removed.
   // Returns true if there is no previous extension.
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc
index 7a5f4f2..8960f4c 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -118,6 +118,10 @@
     case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
     case base::TERMINATION_STATUS_STILL_RUNNING:
       return "abnormal";
+#if defined(OS_CHROMEOS)
+    case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
+      return "oom killed";
+#endif
     case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
       return "killed";
     case base::TERMINATION_STATUS_PROCESS_CRASHED:
diff --git a/extensions/browser/script_executor.cc b/extensions/browser/script_executor.cc
index db5de75f..2b616461 100644
--- a/extensions/browser/script_executor.cc
+++ b/extensions/browser/script_executor.cc
@@ -35,25 +35,20 @@
  public:
   Handler(base::ObserverList<ScriptExecutionObserver>* script_observers,
           content::WebContents* web_contents,
-          ExtensionMsg_ExecuteCode_Params* params,
+          const ExtensionMsg_ExecuteCode_Params& params,
           ScriptExecutor::FrameScope scope,
-          int* request_id_counter,
           const ScriptExecutor::ExecuteScriptCallback& callback)
       : content::WebContentsObserver(web_contents),
         script_observers_(AsWeakPtr(script_observers)),
-        host_id_(params->host_id),
-        main_request_id_((*request_id_counter)++),
-        sub_request_id_(scope == ScriptExecutor::ALL_FRAMES ?
-                            (*request_id_counter)++ : -1),
+        host_id_(params.host_id),
+        request_id_(params.request_id),
         num_pending_(0),
         callback_(callback) {
-    content::RenderFrameHost* main_frame = web_contents->GetMainFrame();
     if (scope == ScriptExecutor::ALL_FRAMES) {
       web_contents->ForEachFrame(base::Bind(&Handler::SendExecuteCode,
-                                            base::Unretained(this), params,
-                                            main_frame));
+                                            base::Unretained(this), params));
     } else {
-      SendExecuteCode(params, main_frame, main_frame);
+      SendExecuteCode(params, web_contents->GetMainFrame());
     }
   }
 
@@ -66,7 +61,8 @@
     Finish(kRendererDestroyed, GURL(), base::ListValue());
   }
 
-  bool OnMessageReceived(const IPC::Message& message) override {
+  bool OnMessageReceived(const IPC::Message& message,
+                         content::RenderFrameHost* render_frame_host) override {
     // Unpack by hand to check the request_id, since there may be multiple
     // requests in flight but only one is for this.
     if (message.type() != ExtensionHostMsg_ExecuteCodeFinished::ID)
@@ -76,12 +72,10 @@
     base::PickleIterator iter(message);
     CHECK(iter.ReadInt(&message_request_id));
 
-    if (message_request_id != main_request_id_ &&
-        message_request_id != sub_request_id_) {
+    if (message_request_id != request_id_)
       return false;
-    }
 
-    IPC_BEGIN_MESSAGE_MAP(Handler, message)
+    IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(Handler, message, render_frame_host)
       IPC_MESSAGE_HANDLER(ExtensionHostMsg_ExecuteCodeFinished,
                           OnExecuteCodeFinished)
     IPC_END_MESSAGE_MAP()
@@ -90,22 +84,21 @@
 
   // Sends an ExecuteCode message to the given frame host, and increments
   // the number of pending messages.
-  void SendExecuteCode(ExtensionMsg_ExecuteCode_Params* params,
-                       content::RenderFrameHost* main_frame,
+  void SendExecuteCode(const ExtensionMsg_ExecuteCode_Params& params,
                        content::RenderFrameHost* frame) {
     ++num_pending_;
-    params->request_id =
-        main_frame == frame ? main_request_id_ : sub_request_id_;
-    frame->Send(new ExtensionMsg_ExecuteCode(frame->GetRoutingID(), *params));
+    frame->Send(new ExtensionMsg_ExecuteCode(frame->GetRoutingID(), params));
   }
 
   // Handles the ExecuteCodeFinished message.
-  void OnExecuteCodeFinished(int request_id,
+  void OnExecuteCodeFinished(content::RenderFrameHost* render_frame_host,
+                             int request_id,
                              const std::string& error,
                              const GURL& on_url,
                              const base::ListValue& result_list) {
-    DCHECK_NE(-1, request_id);
-    bool is_main_frame = request_id == main_request_id_;
+    DCHECK_EQ(request_id_, request_id);
+    DCHECK_GT(num_pending_, 0);
+    bool is_main_frame = web_contents()->GetMainFrame() == render_frame_host;
 
     // Set the result, if there is one.
     const base::Value* script_value = nullptr;
@@ -152,13 +145,8 @@
   // The id of the host (the extension or the webui) doing the injection.
   HostID host_id_;
 
-  // The request id of the injection into the main frame.
-  int main_request_id_;
-
-  // The request id of the injection into any sub frames. We need a separate id
-  // for these so that we know which frame to use as the first result, and which
-  // error (if any) to use.
-  int sub_request_id_;
+  // The request id of the injection.
+  int request_id_;
 
   // The number of still-running injections.
   int num_pending_;
@@ -220,6 +208,7 @@
   }
 
   ExtensionMsg_ExecuteCode_Params params;
+  params.request_id = next_request_id_++;
   params.host_id = host_id;
   params.is_javascript = (script_type == JAVASCRIPT);
   params.code = code;
@@ -233,8 +222,7 @@
   params.user_gesture = user_gesture;
 
   // Handler handles IPCs and deletes itself on completion.
-  new Handler(script_observers_, web_contents_, &params, frame_scope,
-              &next_request_id_, callback);
+  new Handler(script_observers_, web_contents_, params, frame_scope, callback);
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/updater/extension_downloader.cc b/extensions/browser/updater/extension_downloader.cc
index 08e4f8f..a796149 100644
--- a/extensions/browser/updater/extension_downloader.cc
+++ b/extensions/browser/updater/extension_downloader.cc
@@ -306,8 +306,8 @@
   GURL update_url(extension_update_url);
   // Skip extensions with non-empty invalid update URLs.
   if (!update_url.is_empty() && !update_url.is_valid()) {
-    LOG(WARNING) << "Extension " << id << " has invalid update url "
-                 << update_url;
+    DLOG(WARNING) << "Extension " << id << " has invalid update url "
+                  << update_url;
     return false;
   }
 
@@ -318,7 +318,7 @@
 
   // Skip extensions with empty IDs.
   if (id.empty()) {
-    LOG(WARNING) << "Found extension with empty ID";
+    DLOG(WARNING) << "Found extension with empty ID";
     return false;
   }
 
@@ -676,9 +676,9 @@
             update->browser_min_version)) {
       // TODO(asargent) - We may want this to show up in the extensions UI
       // eventually. (http://crbug.com/12547).
-      LOG(WARNING) << "Updated version of extension " << id
-                   << " available, but requires chrome version "
-                   << update->browser_min_version;
+      DLOG(WARNING) << "Updated version of extension " << id
+                    << " available, but requires chrome version "
+                    << update->browser_min_version;
       continue;
     }
     VLOG(2) << "will try to update " << id;
@@ -691,8 +691,8 @@
     scoped_ptr<ExtensionFetch> fetch_data) {
   if (!fetch_data->url.is_valid()) {
     // TODO(asargent): This can sometimes be invalid. See crbug.com/130881.
-    LOG(ERROR) << "Invalid URL: '" << fetch_data->url.possibly_invalid_spec()
-               << "' for extension " << fetch_data->id;
+    DLOG(WARNING) << "Invalid URL: '" << fetch_data->url.possibly_invalid_spec()
+                  << "' for extension " << fetch_data->id;
     return;
   }
 
diff --git a/extensions/common/extension_messages.h b/extensions/common/extension_messages.h
index bdae495..718ab68 100644
--- a/extensions/common/extension_messages.h
+++ b/extensions/common/extension_messages.h
@@ -427,7 +427,7 @@
 // Notifies the renderer that the current tab is an extension page (we limit
 // what other extensions can do on these pages).
 IPC_MESSAGE_ROUTED1(ExtensionMsg_SetTabExtensionOwner,
-                    std::string /* extension_id */);
+                    std::string /* extension_id */)
 
 // Notifies the renderer that extensions were loaded in the browser.
 IPC_MESSAGE_CONTROL1(ExtensionMsg_Loaded,
diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi
index 7457d7b..de96657 100644
--- a/extensions/extensions.gypi
+++ b/extensions/extensions.gypi
@@ -976,8 +976,6 @@
       'renderer/set_icon_natives.h',
       'renderer/static_v8_external_one_byte_string_resource.cc',
       'renderer/static_v8_external_one_byte_string_resource.h',
-      'renderer/tab_finder.cc',
-      'renderer/tab_finder.h',
       'renderer/test_features_native_handler.cc',
       'renderer/test_features_native_handler.h',
       'renderer/user_gestures_native_handler.cc',
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index fbff53b..cf4bb57 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -76,7 +76,6 @@
 #include "extensions/renderer/script_injection_manager.h"
 #include "extensions/renderer/send_request_natives.h"
 #include "extensions/renderer/set_icon_natives.h"
-#include "extensions/renderer/tab_finder.h"
 #include "extensions/renderer/test_features_native_handler.h"
 #include "extensions/renderer/user_gestures_native_handler.h"
 #include "extensions/renderer/utils_native_handler.h"
@@ -993,16 +992,6 @@
                                                 const URLPatternSet& new_hosts,
                                                 bool update_origin_whitelist,
                                                 int tab_id) {
-  // Check against the URL to avoid races. If we can't find the tab, it's
-  // because this is an extension's background page (run in a different
-  // process) - in this case, we can't perform the security check. However,
-  // since activeTab is only granted via user action, this isn't a huge concern.
-  content::RenderView* render_view = TabFinder::Find(tab_id);
-  if (render_view &&
-      render_view->GetWebView()->mainFrame()->document().url() != visible_url) {
-    return;
-  }
-
   const Extension* extension = extensions_.GetByID(extension_id);
   if (!extension)
     return;
diff --git a/extensions/renderer/extension_frame_helper.cc b/extensions/renderer/extension_frame_helper.cc
index c46ac3688..bcfcf42 100644
--- a/extensions/renderer/extension_frame_helper.cc
+++ b/extensions/renderer/extension_frame_helper.cc
@@ -19,6 +19,7 @@
                                            Dispatcher* extension_dispatcher)
     : content::RenderFrameObserver(render_frame),
       content::RenderFrameObserverTracker<ExtensionFrameHelper>(render_frame),
+      tab_id_(-1),
       extension_dispatcher_(extension_dispatcher) {}
 
 ExtensionFrameHelper::~ExtensionFrameHelper() {
@@ -49,6 +50,7 @@
     IPC_MESSAGE_HANDLER(ExtensionMsg_DeliverMessage, OnExtensionDeliverMessage)
     IPC_MESSAGE_HANDLER(ExtensionMsg_DispatchOnDisconnect,
                         OnExtensionDispatchOnDisconnect)
+    IPC_MESSAGE_HANDLER(ExtensionMsg_SetTabId, OnExtensionSetTabId)
     IPC_MESSAGE_HANDLER(ExtensionMsg_SetTabExtensionOwner,
                         OnSetTabExtensionOwner)
     IPC_MESSAGE_UNHANDLED(handled = false)
@@ -93,6 +95,12 @@
       render_frame());
 }
 
+void ExtensionFrameHelper::OnExtensionSetTabId(int tab_id) {
+  CHECK_EQ(tab_id_, -1);
+  CHECK_GE(tab_id, 0);
+  tab_id_ = tab_id;
+}
+
 void ExtensionFrameHelper::OnSetTabExtensionOwner(
     const std::string& extension_id) {
   tab_extension_owner_id_ = extension_id;
diff --git a/extensions/renderer/extension_frame_helper.h b/extensions/renderer/extension_frame_helper.h
index b28458f2..7b83719 100644
--- a/extensions/renderer/extension_frame_helper.h
+++ b/extensions/renderer/extension_frame_helper.h
@@ -26,6 +26,7 @@
                        Dispatcher* extension_dispatcher);
   ~ExtensionFrameHelper() override;
 
+  int tab_id() const { return tab_id_; }
   const std::string& tab_extension_owner_id() const {
     return tab_extension_owner_id_;
   }
@@ -51,8 +52,12 @@
                                  const Message& message);
   void OnExtensionDispatchOnDisconnect(int port_id,
                                        const std::string& error_message);
+  void OnExtensionSetTabId(int tab_id);
   void OnSetTabExtensionOwner(const std::string& extension_id);
 
+  // The id of the tab the render frame is attached to.
+  int tab_id_;
+
   // The id of the extension that "owns" the tab if this is a chrome-extension
   // page. If it's not a chrome-extension page, |tab_extension_owner_id_| is
   // empty.
diff --git a/extensions/renderer/extension_helper.cc b/extensions/renderer/extension_helper.cc
index 82a7e6f..518c4f20 100644
--- a/extensions/renderer/extension_helper.cc
+++ b/extensions/renderer/extension_helper.cc
@@ -121,7 +121,6 @@
       content::RenderViewObserverTracker<ExtensionHelper>(render_view),
       dispatcher_(dispatcher),
       view_type_(VIEW_TYPE_INVALID),
-      tab_id_(-1),
       browser_window_id_(-1) {
   // Lifecycle managed by RenderViewObserver.
   new AutomationApiHelper(render_view);
@@ -136,7 +135,6 @@
     IPC_MESSAGE_HANDLER(ExtensionMsg_Response, OnExtensionResponse)
     IPC_MESSAGE_HANDLER(ExtensionMsg_MessageInvoke, OnExtensionMessageInvoke)
     IPC_MESSAGE_HANDLER(ExtensionMsg_SetFrameName, OnSetFrameName)
-    IPC_MESSAGE_HANDLER(ExtensionMsg_SetTabId, OnSetTabId)
     IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateBrowserWindowId,
                         OnUpdateBrowserWindowId)
     IPC_MESSAGE_HANDLER(ExtensionMsg_NotifyRenderViewType,
@@ -205,12 +203,6 @@
     web_view->mainFrame()->setName(blink::WebString::fromUTF8(name));
 }
 
-void ExtensionHelper::OnSetTabId(int init_tab_id) {
-  CHECK_EQ(tab_id_, -1);
-  CHECK_GE(init_tab_id, 0);
-  tab_id_ = init_tab_id;
-}
-
 void ExtensionHelper::OnUpdateBrowserWindowId(int window_id) {
   browser_window_id_ = window_id;
 }
diff --git a/extensions/renderer/extension_helper.h b/extensions/renderer/extension_helper.h
index 5acc30e..f186056a 100644
--- a/extensions/renderer/extension_helper.h
+++ b/extensions/renderer/extension_helper.h
@@ -45,7 +45,6 @@
   ExtensionHelper(content::RenderView* render_view, Dispatcher* dispatcher);
   ~ExtensionHelper() override;
 
-  int tab_id() const { return tab_id_; }
   int browser_window_id() const { return browser_window_id_; }
   ViewType view_type() const { return view_type_; }
   Dispatcher* dispatcher() const { return dispatcher_; }
@@ -70,7 +69,6 @@
                                 const base::ListValue& args,
                                 bool user_gesture);
   void OnNotifyRendererViewType(ViewType view_type);
-  void OnSetTabId(int tab_id);
   void OnUpdateBrowserWindowId(int window_id);
   void OnAddMessageToConsole(content::ConsoleMessageLevel level,
                              const std::string& message);
@@ -82,9 +80,6 @@
   // Type of view attached with RenderView.
   ViewType view_type_;
 
-  // Id of the tab which the RenderView is attached to.
-  int tab_id_;
-
   // Id number of browser window which RenderView is attached to.
   int browser_window_id_;
 
diff --git a/extensions/renderer/programmatic_script_injector.cc b/extensions/renderer/programmatic_script_injector.cc
index db2fdcc6..bc94d04 100644
--- a/extensions/renderer/programmatic_script_injector.cc
+++ b/extensions/renderer/programmatic_script_injector.cc
@@ -9,7 +9,6 @@
 #include "base/values.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/renderer/render_frame.h"
-#include "content/public/renderer/render_view.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/common/manifest_constants.h"
@@ -18,20 +17,21 @@
 #include "extensions/renderer/script_context.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebScriptSource.h"
 
 namespace extensions {
 
 ProgrammaticScriptInjector::ProgrammaticScriptInjector(
     const ExtensionMsg_ExecuteCode_Params& params,
-    blink::WebFrame* web_frame)
+    content::RenderFrame* render_frame)
     : params_(new ExtensionMsg_ExecuteCode_Params(params)),
-      url_(ScriptContext::GetDataSourceURLForFrame(web_frame)),
-      render_view_(content::RenderView::FromWebView(web_frame->view())),
+      url_(ScriptContext::GetDataSourceURLForFrame(
+          render_frame->GetWebFrame())),
+      render_frame_(render_frame),
       finished_(false) {
   effective_url_ = ScriptContext::GetEffectiveDocumentURL(
-      web_frame, url_, params.match_about_blank);
+      render_frame->GetWebFrame(), url_, params.match_about_blank);
 }
 
 ProgrammaticScriptInjector::~ProgrammaticScriptInjector() {
@@ -66,12 +66,8 @@
 
 PermissionsData::AccessType ProgrammaticScriptInjector::CanExecuteOnFrame(
     const InjectionHost* injection_host,
-    blink::WebFrame* frame,
+    blink::WebLocalFrame* frame,
     int tab_id) const {
-  // It doesn't make sense to inject a script into a remote frame or a frame
-  // with a null document.
-  if (frame->isWebRemoteFrame() || frame->document().isNull())
-    return PermissionsData::ACCESS_DENIED;
   GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL(
       frame, frame->document().url(), params_->match_about_blank);
   if (params_->is_web_view) {
@@ -154,8 +150,8 @@
   DCHECK(!finished_);
   finished_ = true;
 
-  render_view_->Send(new ExtensionHostMsg_ExecuteCodeFinished(
-      render_view_->GetRoutingID(),
+  render_frame_->Send(new ExtensionHostMsg_ExecuteCodeFinished(
+      render_frame_->GetRoutingID(),
       params_->request_id,
       error,
       url_,
diff --git a/extensions/renderer/programmatic_script_injector.h b/extensions/renderer/programmatic_script_injector.h
index 8caca0f..7c3775a 100644
--- a/extensions/renderer/programmatic_script_injector.h
+++ b/extensions/renderer/programmatic_script_injector.h
@@ -13,12 +13,8 @@
 
 struct ExtensionMsg_ExecuteCode_Params;
 
-namespace blink {
-class WebFrame;
-}
-
 namespace content {
-class RenderView;
+class RenderFrame;
 }
 
 namespace extensions {
@@ -27,7 +23,7 @@
 class ProgrammaticScriptInjector : public ScriptInjector {
  public:
   ProgrammaticScriptInjector(const ExtensionMsg_ExecuteCode_Params& params,
-                             blink::WebFrame* web_frame);
+                             content::RenderFrame* render_frame);
   ~ProgrammaticScriptInjector() override;
 
  private:
@@ -40,7 +36,7 @@
   bool ShouldInjectCss(UserScript::RunLocation run_location) const override;
   PermissionsData::AccessType CanExecuteOnFrame(
       const InjectionHost* injection_host,
-      blink::WebFrame* web_frame,
+      blink::WebLocalFrame* web_frame,
       int tab_id) const override;
   std::vector<blink::WebScriptSource> GetJsSources(
       UserScript::RunLocation run_location) const override;
@@ -70,8 +66,8 @@
   // security decisions, to avoid race conditions (e.g. due to navigation).
   GURL effective_url_;
 
-  // The RenderView to which we send the response upon completion.
-  content::RenderView* render_view_;
+  // The RenderFrame to which we send the response upon completion.
+  content::RenderFrame* render_frame_;
 
   // The results of the script execution.
   base::ListValue results_;
diff --git a/extensions/renderer/script_injection.cc b/extensions/renderer/script_injection.cc
index 1c342c4..12d7cfd 100644
--- a/extensions/renderer/script_injection.cc
+++ b/extensions/renderer/script_injection.cc
@@ -11,20 +11,17 @@
 #include "base/timer/elapsed_timer.h"
 #include "base/values.h"
 #include "content/public/child/v8_value_converter.h"
-#include "content/public/renderer/render_view.h"
+#include "content/public/renderer/render_frame.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/common/host_id.h"
-#include "extensions/common/manifest_handlers/csp_info.h"
 #include "extensions/renderer/dom_activity_logger.h"
 #include "extensions/renderer/extension_groups.h"
-#include "extensions/renderer/extension_injection_host.h"
 #include "extensions/renderer/extensions_renderer_client.h"
 #include "extensions/renderer/script_injection_callback.h"
 #include "extensions/renderer/scripts_run_info.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
-#include "third_party/WebKit/public/web/WebScopedUserGesture.h"
 #include "third_party/WebKit/public/web/WebScriptSource.h"
 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
 #include "url/gurl.h"
@@ -98,18 +95,19 @@
 
 ScriptInjection::ScriptInjection(
     scoped_ptr<ScriptInjector> injector,
-    blink::WebLocalFrame* web_frame,
+    content::RenderFrame* render_frame,
     scoped_ptr<const InjectionHost> injection_host,
     UserScript::RunLocation run_location,
     int tab_id)
     : injector_(injector.Pass()),
-      web_frame_(web_frame),
+      render_frame_(render_frame),
       injection_host_(injection_host.Pass()),
       run_location_(run_location),
       tab_id_(tab_id),
       request_id_(kInvalidRequestId),
       complete_(false),
-      did_inject_js_(false) {
+      did_inject_js_(false),
+      weak_ptr_factory_(this) {
   CHECK(injection_host_.get());
 }
 
@@ -135,8 +133,9 @@
     return INJECTION_FINISHED;  // We're done.
   }
 
+  blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
   switch (injector_->CanExecuteOnFrame(
-      injection_host_.get(), web_frame_, tab_id_)) {
+      injection_host_.get(), web_frame, tab_id_)) {
     case PermissionsData::ACCESS_DENIED:
       NotifyWillNotInject(ScriptInjector::NOT_ALLOWED);
       return INJECTION_FINISHED;  // We're done.
@@ -144,7 +143,7 @@
       // Note: we don't consider ACCESS_WITHHELD for child frames because there
       // is nowhere to surface a request for a child frame.
       // TODO(devlin): We should ask for permission somehow. crbug.com/491402.
-      if (web_frame_->parent()) {
+      if (web_frame->parent()) {
         NotifyWillNotInject(ScriptInjector::NOT_ALLOWED);
         return INJECTION_FINISHED;
       }
@@ -179,14 +178,11 @@
 }
 
 void ScriptInjection::SendInjectionMessage(bool request_permission) {
-  content::RenderView* render_view =
-      content::RenderView::FromWebView(web_frame()->top()->view());
-
   // If we are just notifying the browser of the injection, then send an
   // invalid request (which is treated like a notification).
   request_id_ = request_permission ? g_next_pending_id++ : kInvalidRequestId;
-  render_view->Send(new ExtensionHostMsg_RequestScriptInjectionPermission(
-      render_view->GetRoutingID(),
+  render_frame_->Send(new ExtensionHostMsg_RequestScriptInjectionPermission(
+      render_frame_->GetRoutingID(),
       host_id().id(),
       injector_->script_type(),
       request_id_));
@@ -212,9 +208,9 @@
   DCHECK(should_inject_js || should_inject_css);
 
   if (should_inject_js)
-    InjectJs(web_frame_);
+    InjectJs();
   if (should_inject_css)
-    InjectCss(web_frame_);
+    InjectCss();
 
   complete_ = did_inject_js_ || !should_inject_js;
 
@@ -228,19 +224,22 @@
   return complete_ ? INJECTION_FINISHED : INJECTION_BLOCKED;
 }
 
-void ScriptInjection::InjectJs(blink::WebLocalFrame* frame) {
+void ScriptInjection::InjectJs() {
   DCHECK(!did_inject_js_);
+  blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
   std::vector<blink::WebScriptSource> sources =
       injector_->GetJsSources(run_location_);
   bool in_main_world = injector_->ShouldExecuteInMainWorld();
   int world_id = in_main_world
                      ? DOMActivityLogger::kMainWorldId
                      : GetIsolatedWorldIdForInstance(injection_host_.get(),
-                                                     frame);
+                                                     web_frame);
   bool is_user_gesture = injector_->IsUserGesture();
 
   scoped_ptr<blink::WebScriptExecutionCallback> callback(
-      new ScriptInjectionCallback(this, frame));
+      new ScriptInjectionCallback(
+          base::Bind(&ScriptInjection::OnJsInjectionCompleted,
+                     weak_ptr_factory_.GetWeakPtr())));
 
   base::ElapsedTimer exec_timer;
   if (injection_host_->id().type() == HostID::EXTENSIONS)
@@ -249,16 +248,17 @@
     // We only inject in the main world for javascript: urls.
     DCHECK_EQ(1u, sources.size());
 
-    frame->requestExecuteScriptAndReturnValue(sources.front(),
-                                              is_user_gesture,
-                                              callback.release());
+    web_frame->requestExecuteScriptAndReturnValue(sources.front(),
+                                                  is_user_gesture,
+                                                  callback.release());
   } else {
-    frame->requestExecuteScriptInIsolatedWorld(world_id,
-                                               &sources.front(),
-                                               sources.size(),
-                                               EXTENSION_GROUP_CONTENT_SCRIPTS,
-                                               is_user_gesture,
-                                               callback.release());
+    web_frame->requestExecuteScriptInIsolatedWorld(
+        world_id,
+        &sources.front(),
+        sources.size(),
+        EXTENSION_GROUP_CONTENT_SCRIPTS,
+        is_user_gesture,
+        callback.release());
   }
 
   if (injection_host_->id().type() == HostID::EXTENSIONS)
@@ -266,7 +266,6 @@
 }
 
 void ScriptInjection::OnJsInjectionCompleted(
-    blink::WebLocalFrame* frame,
     const blink::WebVector<v8::Local<v8::Value> >& results) {
   DCHECK(!did_inject_js_);
 
@@ -280,7 +279,8 @@
       // here. V8ValueConverterImpl shouldn't actually care about the
       // context scope, and it switches to v8::Object's creation context
       // when encountered.
-      v8::Local<v8::Context> context = frame->mainWorldScriptContext();
+      v8::Local<v8::Context> context =
+          render_frame_->GetWebFrame()->mainWorldScriptContext();
       execution_result_.reset(v8_converter->FromV8Value(results[0], context));
     }
     if (!execution_result_.get())
@@ -297,11 +297,12 @@
   }
 }
 
-void ScriptInjection::InjectCss(blink::WebLocalFrame* frame) {
+void ScriptInjection::InjectCss() {
   std::vector<std::string> css_sources =
       injector_->GetCssSources(run_location_);
+  blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
   for (const std::string& css : css_sources)
-    frame->document().insertStyleSheet(blink::WebString::fromUTF8(css));
+    web_frame->document().insertStyleSheet(blink::WebString::fromUTF8(css));
 }
 
 }  // namespace extensions
diff --git a/extensions/renderer/script_injection.h b/extensions/renderer/script_injection.h
index 1b161b0c..ccb4d1f3 100644
--- a/extensions/renderer/script_injection.h
+++ b/extensions/renderer/script_injection.h
@@ -9,6 +9,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "extensions/common/user_script.h"
 #include "extensions/renderer/injection_host.h"
 #include "extensions/renderer/script_injector.h"
@@ -16,17 +17,19 @@
 struct HostID;
 
 namespace blink {
-class WebLocalFrame;
 template<typename T> class WebVector;
 }
 
+namespace content {
+class RenderFrame;
+}
+
 namespace v8 {
 class Value;
 template <class T> class Local;
 }
 
 namespace extensions {
-class ScriptInjectionManager;
 struct ScriptsRunInfo;
 
 // A script wrapper which is aware of whether or not it is allowed to execute,
@@ -47,10 +50,8 @@
   // Remove the isolated world associated with the given injection host.
   static void RemoveIsolatedWorld(const std::string& host_id);
 
-  // TODO(devlin): This and its *ScriptInjector brethren, should take take a
-  // RenderFrame, instead of a WebFrame.
   ScriptInjection(scoped_ptr<ScriptInjector> injector,
-                  blink::WebLocalFrame* web_frame,
+                  content::RenderFrame* render_frame,
                   scoped_ptr<const InjectionHost> injection_host,
                   UserScript::RunLocation run_location,
                   int tab_id);
@@ -77,13 +78,8 @@
   // Resets the pointer of the injection host when the host is gone.
   void OnHostRemoved();
 
-  // Called when JS injection for the given frame has been completed.
-  void OnJsInjectionCompleted(
-      blink::WebLocalFrame* frame,
-      const blink::WebVector<v8::Local<v8::Value> >& results);
-
   // Accessors.
-  blink::WebLocalFrame* web_frame() const { return web_frame_; }
+  content::RenderFrame* render_frame() const { return render_frame_; }
   const HostID& host_id() const { return injection_host_->id(); }
   int64 request_id() const { return request_id_; }
 
@@ -96,11 +92,15 @@
   // otherwise INJECTION_BLOCKED.
   InjectionResult Inject(ScriptsRunInfo* scripts_run_info);
 
-  // Inject any JS scripts into the |frame|.
-  void InjectJs(blink::WebLocalFrame* frame);
+  // Inject any JS scripts into the frame for the injection.
+  void InjectJs();
 
-  // Inject any CSS source into the |frame|.
-  void InjectCss(blink::WebLocalFrame* frame);
+  // Called when JS injection for the given frame has been completed.
+  void OnJsInjectionCompleted(
+      const blink::WebVector<v8::Local<v8::Value> >& results);
+
+  // Inject any CSS source into the frame for the injection.
+  void InjectCss();
 
   // Notify that we will not inject, and mark it as acknowledged.
   void NotifyWillNotInject(ScriptInjector::InjectFailureReason reason);
@@ -108,8 +108,8 @@
   // The injector for this injection.
   scoped_ptr<ScriptInjector> injector_;
 
-  // The (main) WebFrame into which this should inject the script.
-  blink::WebLocalFrame* web_frame_;
+  // The RenderFrame into which this should inject the script.
+  content::RenderFrame* render_frame_;
 
   // The associated injection host.
   scoped_ptr<const InjectionHost> injection_host_;
@@ -137,6 +137,8 @@
   // The callback to run upon completing asynchronously.
   CompletionCallback async_completion_callback_;
 
+  base::WeakPtrFactory<ScriptInjection> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(ScriptInjection);
 };
 
diff --git a/extensions/renderer/script_injection_callback.cc b/extensions/renderer/script_injection_callback.cc
index 45d3b0d..8b911d1c 100644
--- a/extensions/renderer/script_injection_callback.cc
+++ b/extensions/renderer/script_injection_callback.cc
@@ -4,15 +4,11 @@
 
 #include "extensions/renderer/script_injection_callback.h"
 
-#include "extensions/renderer/script_injection.h"
-
 namespace extensions {
 
 ScriptInjectionCallback::ScriptInjectionCallback(
-    ScriptInjection* injection,
-    blink::WebLocalFrame* web_frame)
-    : injection_(injection),
-      web_frame_(web_frame) {
+    const CompleteCallback& injection_completed_callback)
+    : injection_completed_callback_(injection_completed_callback) {
 }
 
 ScriptInjectionCallback::~ScriptInjectionCallback() {
@@ -20,7 +16,7 @@
 
 void ScriptInjectionCallback::completed(
     const blink::WebVector<v8::Local<v8::Value> >& result) {
-  injection_->OnJsInjectionCompleted(web_frame_, result);
+  injection_completed_callback_.Run(result);
   delete this;
 }
 
diff --git a/extensions/renderer/script_injection_callback.h b/extensions/renderer/script_injection_callback.h
index 371c17c..1481927 100644
--- a/extensions/renderer/script_injection_callback.h
+++ b/extensions/renderer/script_injection_callback.h
@@ -5,34 +5,34 @@
 #ifndef EXTENSIONS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
 #define EXTENSIONS_RENDERER_SCRIPT_INJECTION_CALLBACK_H_
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "third_party/WebKit/public/web/WebScriptExecutionCallback.h"
 #include "v8/include/v8.h"
 
 namespace blink {
-class WebLocalFrame;
 template<typename T> class WebVector;
 }
 
 namespace extensions {
-class ScriptInjection;
 
 // A wrapper around a callback to notify a script injection when injection
 // completes.
 // This class manages its own lifetime.
 class ScriptInjectionCallback : public blink::WebScriptExecutionCallback {
  public:
-  ScriptInjectionCallback(ScriptInjection* injection,
-                          blink::WebLocalFrame* web_frame);
+  using CompleteCallback =
+      base::Callback<void(
+          const blink::WebVector<v8::Local<v8::Value>>& result)>;
+
+  ScriptInjectionCallback(const CompleteCallback& injection_completed_callback);
   ~ScriptInjectionCallback() override;
 
   void completed(
       const blink::WebVector<v8::Local<v8::Value> >& result) override;
 
  private:
-  ScriptInjection* injection_;
-
-  blink::WebLocalFrame* web_frame_;
+  CompleteCallback injection_completed_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(ScriptInjectionCallback);
 };
diff --git a/extensions/renderer/script_injection_manager.cc b/extensions/renderer/script_injection_manager.cc
index e0a610b..326452b8 100644
--- a/extensions/renderer/script_injection_manager.cc
+++ b/extensions/renderer/script_injection_manager.cc
@@ -11,11 +11,10 @@
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_frame_observer.h"
 #include "content/public/renderer/render_thread.h"
-#include "content/public/renderer/render_view.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/common/extension_set.h"
-#include "extensions/renderer/extension_helper.h"
+#include "extensions/renderer/extension_frame_helper.h"
 #include "extensions/renderer/extension_injection_host.h"
 #include "extensions/renderer/programmatic_script_injector.h"
 #include "extensions/renderer/script_injection.h"
@@ -186,10 +185,10 @@
     const ExtensionId& extension_id,
     int script_id,
     const GURL& url) {
-  // TODO(markdittmer): This would be cleaner if we compared page_ids instead.
+  // TODO(markdittmer): URL-checking isn't the best security measure.
   // Begin script injection workflow only if the current URL is identical to
   // the one that matched declarative conditions in the browser.
-  if (render_frame()->GetWebFrame()->top()->document().url() == url) {
+  if (render_frame()->GetWebFrame()->document().url() == url) {
     manager_->HandleExecuteDeclarativeScript(render_frame(),
                                              tab_id,
                                              extension_id,
@@ -282,11 +281,10 @@
 }
 
 void ScriptInjectionManager::InvalidateForFrame(content::RenderFrame* frame) {
-  blink::WebLocalFrame* web_frame = frame->GetWebFrame();
   for (ScopedVector<ScriptInjection>::iterator iter =
            pending_injections_.begin();
        iter != pending_injections_.end();) {
-    if ((*iter)->web_frame() == web_frame)
+    if ((*iter)->render_frame() == frame)
       iter = pending_injections_.erase(iter);
     else
       ++iter;
@@ -333,13 +331,12 @@
 void ScriptInjectionManager::InjectScripts(
     content::RenderFrame* frame,
     UserScript::RunLocation run_location) {
-  blink::WebLocalFrame* web_frame = frame->GetWebFrame();
   // Find any injections that want to run on the given frame.
   ScopedVector<ScriptInjection> frame_injections;
   for (ScopedVector<ScriptInjection>::iterator iter =
            pending_injections_.begin();
        iter != pending_injections_.end();) {
-    if ((*iter)->web_frame() == web_frame) {
+    if ((*iter)->render_frame() == frame) {
       frame_injections.push_back(*iter);
       iter = pending_injections_.weak_erase(iter);
     } else {
@@ -348,10 +345,9 @@
   }
 
   // Add any injections for user scripts.
-  int tab_id = ExtensionHelper::Get(content::RenderView::FromWebView(
-                                        web_frame->top()->view()))->tab_id();
+  int tab_id = ExtensionFrameHelper::Get(frame)->tab_id();
   user_script_set_manager_->GetAllInjections(
-      &frame_injections, web_frame, tab_id, run_location);
+      &frame_injections, frame, tab_id, run_location);
 
   ScriptsRunInfo scripts_run_info;
   std::vector<ScriptInjection*> released_injections;
@@ -359,7 +355,7 @@
   for (ScriptInjection* injection : released_injections)
     TryToInject(make_scoped_ptr(injection), run_location, &scripts_run_info);
 
-  scripts_run_info.LogRun(web_frame, run_location);
+  scripts_run_info.LogRun(frame->GetWebFrame(), run_location);
 }
 
 void ScriptInjectionManager::TryToInject(
@@ -401,14 +397,13 @@
         new WebUIInjectionHost(params.host_id));
   }
 
-  blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
   scoped_ptr<ScriptInjection> injection(new ScriptInjection(
       scoped_ptr<ScriptInjector>(
-          new ProgrammaticScriptInjector(params, web_frame)),
-      web_frame,
+          new ProgrammaticScriptInjector(params, render_frame)),
+      render_frame,
       injection_host.Pass(),
       static_cast<UserScript::RunLocation>(params.run_at),
-      ExtensionHelper::Get(render_frame->GetRenderView())->tab_id()));
+      ExtensionFrameHelper::Get(render_frame)->tab_id()));
 
   ScriptsRunInfo scripts_run_info;
   FrameStatusMap::const_iterator iter = frame_statuses_.find(render_frame);
@@ -425,11 +420,10 @@
     const ExtensionId& extension_id,
     int script_id,
     const GURL& url) {
-  blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
   scoped_ptr<ScriptInjection> injection =
       user_script_set_manager_->GetInjectionForDeclarativeScript(
           script_id,
-          web_frame,
+          render_frame,
           tab_id,
           url,
           extension_id);
@@ -440,7 +434,8 @@
                 UserScript::BROWSER_DRIVEN,
                 &scripts_run_info);
 
-    scripts_run_info.LogRun(web_frame, UserScript::BROWSER_DRIVEN);
+    scripts_run_info.LogRun(render_frame->GetWebFrame(),
+                            UserScript::BROWSER_DRIVEN);
   }
 }
 
@@ -469,7 +464,8 @@
       &scripts_run_info);
   if (res == ScriptInjection::INJECTION_BLOCKED)
     running_injections_.push_back(injection.Pass());
-  scripts_run_info.LogRun(injection->web_frame(), UserScript::RUN_DEFERRED);
+  scripts_run_info.LogRun(injection->render_frame()->GetWebFrame(),
+                          UserScript::RUN_DEFERRED);
 }
 
 }  // namespace extensions
diff --git a/extensions/renderer/script_injector.h b/extensions/renderer/script_injector.h
index 6f915af7..21d434cf 100644
--- a/extensions/renderer/script_injector.h
+++ b/extensions/renderer/script_injector.h
@@ -16,7 +16,7 @@
 class InjectionHost;
 
 namespace blink {
-class WebFrame;
+class WebLocalFrame;
 }
 
 namespace extensions {
@@ -59,7 +59,7 @@
   // Returns true if the script should execute on the given |frame|.
   virtual PermissionsData::AccessType CanExecuteOnFrame(
       const InjectionHost* injection_host,
-      blink::WebFrame* web_frame,
+      blink::WebLocalFrame* web_frame,
       int tab_id) const = 0;
 
   // Returns the javascript sources to inject at the given |run_location|.
diff --git a/extensions/renderer/scripts_run_info.cc b/extensions/renderer/scripts_run_info.cc
index f5a85d1..a7d4115 100644
--- a/extensions/renderer/scripts_run_info.cc
+++ b/extensions/renderer/scripts_run_info.cc
@@ -5,10 +5,10 @@
 #include "extensions/renderer/scripts_run_info.h"
 
 #include "base/metrics/histogram.h"
-#include "content/public/renderer/render_view.h"
+#include "content/public/renderer/render_frame.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/renderer/script_context.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
 
 namespace extensions {
 
@@ -19,14 +19,14 @@
 ScriptsRunInfo::~ScriptsRunInfo() {
 }
 
-void ScriptsRunInfo::LogRun(blink::WebFrame* frame,
+void ScriptsRunInfo::LogRun(blink::WebLocalFrame* frame,
                             UserScript::RunLocation location) {
   // Notify the browser if any extensions are now executing scripts.
   if (!executing_scripts.empty()) {
-    content::RenderView* render_view =
-        content::RenderView::FromWebView(frame->view());
-    render_view->Send(new ExtensionHostMsg_ContentScriptsExecuting(
-        render_view->GetRoutingID(),
+    content::RenderFrame* render_frame =
+        content::RenderFrame::FromWebFrame(frame);
+    render_frame->Send(new ExtensionHostMsg_ContentScriptsExecuting(
+        render_frame->GetRoutingID(),
         executing_scripts,
         ScriptContext::GetDataSourceURLForFrame(frame)));
   }
diff --git a/extensions/renderer/scripts_run_info.h b/extensions/renderer/scripts_run_info.h
index 957671fb..392976d 100644
--- a/extensions/renderer/scripts_run_info.h
+++ b/extensions/renderer/scripts_run_info.h
@@ -15,7 +15,7 @@
 #include "extensions/common/user_script.h"
 
 namespace blink {
-class WebFrame;
+class WebLocalFrame;
 }
 
 namespace extensions {
@@ -40,7 +40,7 @@
   base::ElapsedTimer timer;
 
   // Log information about a given script run.
-  void LogRun(blink::WebFrame* web_frame, UserScript::RunLocation location);
+  void LogRun(blink::WebLocalFrame* frame, UserScript::RunLocation location);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ScriptsRunInfo);
diff --git a/extensions/renderer/tab_finder.cc b/extensions/renderer/tab_finder.cc
deleted file mode 100644
index ca8b602..0000000
--- a/extensions/renderer/tab_finder.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 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.
-
-#include "extensions/renderer/tab_finder.h"
-
-#include "content/public/renderer/render_view.h"
-#include "extensions/renderer/extension_helper.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
-#include "third_party/WebKit/public/web/WebView.h"
-
-using content::RenderView;
-
-namespace extensions {
-
-// static
-content::RenderView* TabFinder::Find(int tab_id) {
-  TabFinder finder(tab_id);
-  RenderView::ForEach(&finder);
-  return finder.view_;
-}
-
-TabFinder::TabFinder(int tab_id) : tab_id_(tab_id), view_(NULL) {}
-
-TabFinder::~TabFinder() {}
-
-// Note: Visit returns false to terminate the iteration.
-bool TabFinder::Visit(RenderView* render_view) {
-  // Only interested in the top frame.
-  if (render_view->GetWebView()->mainFrame()->parent())
-    return true;
-
-  ExtensionHelper* helper = ExtensionHelper::Get(render_view);
-  if (helper && helper->tab_id() == tab_id_)
-    view_ = render_view;
-
-  return !view_;
-}
-
-}  // namespace extensions
diff --git a/extensions/renderer/tab_finder.h b/extensions/renderer/tab_finder.h
deleted file mode 100644
index 4d326aad..0000000
--- a/extensions/renderer/tab_finder.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 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 EXTENSIONS_RENDERER_TAB_FINDER_H_
-#define EXTENSIONS_RENDERER_TAB_FINDER_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "content/public/renderer/render_view_visitor.h"
-
-namespace content {
-class RenderView;
-}
-
-namespace extensions {
-
-// Finds the top RenderView associated with a tab ID.
-class TabFinder : public content::RenderViewVisitor {
- public:
-  // Returns the top RenderView with |tab_id|, or NULL if none is found.
-  static content::RenderView* Find(int tab_id);
-
- private:
-  explicit TabFinder(int tab_id);
-  ~TabFinder() override;
-
-  // content::RenderViewVisitor implementation.
-  bool Visit(content::RenderView* render_view) override;
-
-  int tab_id_;
-  content::RenderView* view_;
-
-  DISALLOW_COPY_AND_ASSIGN(TabFinder);
-};
-
-}  // namespace extensions
-
-#endif  // EXTENSIONS_RENDERER_TAB_FINDER_H_
diff --git a/extensions/renderer/user_script_injector.cc b/extensions/renderer/user_script_injector.cc
index b90e906..341890e2 100644
--- a/extensions/renderer/user_script_injector.cc
+++ b/extensions/renderer/user_script_injector.cc
@@ -19,7 +19,7 @@
 #include "extensions/renderer/scripts_run_info.h"
 #include "grit/extensions_renderer_resources.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebScriptSource.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "url/gurl.h"
@@ -152,7 +152,7 @@
 
 PermissionsData::AccessType UserScriptInjector::CanExecuteOnFrame(
     const InjectionHost* injection_host,
-    blink::WebFrame* web_frame,
+    blink::WebLocalFrame* web_frame,
     int tab_id) const {
   GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL(
       web_frame, web_frame->document().url(), script_->match_about_blank());
diff --git a/extensions/renderer/user_script_injector.h b/extensions/renderer/user_script_injector.h
index abddf051..1ee8fed 100644
--- a/extensions/renderer/user_script_injector.h
+++ b/extensions/renderer/user_script_injector.h
@@ -16,7 +16,7 @@
 class InjectionHost;
 
 namespace blink {
-class WebFrame;
+class WebLocalFrame;
 }
 
 namespace extensions {
@@ -44,7 +44,7 @@
   bool ShouldInjectCss(UserScript::RunLocation run_location) const override;
   PermissionsData::AccessType CanExecuteOnFrame(
       const InjectionHost* injection_host,
-      blink::WebFrame* web_frame,
+      blink::WebLocalFrame* web_frame,
       int tab_id) const override;
   std::vector<blink::WebScriptSource> GetJsSources(
       UserScript::RunLocation run_location) const override;
diff --git a/extensions/renderer/user_script_set.cc b/extensions/renderer/user_script_set.cc
index 257ae42..63634e0 100644
--- a/extensions/renderer/user_script_set.cc
+++ b/extensions/renderer/user_script_set.cc
@@ -6,6 +6,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "content/public/common/url_constants.h"
+#include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_thread.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_set.h"
@@ -19,14 +20,14 @@
 #include "extensions/renderer/user_script_injector.h"
 #include "extensions/renderer/web_ui_injection_host.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "url/gurl.h"
 
 namespace extensions {
 
 namespace {
 
-GURL GetDocumentUrlForFrame(blink::WebFrame* frame) {
+GURL GetDocumentUrlForFrame(blink::WebLocalFrame* frame) {
   GURL data_source_url = ScriptContext::GetDataSourceURLForFrame(frame);
   if (!data_source_url.is_empty() && frame->isViewSourceModeEnabled()) {
     data_source_url = GURL(content::kViewSourceScheme + std::string(":") +
@@ -55,28 +56,24 @@
 
 void UserScriptSet::GetActiveExtensionIds(
     std::set<std::string>* ids) const {
-  for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin();
-       iter != scripts_.end();
-       ++iter) {
-    if ((*iter)->host_id().type() != HostID::EXTENSIONS)
+  for (const UserScript* script : scripts_) {
+    if (script->host_id().type() != HostID::EXTENSIONS)
       continue;
-    DCHECK(!(*iter)->extension_id().empty());
-    ids->insert((*iter)->extension_id());
+    DCHECK(!script->extension_id().empty());
+    ids->insert(script->extension_id());
   }
 }
 
 void UserScriptSet::GetInjections(
     ScopedVector<ScriptInjection>* injections,
-    blink::WebFrame* web_frame,
+    content::RenderFrame* render_frame,
     int tab_id,
     UserScript::RunLocation run_location) {
-  GURL document_url = GetDocumentUrlForFrame(web_frame);
-  for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin();
-       iter != scripts_.end();
-       ++iter) {
+  GURL document_url = GetDocumentUrlForFrame(render_frame->GetWebFrame());
+  for (const UserScript* script : scripts_) {
     scoped_ptr<ScriptInjection> injection = GetInjectionForScript(
-        *iter,
-        web_frame,
+        script,
+        render_frame,
         tab_id,
         run_location,
         document_url,
@@ -161,16 +158,14 @@
 
 scoped_ptr<ScriptInjection> UserScriptSet::GetDeclarativeScriptInjection(
     int script_id,
-    blink::WebFrame* web_frame,
+    content::RenderFrame* render_frame,
     int tab_id,
     UserScript::RunLocation run_location,
     const GURL& document_url) {
-  for (ScopedVector<UserScript>::const_iterator it = scripts_.begin();
-       it != scripts_.end();
-       ++it) {
-    if ((*it)->id() == script_id) {
-      return GetInjectionForScript(*it,
-                                   web_frame,
+  for (const UserScript* script : scripts_) {
+    if (script->id() == script_id) {
+      return GetInjectionForScript(script,
+                                   render_frame,
                                    tab_id,
                                    run_location,
                                    document_url,
@@ -180,17 +175,16 @@
   return scoped_ptr<ScriptInjection>();
 }
 
-// TODO(dcheng): Scripts can't be injected on a remote frame, so this function
-// signature needs to be updated.
 scoped_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
-    UserScript* script,
-    blink::WebFrame* web_frame,
+    const UserScript* script,
+    content::RenderFrame* render_frame,
     int tab_id,
     UserScript::RunLocation run_location,
     const GURL& document_url,
     bool is_declarative) {
   scoped_ptr<ScriptInjection> injection;
   scoped_ptr<const InjectionHost> injection_host;
+  blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
 
   const HostID& host_id = script->host_id();
   if (host_id.type() == HostID::EXTENSIONS) {
@@ -215,14 +209,6 @@
                                                              this,
                                                              is_declarative));
 
-  blink::WebFrame* top_frame = web_frame->top();
-  // It doesn't make sense to do script injection for remote frames, since they
-  // cannot host any documents or content.
-  // TODO(kalman): Fix this properly by moving all security checks into the
-  // browser. See http://crbug.com/466373 for ongoing work here.
-  if (top_frame->isWebRemoteFrame())
-    return injection.Pass();
-
   if (injector->CanExecuteOnFrame(
           injection_host.get(),
           web_frame,
@@ -238,7 +224,7 @@
   if (inject_css || inject_js) {
     injection.reset(new ScriptInjection(
         injector.Pass(),
-        web_frame->toWebLocalFrame(),
+        render_frame,
         injection_host.Pass(),
         run_location,
         tab_id));
diff --git a/extensions/renderer/user_script_set.h b/extensions/renderer/user_script_set.h
index 97afaaa..a39a543 100644
--- a/extensions/renderer/user_script_set.h
+++ b/extensions/renderer/user_script_set.h
@@ -19,8 +19,8 @@
 
 class GURL;
 
-namespace blink {
-class WebFrame;
+namespace content {
+class RenderFrame;
 }
 
 namespace extensions {
@@ -49,18 +49,18 @@
   // Appends the ids of the extensions that have user scripts to |ids|.
   void GetActiveExtensionIds(std::set<std::string>* ids) const;
 
-  // Append any ScriptInjections that should run on the given |web_frame| and
+  // Append any ScriptInjections that should run on the given |render_frame| and
   // |tab_id|, at the given |run_location|, to |injections|.
   // |extensions| is passed in to verify the corresponding extension is still
   // valid.
   void GetInjections(ScopedVector<ScriptInjection>* injections,
-                     blink::WebFrame* web_frame,
+                     content::RenderFrame* render_frame,
                      int tab_id,
                      UserScript::RunLocation run_location);
 
   scoped_ptr<ScriptInjection> GetDeclarativeScriptInjection(
       int script_id,
-      blink::WebFrame* web_frame,
+      content::RenderFrame* render_frame,
       int tab_id,
       UserScript::RunLocation run_location,
       const GURL& document_url);
@@ -75,10 +75,10 @@
 
  private:
   // Returns a new ScriptInjection for the given |script| to execute in the
-  // |web_frame|, or NULL if the script should not execute.
+  // |render_frame|, or NULL if the script should not execute.
   scoped_ptr<ScriptInjection> GetInjectionForScript(
-      UserScript* script,
-      blink::WebFrame* web_frame,
+      const UserScript* script,
+      content::RenderFrame* render_frame,
       int tab_id,
       UserScript::RunLocation run_location,
       const GURL& document_url,
diff --git a/extensions/renderer/user_script_set_manager.cc b/extensions/renderer/user_script_set_manager.cc
index 1c8f72d..e2a7675c 100644
--- a/extensions/renderer/user_script_set_manager.cc
+++ b/extensions/renderer/user_script_set_manager.cc
@@ -12,7 +12,6 @@
 #include "extensions/renderer/user_script_set.h"
 #include "ipc/ipc_message.h"
 #include "ipc/ipc_message_macros.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
 
 namespace extensions {
 
@@ -36,7 +35,7 @@
 scoped_ptr<ScriptInjection>
 UserScriptSetManager::GetInjectionForDeclarativeScript(
     int script_id,
-    blink::WebFrame* web_frame,
+    content::RenderFrame* render_frame,
     int tab_id,
     const GURL& url,
     const std::string& extension_id) {
@@ -47,7 +46,7 @@
 
   return user_script_set->GetDeclarativeScriptInjection(
       script_id,
-      web_frame,
+      render_frame,
       tab_id,
       UserScript::BROWSER_DRIVEN,
       url);
@@ -65,14 +64,14 @@
 
 void UserScriptSetManager::GetAllInjections(
     ScopedVector<ScriptInjection>* injections,
-    blink::WebFrame* web_frame,
+    content::RenderFrame* render_frame,
     int tab_id,
     UserScript::RunLocation run_location) {
-  static_scripts_.GetInjections(injections, web_frame, tab_id, run_location);
+  static_scripts_.GetInjections(injections, render_frame, tab_id, run_location);
   for (UserScriptSetMap::iterator it = programmatic_scripts_.begin();
        it != programmatic_scripts_.end();
        ++it) {
-    it->second->GetInjections(injections, web_frame, tab_id, run_location);
+    it->second->GetInjections(injections, render_frame, tab_id, run_location);
   }
 }
 
diff --git a/extensions/renderer/user_script_set_manager.h b/extensions/renderer/user_script_set_manager.h
index e2d645f..bea5f15f 100644
--- a/extensions/renderer/user_script_set_manager.h
+++ b/extensions/renderer/user_script_set_manager.h
@@ -17,12 +17,12 @@
 #include "extensions/common/user_script.h"
 #include "extensions/renderer/user_script_set.h"
 
-namespace IPC {
-class Message;
+namespace content {
+class RenderFrame;
 }
 
-namespace blink {
-class WebFrame;
+namespace IPC {
+class Message;
 }
 
 namespace extensions {
@@ -61,7 +61,7 @@
   // and |url|.
   scoped_ptr<ScriptInjection> GetInjectionForDeclarativeScript(
       int script_id,
-      blink::WebFrame* web_frame,
+      content::RenderFrame* render_frame,
       int tab_id,
       const GURL& url,
       const std::string& extension_id);
@@ -69,7 +69,7 @@
   // Append all injections from |static_scripts| and each of
   // |programmatic_scripts_| to |injections|.
   void GetAllInjections(ScopedVector<ScriptInjection>* injections,
-                        blink::WebFrame* web_frame,
+                        content::RenderFrame* render_frame,
                         int tab_id,
                         UserScript::RunLocation run_location);
 
diff --git a/extensions/shell/browser/shell_content_browser_client.cc b/extensions/shell/browser/shell_content_browser_client.cc
index 19f0547b..957b8308 100644
--- a/extensions/shell/browser/shell_content_browser_client.cc
+++ b/extensions/shell/browser/shell_content_browser_client.cc
@@ -200,21 +200,26 @@
                  site_instance->GetId()));
 }
 
-void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
-    base::CommandLine* command_line,
-    int child_process_id) {
+void ShellContentBrowserClient::AppendMappedFileCommandLineSwitches(
+    base::CommandLine* command_line) {
   std::string process_type =
       command_line->GetSwitchValueASCII(::switches::kProcessType);
 
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
-  if (process_type != ::switches::kZygoteProcess) {
-    command_line->AppendSwitch(::switches::kV8NativesPassedByFD);
+  DCHECK(natives_fd_exists());
+  command_line->AppendSwitch(::switches::kV8NativesPassedByFD);
+  if (snapshot_fd_exists())
     command_line->AppendSwitch(::switches::kV8SnapshotPassedByFD);
-  }
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
 #endif  // OS_POSIX && !OS_MACOSX
+}
 
+void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
+    base::CommandLine* command_line,
+    int child_process_id) {
+  std::string process_type =
+      command_line->GetSwitchValueASCII(::switches::kProcessType);
   if (process_type == ::switches::kRendererProcess)
     AppendRendererSwitches(command_line);
 }
@@ -255,7 +260,7 @@
     int child_process_id,
     content::FileDescriptorInfo* mappings) {
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
-  if (v8_natives_fd_.get() == -1 || v8_snapshot_fd_.get() == -1) {
+  if (!natives_fd_exists()) {
     int v8_natives_fd = -1;
     int v8_snapshot_fd = -1;
     if (gin::V8Initializer::OpenV8FilesForChildProcesses(&v8_natives_fd,
@@ -264,7 +269,9 @@
       v8_snapshot_fd_.reset(v8_snapshot_fd);
     }
   }
-  DCHECK(v8_natives_fd_.get() != -1 && v8_snapshot_fd_.get() != -1);
+  // V8 can't start up without the source of the natives, but it can
+  // start up (slower) without the snapshot.
+  DCHECK(natives_fd_exists());
   mappings->Share(kV8NativesDataDescriptor, v8_natives_fd_.get());
   mappings->Share(kV8SnapshotDataDescriptor, v8_snapshot_fd_.get());
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
diff --git a/extensions/shell/browser/shell_content_browser_client.h b/extensions/shell/browser/shell_content_browser_client.h
index f9d813f..d282397 100644
--- a/extensions/shell/browser/shell_content_browser_client.h
+++ b/extensions/shell/browser/shell_content_browser_client.h
@@ -52,6 +52,8 @@
   void SiteInstanceDeleting(content::SiteInstance* site_instance) override;
   void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
                                       int child_process_id) override;
+  void AppendMappedFileCommandLineSwitches(
+      base::CommandLine* command_line) override;
   content::SpeechRecognitionManagerDelegate*
   CreateSpeechRecognitionManagerDelegate() override;
   content::BrowserPpapiHost* GetExternalBrowserPpapiHost(
@@ -83,6 +85,8 @@
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
   base::ScopedFD v8_natives_fd_;
   base::ScopedFD v8_snapshot_fd_;
+  bool natives_fd_exists() { return v8_natives_fd_ != -1; }
+  bool snapshot_fd_exists() { return v8_snapshot_fd_ != -1; }
 #endif
 
   // Owned by content::BrowserMainLoop.
diff --git a/extensions/utility/unpacker.cc b/extensions/utility/unpacker.cc
index a65aabb3..2cd8f015 100644
--- a/extensions/utility/unpacker.cc
+++ b/extensions/utility/unpacker.cc
@@ -31,7 +31,6 @@
 #include "ipc/ipc_message_utils.h"
 #include "net/base/file_stream.h"
 #include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/zlib/google/zip.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -97,11 +96,13 @@
   DecodedImages decoded_images;
 };
 
-Unpacker::Unpacker(const base::FilePath& extension_path,
+Unpacker::Unpacker(const base::FilePath& working_dir,
+                   const base::FilePath& extension_dir,
                    const std::string& extension_id,
                    Manifest::Location location,
                    int creation_flags)
-    : extension_path_(extension_path),
+    : working_dir_(working_dir),
+      extension_dir_(extension_dir),
       extension_id_(extension_id),
       location_(location),
       creation_flags_(creation_flags) {
@@ -112,7 +113,7 @@
 }
 
 base::DictionaryValue* Unpacker::ReadManifest() {
-  base::FilePath manifest_path = temp_install_dir_.Append(kManifestFilename);
+  base::FilePath manifest_path = extension_dir_.Append(kManifestFilename);
   if (!base::PathExists(manifest_path)) {
     SetError(errors::kInvalidManifest);
     return NULL;
@@ -135,7 +136,7 @@
 }
 
 bool Unpacker::ReadAllMessageCatalogs(const std::string& default_locale) {
-  base::FilePath locales_path = temp_install_dir_.Append(kLocaleFolder);
+  base::FilePath locales_path = extension_dir_.Append(kLocaleFolder);
 
   // Not all folders under _locales have to be valid locales.
   base::FileEnumerator locales(locales_path, false,
@@ -159,24 +160,6 @@
 }
 
 bool Unpacker::Run() {
-  DVLOG(1) << "Installing extension " << extension_path_.value();
-
-  // <profile>/Extensions/CRX_INSTALL
-  temp_install_dir_ = extension_path_.DirName().AppendASCII(kTempExtensionName);
-
-  if (!base::CreateDirectory(temp_install_dir_)) {
-    SetUTF16Error(l10n_util::GetStringFUTF16(
-        IDS_EXTENSION_PACKAGE_DIRECTORY_ERROR,
-        base::i18n::GetDisplayStringInLTRDirectionality(
-            temp_install_dir_.LossyDisplayName())));
-    return false;
-  }
-
-  if (!zip::Unzip(extension_path_, temp_install_dir_)) {
-    SetUTF16Error(l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR));
-    return false;
-  }
-
   // Parse the manifest.
   parsed_manifest_.reset(ReadManifest());
   if (!parsed_manifest_.get())
@@ -184,7 +167,7 @@
 
   std::string error;
   scoped_refptr<Extension> extension(
-      Extension::Create(temp_install_dir_, location_, *parsed_manifest_,
+      Extension::Create(extension_dir_, location_, *parsed_manifest_,
                         creation_flags_, extension_id_, &error));
   if (!extension.get()) {
     SetError(error);
@@ -214,15 +197,14 @@
       return false;  // Error was already reported.
   }
 
-  return true;
+  return DumpImagesToFile() && DumpMessageCatalogsToFile();
 }
 
 bool Unpacker::DumpImagesToFile() {
   IPC::Message pickle;  // We use a Message so we can use WriteParam.
   IPC::WriteParam(&pickle, internal_data_->decoded_images);
 
-  base::FilePath path =
-      extension_path_.DirName().AppendASCII(kDecodedImagesFilename);
+  base::FilePath path = working_dir_.AppendASCII(kDecodedImagesFilename);
   if (!WritePickle(pickle, path)) {
     SetError("Could not write image data to disk.");
     return false;
@@ -236,7 +218,7 @@
   IPC::WriteParam(&pickle, *parsed_catalogs_.get());
 
   base::FilePath path =
-      extension_path_.DirName().AppendASCII(kDecodedMessageCatalogsFilename);
+      working_dir_.AppendASCII(kDecodedMessageCatalogsFilename);
   if (!WritePickle(pickle, path)) {
     SetError("Could not write message catalogs to disk.");
     return false;
@@ -255,7 +237,7 @@
     return false;
   }
 
-  SkBitmap image_bitmap = DecodeImage(temp_install_dir_.Append(path));
+  SkBitmap image_bitmap = DecodeImage(extension_dir_.Append(path));
   if (image_bitmap.isNull()) {
     SetUTF16Error(l10n_util::GetStringFUTF16(
         IDS_EXTENSION_PACKAGE_IMAGE_ERROR,
@@ -288,7 +270,7 @@
 
   base::FilePath relative_path;
   // message_path was created from temp_install_dir. This should never fail.
-  if (!temp_install_dir_.AppendRelativePath(message_path, &relative_path)) {
+  if (!extension_dir_.AppendRelativePath(message_path, &relative_path)) {
     NOTREACHED();
     return false;
   }
diff --git a/extensions/utility/unpacker.h b/extensions/utility/unpacker.h
index 240172e0..7e5a7e4 100644
--- a/extensions/utility/unpacker.h
+++ b/extensions/utility/unpacker.h
@@ -21,21 +21,29 @@
 namespace extensions {
 
 // This class unpacks an extension.  It is designed to be used in a sandboxed
-// child process.  We unpack and parse various bits of the extension, then
-// report back to the browser process, who then transcodes the pre-parsed bits
-// and writes them back out to disk for later use.
+// child process.  We parse various bits of the extension, then report back to
+// the browser process, who then transcodes the pre-parsed bits and writes them
+// back out to disk for later use.
 class Unpacker {
  public:
-  Unpacker(const base::FilePath& extension_path,
+  Unpacker(const base::FilePath& working_dir,
+           const base::FilePath& extension_dir,
            const std::string& extension_id,
            Manifest::Location location,
            int creation_flags);
   ~Unpacker();
 
-  // Install the extension file at |extension_path|.  Returns true on success.
-  // Otherwise, error_message will contain a string explaining what went wrong.
+  // Runs the processing steps for the extension. On success, this returns true
+  // and the decoded images will be in a file at
+  // |working_dir|/kDecodedImagesFilename and the decoded messages will be in a
+  // file at |working_dir|/kDecodedMessageCatalogsFilename.
   bool Run();
 
+  const base::string16& error_message() { return error_message_; }
+  base::DictionaryValue* parsed_manifest() { return parsed_manifest_.get(); }
+  base::DictionaryValue* parsed_catalogs() { return parsed_catalogs_.get(); }
+
+ private:
   // Write the decoded images to kDecodedImagesFilename.  We do this instead
   // of sending them over IPC, since they are so large.  Returns true on
   // success.
@@ -46,11 +54,6 @@
   // success.
   bool DumpMessageCatalogsToFile();
 
-  const base::string16& error_message() { return error_message_; }
-  base::DictionaryValue* parsed_manifest() { return parsed_manifest_.get(); }
-  base::DictionaryValue* parsed_catalogs() { return parsed_catalogs_.get(); }
-
- private:
   // Parse the manifest.json file inside the extension (not in the header).
   // Caller takes ownership of return value.
   base::DictionaryValue* ReadManifest();
@@ -70,8 +73,11 @@
   void SetError(const std::string& error);
   void SetUTF16Error(const base::string16& error);
 
-  // The extension to unpack.
-  base::FilePath extension_path_;
+  // The directory to do work in.
+  base::FilePath working_dir_;
+
+  // The directory where the extension source lives.
+  base::FilePath extension_dir_;
 
   // The extension ID if known.
   std::string extension_id_;
@@ -82,9 +88,6 @@
   // The creation flags to use with the created extension.
   int creation_flags_;
 
-  // The place we unpacked the extension to.
-  base::FilePath temp_install_dir_;
-
   // The parsed version of the manifest JSON contained in the extension.
   scoped_ptr<base::DictionaryValue> parsed_manifest_;
 
diff --git a/extensions/utility/unpacker_unittest.cc b/extensions/utility/unpacker_unittest.cc
index 917f66e..107a0cc 100644
--- a/extensions/utility/unpacker_unittest.cc
+++ b/extensions/utility/unpacker_unittest.cc
@@ -16,6 +16,7 @@
 #include "extensions/utility/unpacker.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/zlib/google/zip.h"
 
 using base::ASCIIToUTF16;
 
@@ -32,22 +33,22 @@
   }
 
   void SetupUnpacker(const std::string& crx_name) {
-    base::FilePath original_path;
-    ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_path));
-    original_path = original_path.AppendASCII("unpacker").AppendASCII(crx_name);
-    ASSERT_TRUE(base::PathExists(original_path)) << original_path.value();
+    base::FilePath crx_path;
+    ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &crx_path));
+    crx_path = crx_path.AppendASCII("unpacker").AppendASCII(crx_name);
+    ASSERT_TRUE(base::PathExists(crx_path)) << crx_path.value();
 
     // Try bots won't let us write into DIR_TEST_DATA, so we have to create
     // a temp folder to play in.
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
 
-    base::FilePath crx_path = temp_dir_.path().AppendASCII(crx_name);
-    ASSERT_TRUE(base::CopyFile(original_path, crx_path))
-        << "Original path " << original_path.value() << ", Crx path "
-        << crx_path.value();
+    base::FilePath unzipped_dir = temp_dir_.path().AppendASCII("unzipped");
+    ASSERT_TRUE(zip::Unzip(crx_path, unzipped_dir))
+        << "Failed to unzip " << crx_path.value() << " to "
+        << unzipped_dir.value();
 
-    unpacker_.reset(new Unpacker(crx_path, std::string(), Manifest::INTERNAL,
-                                 Extension::NO_FLAGS));
+    unpacker_.reset(new Unpacker(temp_dir_.path(), unzipped_dir, std::string(),
+                                 Manifest::INTERNAL, Extension::NO_FLAGS));
   }
 
  protected:
@@ -130,25 +131,6 @@
   EXPECT_EQ(0U, unpacker_->parsed_catalogs()->size());
 }
 
-TEST_F(UnpackerTest, UnzipDirectoryError) {
-  const char kExpected[] = "Could not create directory for unzipping: ";
-  SetupUnpacker("good_package.crx");
-  base::FilePath path = temp_dir_.path().AppendASCII(kTempExtensionName);
-  ASSERT_TRUE(base::WriteFile(path, "foo", 3));
-  EXPECT_FALSE(unpacker_->Run());
-  EXPECT_TRUE(
-      StartsWith(unpacker_->error_message(), ASCIIToUTF16(kExpected), false))
-      << "Expected prefix: \"" << kExpected << "\", actual error: \""
-      << unpacker_->error_message() << "\"";
-}
-
-TEST_F(UnpackerTest, UnzipError) {
-  const char kExpected[] = "Could not unzip extension";
-  SetupUnpacker("bad_zip.crx");
-  EXPECT_FALSE(unpacker_->Run());
-  EXPECT_EQ(ASCIIToUTF16(kExpected), unpacker_->error_message());
-}
-
 namespace {
 
 // Inserts an illegal path into the browser images returned by
diff --git a/extensions/utility/utility_handler.cc b/extensions/utility/utility_handler.cc
index 1620337..65cf509d 100644
--- a/extensions/utility/utility_handler.cc
+++ b/extensions/utility/utility_handler.cc
@@ -6,17 +6,22 @@
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/i18n/rtl.h"
 #include "content/public/utility/utility_thread.h"
+#include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_l10n_util.h"
 #include "extensions/common/extension_utility_messages.h"
 #include "extensions/common/extensions_client.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/update_manifest.h"
+#include "extensions/strings/grit/extensions_strings.h"
 #include "extensions/utility/unpacker.h"
 #include "ipc/ipc_message.h"
 #include "ipc/ipc_message_macros.h"
 #include "third_party/zlib/google/zip.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/base/ui_base_switches.h"
 
 namespace extensions {
@@ -94,19 +99,30 @@
   CHECK_GT(location, Manifest::INVALID_LOCATION);
   CHECK_LT(location, Manifest::NUM_LOCATIONS);
   DCHECK(ExtensionsClient::Get());
-  Unpacker unpacker(extension_path,
-                    extension_id,
-                    static_cast<Manifest::Location>(location),
-                    creation_flags);
-  if (unpacker.Run() && unpacker.DumpImagesToFile() &&
-      unpacker.DumpMessageCatalogsToFile()) {
-    Send(new ExtensionUtilityHostMsg_UnpackExtension_Succeeded(
-        *unpacker.parsed_manifest()));
-  } else {
+  base::FilePath working_dir = extension_path.DirName();
+  base::FilePath unzipped_dir = working_dir.AppendASCII(kTempExtensionName);
+  base::string16 error;
+  if (!base::CreateDirectory(unzipped_dir)) {
     Send(new ExtensionUtilityHostMsg_UnpackExtension_Failed(
-        unpacker.error_message()));
+        l10n_util::GetStringFUTF16(
+            IDS_EXTENSION_PACKAGE_DIRECTORY_ERROR,
+            base::i18n::GetDisplayStringInLTRDirectionality(
+                unzipped_dir.LossyDisplayName()))));
+  } else if (!zip::Unzip(extension_path, unzipped_dir)) {
+    Send(new ExtensionUtilityHostMsg_UnpackExtension_Failed(
+        l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR)));
+  } else {
+    Unpacker unpacker(working_dir, unzipped_dir, extension_id,
+                      static_cast<Manifest::Location>(location),
+                        creation_flags);
+    if (unpacker.Run()) {
+      Send(new ExtensionUtilityHostMsg_UnpackExtension_Succeeded(
+          *unpacker.parsed_manifest()));
+    } else {
+      Send(new ExtensionUtilityHostMsg_UnpackExtension_Failed(
+          unpacker.error_message()));
+    }
   }
-
   ReleaseProcessIfNeeded();
 }
 
diff --git a/gin/BUILD.gn b/gin/BUILD.gn
index 793ee3d8..d926cb9 100644
--- a/gin/BUILD.gn
+++ b/gin/BUILD.gn
@@ -161,6 +161,7 @@
     "shell_runner_unittest.cc",
     "test/run_all_unittests.cc",
     "test/run_js_tests.cc",
+    "v8_isolate_memory_dump_provider_unittest.cc",
     "wrappable_unittest.cc",
   ]
 
diff --git a/gin/gin.gyp b/gin/gin.gyp
index d04515e..a3e4d39 100644
--- a/gin/gin.gyp
+++ b/gin/gin.gyp
@@ -168,6 +168,7 @@
         'shell/gin_shell_unittest.cc',
         'test/run_all_unittests.cc',
         'test/run_js_tests.cc',
+        'v8_isolate_memory_dump_provider_unittest.cc',
         'wrappable_unittest.cc',
       ],
     },
diff --git a/gin/public/isolate_holder.h b/gin/public/isolate_holder.h
index 111fde87..1647293 100644
--- a/gin/public/isolate_holder.h
+++ b/gin/public/isolate_holder.h
@@ -40,7 +40,10 @@
 
   // Should be invoked once before creating IsolateHolder instances to
   // initialize V8 and Gin. In case V8_USE_EXTERNAL_STARTUP_DATA is
-  // defined, V8's initial snapshot should be loaded (by calling
+  // defined, V8's initial natives should be loaded (by calling
+  // V8Initializer::LoadV8NativesFromFD or
+  // V8Initializer::LoadV8Natives) before calling this method.  If the
+  // snapshot file is available, it should also be loaded (by calling
   // V8Initializer::LoadV8SnapshotFromFD or
   // V8Initializer::LoadV8Snapshot) before calling this method.
   static void Initialize(ScriptMode mode,
@@ -63,6 +66,13 @@
   // This method returns if v8::Locker is needed to access isolate.
   AccessMode access_mode() const { return access_mode_; }
 
+  // This method returns V8IsolateMemoryDumpProvider of this isolate, used for
+  // testing.
+  V8IsolateMemoryDumpProvider* isolate_memory_dump_provider_for_testing()
+      const {
+    return isolate_memory_dump_provider_.get();
+  }
+
  private:
   v8::Isolate* isolate_;
   scoped_ptr<PerIsolateData> isolate_data_;
diff --git a/gin/shell/gin_main.cc b/gin/shell/gin_main.cc
index ceb4d64..0b461ee 100644
--- a/gin/shell/gin_main.cc
+++ b/gin/shell/gin_main.cc
@@ -62,6 +62,7 @@
   base::i18n::InitializeICU();
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
   gin::V8Initializer::LoadV8Snapshot();
+  gin::V8Initializer::LoadV8Natives();
 #endif
 
   base::MessageLoop message_loop;
diff --git a/gin/shell_runner_unittest.cc b/gin/shell_runner_unittest.cc
index 4e4b9c2f..4c8b0f6 100644
--- a/gin/shell_runner_unittest.cc
+++ b/gin/shell_runner_unittest.cc
@@ -29,6 +29,7 @@
 
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
   gin::V8Initializer::LoadV8Snapshot();
+  gin::V8Initializer::LoadV8Natives();
 #endif
 
   gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode,
diff --git a/gin/test/file_runner.cc b/gin/test/file_runner.cc
index 8ed0f212..4e84b88 100644
--- a/gin/test/file_runner.cc
+++ b/gin/test/file_runner.cc
@@ -61,6 +61,7 @@
 
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
   gin::V8Initializer::LoadV8Snapshot();
+  gin::V8Initializer::LoadV8Natives();
 #endif
 
   gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode,
diff --git a/gin/test/v8_test.cc b/gin/test/v8_test.cc
index aad291d8..cec4fc8 100644
--- a/gin/test/v8_test.cc
+++ b/gin/test/v8_test.cc
@@ -23,6 +23,7 @@
 void V8Test::SetUp() {
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
   gin::V8Initializer::LoadV8Snapshot();
+  gin::V8Initializer::LoadV8Natives();
 #endif
   gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode,
                                  gin::ArrayBufferAllocator::SharedInstance());
diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc
index 8f79d0d..0568fe7 100644
--- a/gin/v8_initializer.cc
+++ b/gin/v8_initializer.cc
@@ -50,53 +50,31 @@
 const int kMaxOpenAttempts = 5;
 const int kOpenRetryDelayMillis = 250;
 
-void GetV8FilePaths(base::FilePath* natives_path_out,
-                    base::FilePath* snapshot_path_out) {
+void GetV8FilePath(const char* file_name, base::FilePath* path_out) {
 #if !defined(OS_MACOSX)
   base::FilePath data_path;
   PathService::Get(kV8SnapshotBasePathKey, &data_path);
   DCHECK(!data_path.empty());
 
-  *natives_path_out = data_path.AppendASCII(kNativesFileName);
-  *snapshot_path_out = data_path.AppendASCII(kSnapshotFileName);
+  *path_out = data_path.AppendASCII(file_name);
 #else   // !defined(OS_MACOSX)
   base::ScopedCFTypeRef<CFStringRef> natives_file_name(
-      base::SysUTF8ToCFStringRef(kNativesFileName));
-  *natives_path_out =
-      base::mac::PathForFrameworkBundleResource(natives_file_name);
-  base::ScopedCFTypeRef<CFStringRef> snapshot_file_name(
-      base::SysUTF8ToCFStringRef(kSnapshotFileName));
-  *snapshot_path_out =
-      base::mac::PathForFrameworkBundleResource(snapshot_file_name);
-  DCHECK(!natives_path_out->empty());
-  DCHECK(!snapshot_path_out->empty());
+      base::SysUTF8ToCFStringRef(file_name));
+  *path_out = base::mac::PathForFrameworkBundleResource(natives_file_name);
 #endif  // !defined(OS_MACOSX)
+  DCHECK(!path_out->empty());
 }
 
-static bool MapV8Files(base::File natives_file,
-                       base::File snapshot_file,
-                       base::MemoryMappedFile::Region natives_region =
-                           base::MemoryMappedFile::Region::kWholeFile,
-                       base::MemoryMappedFile::Region snapshot_region =
-                           base::MemoryMappedFile::Region::kWholeFile) {
-  g_mapped_natives = new base::MemoryMappedFile;
-  if (!g_mapped_natives->IsValid()) {
-    if (!g_mapped_natives->Initialize(natives_file.Pass(), natives_region)) {
-      delete g_mapped_natives;
-      g_mapped_natives = NULL;
-      LOG(FATAL) << "Couldn't mmap v8 natives data file";
-      return false;
-    }
-  }
-
-  g_mapped_snapshot = new base::MemoryMappedFile;
-  if (!g_mapped_snapshot->IsValid()) {
-    if (!g_mapped_snapshot->Initialize(snapshot_file.Pass(), snapshot_region)) {
-      delete g_mapped_snapshot;
-      g_mapped_snapshot = NULL;
-      LOG(ERROR) << "Couldn't mmap v8 snapshot data file";
-      return false;
-    }
+static bool MapV8File(base::File file,
+                      base::MemoryMappedFile::Region region,
+                      base::MemoryMappedFile** mmapped_file_out) {
+  DCHECK(*mmapped_file_out == NULL);
+  base::MemoryMappedFile* mmapped_file = *mmapped_file_out =
+      new base::MemoryMappedFile;
+  if (!mmapped_file->Initialize(file.Pass(), region)) {
+    delete mmapped_file;
+    *mmapped_file_out = NULL;
+    return false;
   }
 
   return true;
@@ -146,14 +124,19 @@
 }
 
 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA)
-bool VerifyV8SnapshotFile(base::MemoryMappedFile* snapshot_file,
-                          const unsigned char* fingerprint) {
+bool VerifyV8StartupFile(base::MemoryMappedFile** file,
+                         const unsigned char* fingerprint) {
   unsigned char output[crypto::kSHA256Length];
   crypto::SHA256HashString(
-      base::StringPiece(reinterpret_cast<const char*>(snapshot_file->data()),
-                        snapshot_file->length()),
+      base::StringPiece(reinterpret_cast<const char*>((*file)->data()),
+                        (*file)->length()),
       output, sizeof(output));
-  return !memcmp(fingerprint, output, sizeof(output));
+  if (!memcmp(fingerprint, output, sizeof(output))) {
+    return true;
+  }
+  delete *file;
+  *file = NULL;
+  return false;
 }
 #endif  // V8_VERIFY_EXTERNAL_STARTUP_DATA
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
@@ -172,58 +155,103 @@
 extern const unsigned char g_snapshot_fingerprint[];
 #endif  // V8_VERIFY_EXTERNAL_STARTUP_DATA
 
-// static
-bool V8Initializer::LoadV8Snapshot() {
+enum LoadV8FileResult {
+  V8_LOAD_SUCCESS = 0,
+  V8_LOAD_FAILED_OPEN,
+  V8_LOAD_FAILED_MAP,
+  V8_LOAD_FAILED_VERIFY,
+  V8_LOAD_MAX_VALUE
+};
 
-  enum LoadV8SnapshotResult {
-    SUCCESS = 0,
-    FAILED_OPEN,
-    FAILED_MAP,
-    FAILED_VERIFY,
-    MAX_VALUE
-  };
+static LoadV8FileResult OpenMapVerify(
+    const char* file_name,
+#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA)
+    const unsigned char* fingerprint,
+#endif
+    base::MemoryMappedFile** mmapped_file_out) {
+  base::FilePath path;
+  GetV8FilePath(file_name, &path);
 
-  if (g_mapped_natives && g_mapped_snapshot)
-    return true;
-
-  base::FilePath natives_data_path;
-  base::FilePath snapshot_data_path;
-  GetV8FilePaths(&natives_data_path, &snapshot_data_path);
-
-  base::File natives_file;
-  base::File snapshot_file;
+  base::File file;
   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
 
-  LoadV8SnapshotResult result;
-  if (!OpenV8File(natives_data_path, flags, natives_file) ||
-      !OpenV8File(snapshot_data_path, flags, snapshot_file)) {
-    result = LoadV8SnapshotResult::FAILED_OPEN;
-  } else if (!MapV8Files(natives_file.Pass(), snapshot_file.Pass())) {
-    result = LoadV8SnapshotResult::FAILED_MAP;
+  if (!OpenV8File(path, flags, file))
+    return V8_LOAD_FAILED_OPEN;
+  if (!MapV8File(file.Pass(), base::MemoryMappedFile::Region::kWholeFile,
+                 mmapped_file_out))
+    return V8_LOAD_FAILED_MAP;
 #if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA)
-  } else if (!VerifyV8SnapshotFile(g_mapped_natives, g_natives_fingerprint) ||
-             !VerifyV8SnapshotFile(g_mapped_snapshot, g_snapshot_fingerprint)) {
-    result = LoadV8SnapshotResult::FAILED_VERIFY;
+  if (!VerifyV8StartupFile(mmapped_file_out, fingerprint))
+    return V8_LOAD_FAILED_VERIFY;
 #endif  // V8_VERIFY_EXTERNAL_STARTUP_DATA
-  } else {
-    result = LoadV8SnapshotResult::SUCCESS;
-  }
-
-  UMA_HISTOGRAM_ENUMERATION("V8.Initializer.LoadV8Snapshot.Result",
-                            result,
-                            LoadV8SnapshotResult::MAX_VALUE);
-  return result == LoadV8SnapshotResult::SUCCESS;
+  return V8_LOAD_SUCCESS;
 }
 
 // static
-bool V8Initializer::LoadV8SnapshotFromFD(base::PlatformFile natives_pf,
-                                         int64 natives_offset,
-                                         int64 natives_size,
-                                         base::PlatformFile snapshot_pf,
+void V8Initializer::LoadV8Snapshot() {
+  if (g_mapped_snapshot)
+    return;
+
+  LoadV8FileResult result = OpenMapVerify(kSnapshotFileName,
+#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA)
+                                          g_snapshot_fingerprint,
+#endif
+                                          &g_mapped_snapshot);
+  UMA_HISTOGRAM_ENUMERATION("V8.Initializer.LoadV8Snapshot.Result", result,
+                            V8_LOAD_MAX_VALUE);
+}
+
+void V8Initializer::LoadV8Natives() {
+  if (g_mapped_natives)
+    return;
+
+  LoadV8FileResult result = OpenMapVerify(kNativesFileName,
+#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA)
+                                          g_natives_fingerprint,
+#endif
+                                          &g_mapped_natives);
+  if (result != V8_LOAD_SUCCESS) {
+    LOG(FATAL) << "Couldn't mmap v8 natives data file, status code is "
+               << static_cast<int>(result);
+  }
+}
+
+// static
+void V8Initializer::LoadV8SnapshotFromFD(base::PlatformFile snapshot_pf,
                                          int64 snapshot_offset,
                                          int64 snapshot_size) {
-  if (g_mapped_natives && g_mapped_snapshot)
-    return true;
+  if (g_mapped_snapshot)
+    return;
+
+  if (snapshot_pf == reinterpret_cast<base::PlatformFile>(-1))
+    return;
+
+  base::MemoryMappedFile::Region snapshot_region =
+      base::MemoryMappedFile::Region::kWholeFile;
+  if (snapshot_size != 0 || snapshot_offset != 0) {
+    snapshot_region =
+        base::MemoryMappedFile::Region(snapshot_offset, snapshot_size);
+  }
+
+  LoadV8FileResult result = V8_LOAD_SUCCESS;
+  if (!MapV8File(base::File(snapshot_pf), snapshot_region, &g_mapped_snapshot))
+    result = V8_LOAD_FAILED_MAP;
+#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA)
+  if (!VerifyV8StartupFile(&g_mapped_snapshot, g_snapshot_fingerprint))
+    result = V8_LOAD_FAILED_VERIFY;
+#endif  // V8_VERIFY_EXTERNAL_STARTUP_DATA
+  UMA_HISTOGRAM_ENUMERATION("V8.Initializer.LoadV8Snapshot.Result", result,
+                            V8_LOAD_MAX_VALUE);
+}
+
+// static
+void V8Initializer::LoadV8NativesFromFD(base::PlatformFile natives_pf,
+                                        int64 natives_offset,
+                                        int64 natives_size) {
+  if (g_mapped_natives)
+    return;
+
+  CHECK_NE(natives_pf, reinterpret_cast<base::PlatformFile>(-1));
 
   base::MemoryMappedFile::Region natives_region =
       base::MemoryMappedFile::Region::kWholeFile;
@@ -232,15 +260,14 @@
         base::MemoryMappedFile::Region(natives_offset, natives_size);
   }
 
-  base::MemoryMappedFile::Region snapshot_region =
-      base::MemoryMappedFile::Region::kWholeFile;
-  if (natives_size != 0 || natives_offset != 0) {
-    snapshot_region =
-        base::MemoryMappedFile::Region(snapshot_offset, snapshot_size);
+  if (!MapV8File(base::File(natives_pf), natives_region, &g_mapped_natives)) {
+    LOG(FATAL) << "Couldn't mmap v8 natives data file";
   }
-
-  return MapV8Files(base::File(natives_pf), base::File(snapshot_pf),
-                    natives_region, snapshot_region);
+#if defined(V8_VERIFY_EXTERNAL_STARTUP_DATA)
+  if (!VerifyV8StartupFile(&g_mapped_natives, g_natives_fingerprint)) {
+    LOG(FATAL) << "Couldn't verify contents of v8 natives data file";
+  }
+#endif  // V8_VERIFY_EXTERNAL_STARTUP_DATA
 }
 
 // static
@@ -249,19 +276,25 @@
     base::PlatformFile* snapshot_fd_out) {
   base::FilePath natives_data_path;
   base::FilePath snapshot_data_path;
-  GetV8FilePaths(&natives_data_path, &snapshot_data_path);
+  GetV8FilePath(kNativesFileName, &natives_data_path);
+  GetV8FilePath(kSnapshotFileName, &snapshot_data_path);
 
   base::File natives_data_file;
   base::File snapshot_data_file;
   int file_flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
 
-  bool success = OpenV8File(natives_data_path, file_flags, natives_data_file) &&
-                 OpenV8File(snapshot_data_path, file_flags, snapshot_data_file);
-  if (success) {
+  bool natives_success =
+      OpenV8File(natives_data_path, file_flags, natives_data_file);
+  if (natives_success) {
     *natives_fd_out = natives_data_file.TakePlatformFile();
+  }
+  bool snapshot_success =
+      OpenV8File(snapshot_data_path, file_flags, snapshot_data_file);
+  if (snapshot_success) {
     *snapshot_fd_out = snapshot_data_file.TakePlatformFile();
   }
-  return success;
+  // We can start up without the snapshot file, but not without the natives.
+  return natives_success;
 }
 
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
@@ -285,10 +318,12 @@
   natives.raw_size = static_cast<int>(g_mapped_natives->length());
   v8::V8::SetNativesDataBlob(&natives);
 
-  v8::StartupData snapshot;
-  snapshot.data = reinterpret_cast<const char*>(g_mapped_snapshot->data());
-  snapshot.raw_size = static_cast<int>(g_mapped_snapshot->length());
-  v8::V8::SetSnapshotDataBlob(&snapshot);
+  if (g_mapped_snapshot != NULL) {
+    v8::StartupData snapshot;
+    snapshot.data = reinterpret_cast<const char*>(g_mapped_snapshot->data());
+    snapshot.raw_size = static_cast<int>(g_mapped_snapshot->length());
+    v8::V8::SetSnapshotDataBlob(&snapshot);
+  }
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
 
   v8::V8::SetEntropySource(&GenerateEntropy);
@@ -302,15 +337,21 @@
                                               int* natives_size_out,
                                               const char** snapshot_data_out,
                                               int* snapshot_size_out) {
-  if (!g_mapped_natives || !g_mapped_snapshot) {
-    *natives_data_out = *snapshot_data_out = NULL;
-    *natives_size_out = *snapshot_size_out = 0;
-    return;
+  if (g_mapped_natives) {
+    *natives_data_out = reinterpret_cast<const char*>(g_mapped_natives->data());
+    *natives_size_out = static_cast<int>(g_mapped_natives->length());
+  } else {
+    *natives_data_out = NULL;
+    *natives_size_out = 0;
   }
-  *natives_data_out = reinterpret_cast<const char*>(g_mapped_natives->data());
-  *snapshot_data_out = reinterpret_cast<const char*>(g_mapped_snapshot->data());
-  *natives_size_out = static_cast<int>(g_mapped_natives->length());
-  *snapshot_size_out = static_cast<int>(g_mapped_snapshot->length());
+  if (g_mapped_snapshot) {
+    *snapshot_data_out =
+        reinterpret_cast<const char*>(g_mapped_snapshot->data());
+    *snapshot_size_out = static_cast<int>(g_mapped_snapshot->length());
+  } else {
+    *snapshot_data_out = NULL;
+    *snapshot_size_out = 0;
+  }
 }
 
 }  // namespace gin
diff --git a/gin/v8_initializer.h b/gin/v8_initializer.h
index 0189f59..1e05fd0 100644
--- a/gin/v8_initializer.h
+++ b/gin/v8_initializer.h
@@ -31,25 +31,31 @@
 
   // Load V8 snapshot from user provided platform file descriptors.
   // The offset and size arguments, if non-zero, specify the portions
-  // of the files to be loaded. This methods returns true on success
-  // (or if snapshot is already loaded), false otherwise.
-  static bool LoadV8SnapshotFromFD(base::PlatformFile natives_fd,
-                                   int64 natives_offset,
-                                   int64 natives_size,
-                                   base::PlatformFile snapshot_fd,
+  // of the files to be loaded. Since the VM can boot with or without
+  // the snapshot, this function does not return a status.
+  static void LoadV8SnapshotFromFD(base::PlatformFile snapshot_fd,
                                    int64 snapshot_offset,
                                    int64 snapshot_size);
+  // Similar to LoadV8SnapshotFromFD, but for the source of the natives.
+  // Without the natives we cannot continue, so this function contains
+  // release mode asserts and won't return if it fails.
+  static void LoadV8NativesFromFD(base::PlatformFile natives_fd,
+                                  int64 natives_offset,
+                                  int64 natives_size);
 
-  // Load V8 snapshot from default resources. Returns true on success or
-  // snapshot is already loaded, false otherwise.
-  static bool LoadV8Snapshot();
+  // Load V8 snapshot from default resources, if they are available.
+  static void LoadV8Snapshot();
+
+  // Load V8 natives source from default resources. Contains asserts
+  // so that it will not return if natives cannot be loaded.
+  static void LoadV8Natives();
 
   // Opens the V8 snapshot data files and returns open file descriptors to these
   // files in |natives_fd_out| and |snapshot_fd_out|, which can be passed to
   // child processes.
   static bool OpenV8FilesForChildProcesses(base::PlatformFile* natives_fd_out,
-                                           base::PlatformFile* snapshot_fd_out);
-
+                                           base::PlatformFile* snapshot_fd_out)
+      WARN_UNUSED_RESULT;
 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
 };
 
diff --git a/gin/v8_isolate_memory_dump_provider.cc b/gin/v8_isolate_memory_dump_provider.cc
index 8e21e74f..57fa91b 100644
--- a/gin/v8_isolate_memory_dump_provider.cc
+++ b/gin/v8_isolate_memory_dump_provider.cc
@@ -4,7 +4,6 @@
 
 #include "gin/v8_isolate_memory_dump_provider.h"
 
-#include "base/message_loop/message_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/trace_event/memory_dump_manager.h"
@@ -15,9 +14,8 @@
 namespace gin {
 
 namespace {
-const char kRootDumpName[] = "v8";
-const char kIsolateDumpName[] = "isolate";
 const char kHeapSpacesDumpName[] = "heap_spaces";
+const char kHeapObjectsDumpName[] = "heap_objects";
 const char kAvailableSizeAttribute[] = "available_size_in_bytes";
 }  // namespace
 
@@ -36,18 +34,29 @@
 // Called at trace dump point time. Creates a snapshot with the memory counters
 // for the current isolate.
 bool V8IsolateMemoryDumpProvider::OnMemoryDump(
-    base::trace_event::ProcessMemoryDump* pmd) {
+    base::trace_event::ProcessMemoryDump* process_memory_dump) {
+  std::string dump_base_name =
+      base::StringPrintf("v8/isolate_%p", isolate_holder_->isolate());
+  std::string space_dump_name = dump_base_name + "/" + kHeapSpacesDumpName;
+  std::string object_dump_name = dump_base_name + "/" + kHeapObjectsDumpName;
+  process_memory_dump->AddOwnershipEdge(
+      process_memory_dump->CreateAllocatorDump(object_dump_name)->guid(),
+      process_memory_dump->CreateAllocatorDump(space_dump_name)->guid());
+
   if (isolate_holder_->access_mode() == IsolateHolder::kUseLocker) {
     v8::Locker locked(isolate_holder_->isolate());
-    DumpMemoryStatistics(pmd);
+    DumpHeapSpacesStatistics(process_memory_dump, space_dump_name);
+    DumpHeapObjectStatistics(process_memory_dump, object_dump_name);
   } else {
-    DumpMemoryStatistics(pmd);
+    DumpHeapSpacesStatistics(process_memory_dump, space_dump_name);
+    DumpHeapObjectStatistics(process_memory_dump, object_dump_name);
   }
   return true;
 }
 
-void V8IsolateMemoryDumpProvider::DumpMemoryStatistics(
-    base::trace_event::ProcessMemoryDump* pmd) {
+void V8IsolateMemoryDumpProvider::DumpHeapSpacesStatistics(
+    base::trace_event::ProcessMemoryDump* process_memory_dump,
+    const std::string& dump_base_name) {
   v8::HeapStatistics heap_statistics;
   isolate_holder_->isolate()->GetHeapStatistics(&heap_statistics);
 
@@ -67,18 +76,12 @@
     known_spaces_used_size += space_used_size;
     known_spaces_available_size += space_available_size;
 
-    std::string allocator_name =
-        base::StringPrintf("%s/%s_%p/%s/%s", kRootDumpName, kIsolateDumpName,
-                           isolate_holder_->isolate(), kHeapSpacesDumpName,
-                           space_statistics.space_name());
     base::trace_event::MemoryAllocatorDump* space_dump =
-        pmd->CreateAllocatorDump(allocator_name);
+        process_memory_dump->CreateAllocatorDump(dump_base_name + "/" +
+                                                 space_statistics.space_name());
     space_dump->AddScalar(
         base::trace_event::MemoryAllocatorDump::kNameOuterSize,
         base::trace_event::MemoryAllocatorDump::kUnitsBytes, space_size);
-
-    // TODO(ssid): Fix crbug.com/481504 to get the objects count of live objects
-    // after the last GC.
     space_dump->AddScalar(
         base::trace_event::MemoryAllocatorDump::kNameInnerSize,
         base::trace_event::MemoryAllocatorDump::kUnitsBytes, space_used_size);
@@ -86,12 +89,11 @@
                           base::trace_event::MemoryAllocatorDump::kUnitsBytes,
                           space_available_size);
   }
+
   // Compute the rest of the memory, not accounted by the spaces above.
-  std::string allocator_name = base::StringPrintf(
-      "%s/%s_%p/%s/%s", kRootDumpName, kIsolateDumpName,
-      isolate_holder_->isolate(), kHeapSpacesDumpName, "other_spaces");
   base::trace_event::MemoryAllocatorDump* other_spaces_dump =
-      pmd->CreateAllocatorDump(allocator_name);
+      process_memory_dump->CreateAllocatorDump(dump_base_name +
+                                               "/other_spaces");
   other_spaces_dump->AddScalar(
       base::trace_event::MemoryAllocatorDump::kNameOuterSize,
       base::trace_event::MemoryAllocatorDump::kUnitsBytes,
@@ -107,4 +109,39 @@
       heap_statistics.total_available_size() - known_spaces_available_size);
 }
 
+void V8IsolateMemoryDumpProvider::DumpHeapObjectStatistics(
+    base::trace_event::ProcessMemoryDump* process_memory_dump,
+    const std::string& dump_base_name) {
+  const size_t object_types =
+      isolate_holder_->isolate()->NumberOfTrackedHeapObjectTypes();
+  for (size_t type_index = 0; type_index < object_types; type_index++) {
+    v8::HeapObjectStatistics object_statistics;
+    if (!isolate_holder_->isolate()->GetHeapObjectStatisticsAtLastGC(
+            &object_statistics, type_index))
+      continue;
+
+    std::string dump_name =
+        dump_base_name + "/" + object_statistics.object_type();
+    if (object_statistics.object_sub_type()[0] != '\0')
+      dump_name += std::string("/") + object_statistics.object_sub_type();
+    base::trace_event::MemoryAllocatorDump* object_dump =
+        process_memory_dump->CreateAllocatorDump(dump_name);
+
+    object_dump->AddScalar(
+        base::trace_event::MemoryAllocatorDump::kNameObjectsCount,
+        base::trace_event::MemoryAllocatorDump::kUnitsObjects,
+        object_statistics.object_count());
+    object_dump->AddScalar(
+        base::trace_event::MemoryAllocatorDump::kNameInnerSize,
+        base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+        object_statistics.object_size());
+  }
+
+  process_memory_dump->AddOwnershipEdge(
+      process_memory_dump->CreateAllocatorDump(dump_base_name +
+                                               "/CODE_TYPE/CODE_KIND")->guid(),
+      process_memory_dump->CreateAllocatorDump(dump_base_name +
+                                               "/CODE_TYPE/CODE_AGE")->guid());
+}
+
 }  // namespace gin
diff --git a/gin/v8_isolate_memory_dump_provider.h b/gin/v8_isolate_memory_dump_provider.h
index 41683b2..99a050b 100644
--- a/gin/v8_isolate_memory_dump_provider.h
+++ b/gin/v8_isolate_memory_dump_provider.h
@@ -5,6 +5,8 @@
 #ifndef GIN_V8_ISOLATE_MEMORY_DUMP_PROVIDER_H_
 #define GIN_V8_ISOLATE_MEMORY_DUMP_PROVIDER_H_
 
+#include <string>
+
 #include "base/trace_event/memory_dump_provider.h"
 #include "gin/gin_export.h"
 
@@ -21,12 +23,18 @@
   ~V8IsolateMemoryDumpProvider() override;
 
   // MemoryDumpProvider implementation.
-  bool OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd) override;
+  bool OnMemoryDump(
+      base::trace_event::ProcessMemoryDump* process_memory_dump) override;
 
  private:
   IsolateHolder* isolate_holder_;  // Not owned.
 
-  void DumpMemoryStatistics(base::trace_event::ProcessMemoryDump* pmd);
+  void DumpHeapSpacesStatistics(
+      base::trace_event::ProcessMemoryDump* process_memory_dump,
+      const std::string& dump_base_name);
+  void DumpHeapObjectStatistics(
+      base::trace_event::ProcessMemoryDump* process_memory_dump,
+      const std::string& dump_base_name);
 
   DISALLOW_COPY_AND_ASSIGN(V8IsolateMemoryDumpProvider);
 };
diff --git a/gin/v8_isolate_memory_dump_provider_unittest.cc b/gin/v8_isolate_memory_dump_provider_unittest.cc
new file mode 100644
index 0000000..b1693cd
--- /dev/null
+++ b/gin/v8_isolate_memory_dump_provider_unittest.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 "gin/v8_isolate_memory_dump_provider.h"
+
+#include "base/trace_event/process_memory_dump.h"
+#include "gin/public/isolate_holder.h"
+#include "gin/test/v8_test.h"
+
+namespace gin {
+
+typedef V8Test V8MemoryDumpProviderTest;
+
+// Checks if the dump provider runs without crashing and dumps root objects.
+TEST_F(V8MemoryDumpProviderTest, DumpStatistics) {
+  // Sets the track objects flag for dumping object statistics. Since this is
+  // not set before V8::InitializePlatform the sizes will not be accurate, but
+  // this serves the purpose of this test.
+  const char track_objects_flag[] = "--track-gc-object-stats";
+  v8::V8::SetFlagsFromString(track_objects_flag,
+                             static_cast<int>(strlen(track_objects_flag)));
+
+  scoped_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
+      new base::trace_event::ProcessMemoryDump(nullptr));
+  instance_->isolate_memory_dump_provider_for_testing()->OnMemoryDump(
+      process_memory_dump.get());
+  const base::trace_event::ProcessMemoryDump::AllocatorDumpsMap&
+      allocator_dumps = process_memory_dump->allocator_dumps();
+
+  bool did_dump_isolate_stats = false;
+  bool did_dump_space_stats = false;
+  bool did_dump_objects_stats = false;
+  for (const auto& it : allocator_dumps) {
+    const std::string& dump_name = it.first;
+    if (dump_name.find("v8/isolate") != std::string::npos) {
+      did_dump_isolate_stats = true;
+    }
+    if (dump_name.find("heap_spaces") != std::string::npos) {
+      did_dump_space_stats = true;
+    } else if (dump_name.find("heap_objects") != std::string::npos) {
+      did_dump_objects_stats = true;
+    }
+  }
+
+  ASSERT_TRUE(did_dump_isolate_stats);
+  ASSERT_TRUE(did_dump_space_stats);
+  ASSERT_TRUE(did_dump_objects_stats);
+}
+
+}  // namespace gin
diff --git a/google_apis/gaia/fake_gaia.cc b/google_apis/gaia/fake_gaia.cc
index 88fb274..456d8db 100644
--- a/google_apis/gaia/fake_gaia.cc
+++ b/google_apis/gaia/fake_gaia.cc
@@ -51,7 +51,7 @@
 const char kTestOAuthLoginLSID[] = "fake-oauth-LSID-cookie";
 const char kTestOAuthLoginAuthCode[] = "fake-oauth-auth-code";
 
-const char kDefaultGaiaId[]  ="12345";
+const char kDefaultGaiaId[] = "12345";
 
 const base::FilePath::CharType kServiceLogin[] =
     FILE_PATH_LITERAL("google_apis/test/service_login.html");
@@ -64,7 +64,7 @@
 const char kAuthHeaderOAuth[] = "OAuth ";
 
 const char kListAccountsResponseFormat[] =
-    "[\"gaia.l.a.r\",[[\"gaia.l.a\",1,\"\",\"%s\",\"\",1,1,0]]]";
+    "[\"gaia.l.a.r\",[[\"gaia.l.a\",1,\"\",\"%s\",\"\",1,1,0,0,1,\"12345\"]]]";
 
 typedef std::map<std::string, std::string> CookieMap;
 
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc
index 42134bb..eaae715 100644
--- a/google_apis/gaia/gaia_auth_fetcher.cc
+++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -224,6 +224,10 @@
   return fetch_pending_;
 }
 
+void GaiaAuthFetcher::SetPendingFetch(bool pending_fetch) {
+  fetch_pending_ = pending_fetch;
+}
+
 void GaiaAuthFetcher::CancelRequest() {
   fetcher_.reset();
   fetch_pending_ = false;
diff --git a/google_apis/gaia/gaia_auth_fetcher.h b/google_apis/gaia/gaia_auth_fetcher.h
index 8910cfd6..163db748 100644
--- a/google_apis/gaia/gaia_auth_fetcher.h
+++ b/google_apis/gaia/gaia_auth_fetcher.h
@@ -224,7 +224,7 @@
   bool HasPendingFetch();
 
   // Stop any URL fetches in progress.
-  void CancelRequest();
+  virtual void CancelRequest();
 
   // From a URLFetcher result, generate an appropriate error.
   // From the API documentation, both IssueAuthToken and ClientLogin have
@@ -255,6 +255,8 @@
                               const net::URLRequestStatus& status,
                               int response_code);
 
+  void SetPendingFetch(bool pending_fetch);
+
  private:
   // ClientLogin body constants that don't change
   static const char kCookiePersistence[];
diff --git a/google_apis/gaia/gaia_auth_util.cc b/google_apis/gaia/gaia_auth_util.cc
index 3a9ccab6..33be5a8 100644
--- a/google_apis/gaia/gaia_auth_util.cc
+++ b/google_apis/gaia/gaia_auth_util.cc
@@ -43,6 +43,18 @@
 
 }  // namespace
 
+
+ListedAccount::ListedAccount() {}
+
+ListedAccount::~ListedAccount() {}
+
+bool ListedAccount::operator==(const ListedAccount& other) const {
+  return email == other.email &&
+         gaia_id == other.gaia_id &&
+         valid == other.valid &&
+         raw_email == other.raw_email;
+}
+
 std::string CanonicalizeEmail(const std::string& email_address) {
   // CanonicalizeEmail() is called to process email strings that are eventually
   // shown to the user, and may also be used in persisting email strings.  To
@@ -94,8 +106,7 @@
 
 
 bool ParseListAccountsData(
-    const std::string& data,
-    std::vector<std::pair<std::string, bool> >* accounts) {
+    const std::string& data, std::vector<ListedAccount>* accounts) {
   accounts->clear();
 
   // Parse returned data and make sure we have data.
@@ -128,8 +139,16 @@
         if (!account->GetInteger(9, &is_email_valid))
           is_email_valid = 1;
 
-        accounts->push_back(
-            std::make_pair(CanonicalizeEmail(email), is_email_valid != 0));
+        std::string gaia_id;
+        // ListAccounts must also return the Gaia Id.
+        if (account->GetString(10, &gaia_id) && !gaia_id.empty()) {
+          ListedAccount listed_account;
+          listed_account.email = CanonicalizeEmail(email);
+          listed_account.gaia_id = gaia_id;
+          listed_account.valid = is_email_valid != 0;
+          listed_account.raw_email = email;
+          accounts->push_back(listed_account);
+        }
       }
     }
   }
diff --git a/google_apis/gaia/gaia_auth_util.h b/google_apis/gaia/gaia_auth_util.h
index 9b90f8a..5e756457 100644
--- a/google_apis/gaia/gaia_auth_util.h
+++ b/google_apis/gaia/gaia_auth_util.h
@@ -13,6 +13,20 @@
 
 namespace gaia {
 
+struct ListedAccount {
+  // The account's ID, as per Chrome, will be determined in the
+  // CookieManagerService.
+  std::string id;
+  std::string email;
+  std::string gaia_id;
+  std::string raw_email;
+  bool valid;
+
+  ListedAccount();
+  ~ListedAccount();
+  bool operator==(const ListedAccount& other) const;
+};
+
 // Perform basic canonicalization of |email_address|, taking into account that
 // gmail does not consider '.' or caps inside a username to matter.
 std::string CanonicalizeEmail(const std::string& email_address);
@@ -38,8 +52,7 @@
 // login would succeed (i.e. the user does not need to reauthenticate).
 // If there an error parsing the JSON, then false is returned.
 bool ParseListAccountsData(
-    const std::string& data,
-    std::vector<std::pair<std::string, bool> >* accounts);
+    const std::string& data, std::vector<ListedAccount>* accounts);
 
 }  // namespace gaia
 
diff --git a/google_apis/gaia/gaia_auth_util_unittest.cc b/google_apis/gaia/gaia_auth_util_unittest.cc
index b17ac575..98e1b76 100644
--- a/google_apis/gaia/gaia_auth_util_unittest.cc
+++ b/google_apis/gaia/gaia_auth_util_unittest.cc
@@ -109,7 +109,7 @@
 }
 
 TEST(GaiaAuthUtilTest, ParseListAccountsData) {
-  std::vector<std::pair<std::string, bool> > accounts;
+  std::vector<ListedAccount> accounts;
   ASSERT_FALSE(ParseListAccountsData("", &accounts));
   ASSERT_EQ(0u, accounts.size());
 
@@ -130,58 +130,73 @@
   ASSERT_EQ(0u, accounts.size());
 
   ASSERT_TRUE(ParseListAccountsData(
-      "[\"foo\", [[\"bar\", 0, \"name\", \"u@g.c\", \"photo\", 0, 0, 0]]]",
+      "[\"foo\", "
+          "[[\"bar\", 0, \"name\", \"u@g.c\", \"p\", 0, 0, 0, 0, 1, \"45\"]]]",
       &accounts));
   ASSERT_EQ(1u, accounts.size());
-  ASSERT_EQ("u@g.c", accounts[0].first);
-  ASSERT_TRUE(accounts[0].second);
+  ASSERT_EQ("u@g.c", accounts[0].email);
+  ASSERT_TRUE(accounts[0].valid);
 
   ASSERT_TRUE(ParseListAccountsData(
-      "[\"foo\", [[\"bar1\", 0, \"name1\", \"u1@g.c\", \"photo1\", 0, 0, 0], "
-                 "[\"bar2\", 0, \"name2\", \"u2@g.c\", \"photo2\", 0, 0, 0]]]",
+      "[\"foo\", "
+          "[[\"bar1\",0,\"name1\",\"u1@g.c\",\"photo1\",0,0,0,0,1,\"45\"], "
+          "[\"bar2\",0,\"name2\",\"u2@g.c\",\"photo2\",0,0,0,0,1,\"6\"]]]",
       &accounts));
   ASSERT_EQ(2u, accounts.size());
-  ASSERT_EQ("u1@g.c", accounts[0].first);
-  ASSERT_TRUE(accounts[0].second);
-  ASSERT_EQ("u2@g.c", accounts[1].first);
-  ASSERT_TRUE(accounts[1].second);
+  ASSERT_EQ("u1@g.c", accounts[0].email);
+  ASSERT_TRUE(accounts[0].valid);
+  ASSERT_EQ("u2@g.c", accounts[1].email);
+  ASSERT_TRUE(accounts[1].valid);
 
   ASSERT_TRUE(ParseListAccountsData(
-      "[\"foo\", [[\"b1\", 0, \"name1\", \"U1@g.c\", \"photo1\", 0, 0, 0], "
-                 "[\"b2\", 0, \"name2\", \"u.2@g.c\", \"photo2\", 0, 0, 0]]]",
+      "[\"foo\", "
+          "[[\"b1\", 0,\"name1\",\"U1@g.c\",\"photo1\",0,0,0,0,1,\"45\"], "
+          "[\"b2\",0,\"name2\",\"u.2@g.c\",\"photo2\",0,0,0,0,1,\"46\"]]]",
       &accounts));
   ASSERT_EQ(2u, accounts.size());
-  ASSERT_EQ(CanonicalizeEmail("U1@g.c"), accounts[0].first);
-  ASSERT_TRUE(accounts[0].second);
-  ASSERT_EQ(CanonicalizeEmail("u.2@g.c"), accounts[1].first);
-  ASSERT_TRUE(accounts[1].second);
+  ASSERT_EQ(CanonicalizeEmail("U1@g.c"), accounts[0].email);
+  ASSERT_TRUE(accounts[0].valid);
+  ASSERT_EQ(CanonicalizeEmail("u.2@g.c"), accounts[1].email);
+  ASSERT_TRUE(accounts[1].valid);
 }
 
 TEST(GaiaAuthUtilTest, ParseListAccountsDataValidSession) {
-  std::vector<std::pair<std::string, bool> > accounts;
-
-  // Missing valid session means: return account.
-  ASSERT_TRUE(ParseListAccountsData(
-      "[\"foo\", [[\"b\", 0, \"n\", \"u@g.c\", \"p\", 0, 0, 0]]]",
-      &accounts));
-  ASSERT_EQ(1u, accounts.size());
-  ASSERT_EQ("u@g.c", accounts[0].first);
-  ASSERT_TRUE(accounts[0].second);
+  std::vector<ListedAccount> accounts;
 
   // Valid session is true means: return account.
   ASSERT_TRUE(ParseListAccountsData(
-      "[\"foo\", [[\"b\", 0, \"n\", \"u@g.c\", \"p\", 0, 0, 0, 0, 1]]]",
+      "[\"foo\", [[\"b\",0,\"n\",\"u@g.c\",\"photo\",0,0,0,0,1,\"45\"]]]",
       &accounts));
   ASSERT_EQ(1u, accounts.size());
-  ASSERT_EQ("u@g.c", accounts[0].first);
-  ASSERT_TRUE(accounts[0].second);
+  ASSERT_EQ("u@g.c", accounts[0].email);
+  ASSERT_TRUE(accounts[0].valid);
 
   // Valid session is false means: return account with valid bit false.
   ASSERT_TRUE(ParseListAccountsData(
-      "[\"foo\", [[\"b\", 0, \"n\", \"u@g.c\", \"p\", 0, 0, 0, 0, 0]]]",
+      "[\"foo\", [[\"b\",0,\"n\",\"u@g.c\",\"photo\",0,0,0,0,0,\"45\"]]]",
       &accounts));
   ASSERT_EQ(1u, accounts.size());
-  ASSERT_FALSE(accounts[0].second);
+  ASSERT_FALSE(accounts[0].valid);
+}
+
+TEST(GaiaAuthUtilTest, ParseListAccountsDataGaiaId) {
+  std::vector<ListedAccount> accounts;
+
+  // Missing gaia id means: do not return account.
+  ASSERT_TRUE(ParseListAccountsData(
+      "[\"foo\", [[\"b\", 0, \"n\", \"u@g.c\", \"photo\", 0, 0, 0, 0, 1]]]",
+      &accounts));
+  ASSERT_EQ(0u, accounts.size());
+
+  // Valid gaia session means: return gaia session
+  ASSERT_TRUE(ParseListAccountsData(
+      "[\"foo\", "
+          "[[\"b\",0,\"n\",\"u@g.c\",\"photo\",0,0,0,0,1,\"9863\"]]]",
+      &accounts));
+  ASSERT_EQ(1u, accounts.size());
+  ASSERT_EQ("u@g.c", accounts[0].email);
+  ASSERT_TRUE(accounts[0].valid);
+  ASSERT_EQ("9863", accounts[0].gaia_id);
 }
 
 }  // namespace gaia
diff --git a/google_apis/gaia/ubertoken_fetcher.cc b/google_apis/gaia/ubertoken_fetcher.cc
index 24cb53d8..d72c60c 100644
--- a/google_apis/gaia/ubertoken_fetcher.cc
+++ b/google_apis/gaia/ubertoken_fetcher.cc
@@ -15,6 +15,15 @@
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 
+namespace {
+GaiaAuthFetcher* CreateGaiaAuthFetcher(
+    GaiaAuthConsumer* consumer,
+    const std::string& source,
+    net::URLRequestContextGetter* request_context) {
+  return new GaiaAuthFetcher(consumer, source, request_context);
+}
+}
+
 const int UbertokenFetcher::kMaxRetries = 3;
 
 UbertokenFetcher::UbertokenFetcher(
@@ -22,11 +31,25 @@
     UbertokenConsumer* consumer,
     const std::string& source,
     net::URLRequestContextGetter* request_context)
+    : UbertokenFetcher(token_service,
+                       consumer,
+                       source,
+                       request_context,
+                       base::Bind(CreateGaiaAuthFetcher)) {
+}
+
+UbertokenFetcher::UbertokenFetcher(
+    OAuth2TokenService* token_service,
+    UbertokenConsumer* consumer,
+    const std::string& source,
+    net::URLRequestContextGetter* request_context,
+    GaiaAuthFetcherFactory factory)
     : OAuth2TokenService::Consumer("uber_token_fetcher"),
       token_service_(token_service),
       consumer_(consumer),
       source_(source),
       request_context_(request_context),
+      gaia_auth_fetcher_factory_(factory),
       retry_number_(0),
       second_access_token_request_(false) {
   DCHECK(token_service);
@@ -126,8 +149,7 @@
 }
 
 void UbertokenFetcher::ExchangeTokens() {
-  gaia_auth_fetcher_.reset(new GaiaAuthFetcher(this,
-                                               source_,
-                                               request_context_));
+  gaia_auth_fetcher_.reset(
+      gaia_auth_fetcher_factory_.Run(this, source_, request_context_));
   gaia_auth_fetcher_->StartTokenFetchForUberAuthExchange(access_token_);
 }
diff --git a/google_apis/gaia/ubertoken_fetcher.h b/google_apis/gaia/ubertoken_fetcher.h
index c74aa6c..ade53cc 100644
--- a/google_apis/gaia/ubertoken_fetcher.h
+++ b/google_apis/gaia/ubertoken_fetcher.h
@@ -26,6 +26,11 @@
 class URLRequestContextGetter;
 }
 
+typedef base::Callback<GaiaAuthFetcher*(GaiaAuthConsumer*,
+                                        const std::string&,
+                                        net::URLRequestContextGetter*)>
+    GaiaAuthFetcherFactory;
+
 // Callback for the |UbertokenFetcher| class.
 class UbertokenConsumer {
  public:
@@ -46,6 +51,11 @@
                    UbertokenConsumer* consumer,
                    const std::string& source,
                    net::URLRequestContextGetter* request_context);
+  UbertokenFetcher(OAuth2TokenService* token_service,
+                   UbertokenConsumer* consumer,
+                   const std::string& source,
+                   net::URLRequestContextGetter* request_context,
+                   GaiaAuthFetcherFactory factory);
   ~UbertokenFetcher() override;
 
   // Start fetching the token for |account_id|.
@@ -75,6 +85,7 @@
   UbertokenConsumer* consumer_;
   std::string source_;
   net::URLRequestContextGetter* request_context_;
+  GaiaAuthFetcherFactory gaia_auth_fetcher_factory_;
   scoped_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
   scoped_ptr<OAuth2TokenService::Request> access_token_request_;
   std::string account_id_;
diff --git a/google_apis/gcm/engine/gcm_registration_request_handler.cc b/google_apis/gcm/engine/gcm_registration_request_handler.cc
index c0213f3..9533165 100644
--- a/google_apis/gcm/engine/gcm_registration_request_handler.cc
+++ b/google_apis/gcm/engine/gcm_registration_request_handler.cc
@@ -4,6 +4,7 @@
 
 #include "google_apis/gcm/engine/gcm_registration_request_handler.h"
 
+#include "base/metrics/histogram.h"
 #include "google_apis/gcm/base/gcm_util.h"
 
 namespace gcm {
@@ -26,4 +27,20 @@
   BuildFormEncoding(kSenderKey, senders_, body);
 }
 
+void GCMRegistrationRequestHandler::ReportUMAs(
+    RegistrationRequest::Status status,
+    int retry_count,
+    base::TimeDelta complete_time) {
+  UMA_HISTOGRAM_ENUMERATION("GCM.RegistrationRequestStatus",
+                            status,
+                            RegistrationRequest::STATUS_COUNT);
+
+  // Other UMAs are only reported when the request succeeds.
+  if (status != RegistrationRequest::SUCCESS)
+    return;
+
+  UMA_HISTOGRAM_COUNTS("GCM.RegistrationRetryCount", retry_count);
+  UMA_HISTOGRAM_TIMES("GCM.RegistrationCompleteTime", complete_time);
+}
+
 }  // namespace gcm
diff --git a/google_apis/gcm/engine/gcm_registration_request_handler.h b/google_apis/gcm/engine/gcm_registration_request_handler.h
index 26ba49d8..934f927 100644
--- a/google_apis/gcm/engine/gcm_registration_request_handler.h
+++ b/google_apis/gcm/engine/gcm_registration_request_handler.h
@@ -18,6 +18,9 @@
 
   // RegistrationRequest::RequestHandler overrides:
   void BuildRequestBody(std::string* body) override;
+  void ReportUMAs(RegistrationRequest::Status status,
+                  int retry_count,
+                  base::TimeDelta complete_time) override;
 
  private:
   std::string senders_;
diff --git a/google_apis/gcm/engine/gcm_store_impl.cc b/google_apis/gcm/engine/gcm_store_impl.cc
index 3436ba9..b90630a 100644
--- a/google_apis/gcm/engine/gcm_store_impl.cc
+++ b/google_apis/gcm/engine/gcm_store_impl.cc
@@ -17,6 +17,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/tracked_objects.h"
@@ -336,6 +337,17 @@
     return;
   }
 
+  // |result->registrations| contains both GCM registrations and InstanceID
+  // tokens. Count them separately.
+  int gcm_registration_count = 0;
+  int instance_id_token_count = 0;
+  for (const auto& registration : result->registrations) {
+    if (StartsWithASCII(registration.first, "iid-", true))
+      instance_id_token_count++;
+    else
+      gcm_registration_count++;
+  }
+
   // Only record histograms if GCM had already been set up for this device.
   if (result->device_android_id != 0 && result->device_security_token != 0) {
     int64 file_size = 0;
@@ -343,20 +355,27 @@
       UMA_HISTOGRAM_COUNTS("GCM.StoreSizeKB",
                            static_cast<int>(file_size / 1024));
     }
-    UMA_HISTOGRAM_COUNTS("GCM.RestoredRegistrations",
-                         result->registrations.size());
+
+    UMA_HISTOGRAM_COUNTS("GCM.RestoredRegistrations", gcm_registration_count);
     UMA_HISTOGRAM_COUNTS("GCM.RestoredOutgoingMessages",
                          result->outgoing_messages.size());
     UMA_HISTOGRAM_COUNTS("GCM.RestoredIncomingMessages",
                          result->incoming_messages.size());
+
+    UMA_HISTOGRAM_COUNTS("InstanceID.RestoredTokenCount",
+                         instance_id_token_count);
+    UMA_HISTOGRAM_COUNTS("InstanceID.RestoredIDCount",
+                         result->instance_id_data.size());
   }
 
-  DVLOG(1) << "Succeeded in loading " << result->registrations.size()
-           << " registrations, "
+  DVLOG(1) << "Succeeded in loading "
+           << gcm_registration_count << " GCM registrations, "
            << result->incoming_messages.size()
-           << " unacknowledged incoming messages and "
+           << " unacknowledged incoming messages "
            << result->outgoing_messages.size()
-           << " unacknowledged outgoing messages.";
+           << " unacknowledged outgoing messages, "
+           << result->instance_id_data.size() << " Instance IDs, "
+           << instance_id_token_count << " InstanceID tokens.";
   result->success = true;
   foreground_task_runner_->PostTask(FROM_HERE,
                                     base::Bind(callback,
diff --git a/google_apis/gcm/engine/gcm_unregistration_request_handler.cc b/google_apis/gcm/engine/gcm_unregistration_request_handler.cc
index 86f473b..5d37382c 100644
--- a/google_apis/gcm/engine/gcm_unregistration_request_handler.cc
+++ b/google_apis/gcm/engine/gcm_unregistration_request_handler.cc
@@ -4,6 +4,7 @@
 
 #include "google_apis/gcm/engine/gcm_unregistration_request_handler.h"
 
+#include "base/metrics/histogram.h"
 #include "google_apis/gcm/base/gcm_util.h"
 #include "net/url_request/url_fetcher.h"
 
@@ -65,4 +66,20 @@
   return UnregistrationRequest::RESPONSE_PARSING_FAILED;
 }
 
+void GCMUnregistrationRequestHandler::ReportUMAs(
+    UnregistrationRequest::Status status,
+    int retry_count,
+    base::TimeDelta complete_time) {
+  UMA_HISTOGRAM_ENUMERATION("GCM.UnregistrationRequestStatus",
+                            status,
+                            UnregistrationRequest::UNREGISTRATION_STATUS_COUNT);
+
+  // Other UMAs are only reported when the request succeeds.
+  if (status != UnregistrationRequest::SUCCESS)
+    return;
+
+  UMA_HISTOGRAM_COUNTS("GCM.UnregistrationRetryCount", retry_count);
+  UMA_HISTOGRAM_TIMES("GCM.UnregistrationCompleteTime", complete_time);
+}
+
 }  // namespace gcm
diff --git a/google_apis/gcm/engine/gcm_unregistration_request_handler.h b/google_apis/gcm/engine/gcm_unregistration_request_handler.h
index ac2a5d4a..e66f355 100644
--- a/google_apis/gcm/engine/gcm_unregistration_request_handler.h
+++ b/google_apis/gcm/engine/gcm_unregistration_request_handler.h
@@ -21,6 +21,9 @@
   void BuildRequestBody(std::string* body) override;
   UnregistrationRequest::Status ParseResponse(
       const net::URLFetcher* source) override;
+  void ReportUMAs(UnregistrationRequest::Status status,
+                  int retry_count,
+                  base::TimeDelta complete_time) override;
 
  private:
   std::string app_id_;
diff --git a/google_apis/gcm/engine/instance_id_delete_token_request_handler.cc b/google_apis/gcm/engine/instance_id_delete_token_request_handler.cc
index 2ee4713..82de88a 100644
--- a/google_apis/gcm/engine/instance_id_delete_token_request_handler.cc
+++ b/google_apis/gcm/engine/instance_id_delete_token_request_handler.cc
@@ -4,6 +4,7 @@
 
 #include "google_apis/gcm/engine/instance_id_delete_token_request_handler.h"
 
+#include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "google_apis/gcm/base/gcm_util.h"
 #include "net/url_request/url_fetcher.h"
@@ -66,4 +67,20 @@
   return UnregistrationRequest::SUCCESS;
 }
 
+void InstanceIDDeleteTokenRequestHandler::ReportUMAs(
+    UnregistrationRequest::Status status,
+    int retry_count,
+    base::TimeDelta complete_time) {
+  UMA_HISTOGRAM_ENUMERATION("InstanceID.DeleteToken.RequestStatus",
+                            status,
+                            UnregistrationRequest::UNREGISTRATION_STATUS_COUNT);
+
+  // Other UMAs are only reported when the request succeeds.
+  if (status != UnregistrationRequest::SUCCESS)
+    return;
+
+  UMA_HISTOGRAM_COUNTS("InstanceID.DeleteToken.RetryCount", retry_count);
+  UMA_HISTOGRAM_TIMES("InstanceID.DeleteToken.CompleteTime", complete_time);
+}
+
 }  // namespace gcm
diff --git a/google_apis/gcm/engine/instance_id_delete_token_request_handler.h b/google_apis/gcm/engine/instance_id_delete_token_request_handler.h
index fec6e04d..cd10d346 100644
--- a/google_apis/gcm/engine/instance_id_delete_token_request_handler.h
+++ b/google_apis/gcm/engine/instance_id_delete_token_request_handler.h
@@ -26,6 +26,9 @@
   void BuildRequestBody(std::string* body) override;
   UnregistrationRequest::Status ParseResponse(
       const net::URLFetcher* source) override;
+  void ReportUMAs(UnregistrationRequest::Status status,
+                  int retry_count,
+                  base::TimeDelta complete_time) override;
 
  private:
   std::string instance_id_;
diff --git a/google_apis/gcm/engine/instance_id_get_token_request_handler.cc b/google_apis/gcm/engine/instance_id_get_token_request_handler.cc
index ebf6279..1ca735b 100644
--- a/google_apis/gcm/engine/instance_id_get_token_request_handler.cc
+++ b/google_apis/gcm/engine/instance_id_get_token_request_handler.cc
@@ -4,6 +4,7 @@
 
 #include "google_apis/gcm/engine/instance_id_get_token_request_handler.h"
 
+#include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "google_apis/gcm/base/gcm_util.h"
 #include "net/url_request/url_request_context_getter.h"
@@ -53,4 +54,20 @@
   BuildFormEncoding(kSubtypeKey, authorized_entity_, body);
 }
 
+void InstanceIDGetTokenRequestHandler::ReportUMAs(
+    RegistrationRequest::Status status,
+    int retry_count,
+    base::TimeDelta complete_time) {
+  UMA_HISTOGRAM_ENUMERATION("InstanceID.GetToken.RequestStatus",
+                            status,
+                            RegistrationRequest::STATUS_COUNT);
+
+  // Other UMAs are only reported when the request succeeds.
+  if (status != RegistrationRequest::SUCCESS)
+    return;
+
+  UMA_HISTOGRAM_COUNTS("InstanceID.GetToken.RetryCount", retry_count);
+  UMA_HISTOGRAM_TIMES("InstanceID.GetToken.CompleteTime", complete_time);
+}
+
 }  // namespace gcm
diff --git a/google_apis/gcm/engine/instance_id_get_token_request_handler.h b/google_apis/gcm/engine/instance_id_get_token_request_handler.h
index c09b1ab..de92ab9 100644
--- a/google_apis/gcm/engine/instance_id_get_token_request_handler.h
+++ b/google_apis/gcm/engine/instance_id_get_token_request_handler.h
@@ -26,6 +26,9 @@
 
    // RegistrationRequest overrides:
   void BuildRequestBody(std::string* body) override;
+  void ReportUMAs(RegistrationRequest::Status status,
+                  int retry_count,
+                  base::TimeDelta complete_time) override;
 
  private:
   std::string instance_id_;
diff --git a/google_apis/gcm/engine/registration_request.cc b/google_apis/gcm/engine/registration_request.cc
index b30bc4c..6537389 100644
--- a/google_apis/gcm/engine/registration_request.cc
+++ b/google_apis/gcm/engine/registration_request.cc
@@ -65,11 +65,6 @@
          status == RegistrationRequest::RESPONSE_PARSING_FAILED;
 }
 
-void RecordRegistrationStatusToUMA(RegistrationRequest::Status status) {
-  UMA_HISTOGRAM_ENUMERATION("GCM.RegistrationRequestStatus", status,
-                            RegistrationRequest::STATUS_COUNT);
-}
-
 }  // namespace
 
 RegistrationRequest::RequestInfo::RequestInfo(
@@ -228,12 +223,17 @@
 void RegistrationRequest::OnURLFetchComplete(const net::URLFetcher* source) {
   std::string token;
   Status status = ParseResponse(source, &token);
-  RecordRegistrationStatusToUMA(status);
   recorder_->RecordRegistrationResponse(
       request_info_.app_id,
       source_to_record_,
       status);
 
+  DCHECK(custom_request_handler_.get());
+  custom_request_handler_->ReportUMAs(
+      status,
+      backoff_entry_.failure_count(),
+      base::TimeTicks::Now() - request_start_time_);
+
   if (ShouldRetryWithStatus(status)) {
     if (retries_left_ > 0) {
       recorder_->RecordRegistrationRetryRequested(
@@ -249,15 +249,13 @@
         request_info_.app_id,
         source_to_record_,
         status);
-    RecordRegistrationStatusToUMA(status);
+
+    // Only REACHED_MAX_RETRIES is reported because the function will skip
+    // reporting count and time when status is not SUCCESS.
+    DCHECK(custom_request_handler_.get());
+    custom_request_handler_->ReportUMAs(status, 0, base::TimeDelta());
   }
 
-  if (status == SUCCESS) {
-    UMA_HISTOGRAM_COUNTS("GCM.RegistrationRetryCount",
-                         backoff_entry_.failure_count());
-    UMA_HISTOGRAM_TIMES("GCM.RegistrationCompleteTime",
-                        base::TimeTicks::Now() - request_start_time_);
-  }
   callback_.Run(status, token);
 }
 
diff --git a/google_apis/gcm/engine/registration_request.h b/google_apis/gcm/engine/registration_request.h
index c4c3ae7..96d77fd 100644
--- a/google_apis/gcm/engine/registration_request.h
+++ b/google_apis/gcm/engine/registration_request.h
@@ -87,6 +87,11 @@
     // RegistrationRequest::BuildRequestBody to append more custom info to
     // |body|. Note that the request body is encoded in HTTP form format.
     virtual void BuildRequestBody(std::string* body) = 0;
+
+    // Reports various UMAs, including status, retry count and completion time.
+    virtual void ReportUMAs(Status status,
+                            int retry_count,
+                            base::TimeDelta complete_time) = 0;
   };
 
   RegistrationRequest(
diff --git a/google_apis/gcm/engine/unregistration_request.cc b/google_apis/gcm/engine/unregistration_request.cc
index 931a5e94..bb68c72 100644
--- a/google_apis/gcm/engine/unregistration_request.cc
+++ b/google_apis/gcm/engine/unregistration_request.cc
@@ -6,7 +6,6 @@
 
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
-#include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/values.h"
@@ -169,9 +168,13 @@
   UnregistrationRequest::Status status = ParseResponse(source);
 
   DVLOG(1) << "UnregistrationRequestStauts: " << status;
-  UMA_HISTOGRAM_ENUMERATION("GCM.UnregistrationRequestStatus",
-                            status,
-                            UNREGISTRATION_STATUS_COUNT);
+
+  DCHECK(custom_request_handler_.get());
+  custom_request_handler_->ReportUMAs(
+      status,
+      backoff_entry_.failure_count(),
+      base::TimeTicks::Now() - request_start_time_);
+
   recorder_->RecordUnregistrationResponse(request_info_.app_id, status);
 
   if (status == URL_FETCHING_FAILED ||
@@ -186,13 +189,6 @@
   // status == SUCCESS || HTTP_NOT_OK || NO_RESPONSE_BODY ||
   // INVALID_PARAMETERS || UNKNOWN_ERROR
 
-  if (status == SUCCESS) {
-    UMA_HISTOGRAM_COUNTS("GCM.UnregistrationRetryCount",
-                         backoff_entry_.failure_count());
-    UMA_HISTOGRAM_TIMES("GCM.UnregistrationCompleteTime",
-                        base::TimeTicks::Now() - request_start_time_);
-  }
-
   callback_.Run(status);
 }
 
diff --git a/google_apis/gcm/engine/unregistration_request.h b/google_apis/gcm/engine/unregistration_request.h
index 61d9bff2..0f54538f 100644
--- a/google_apis/gcm/engine/unregistration_request.h
+++ b/google_apis/gcm/engine/unregistration_request.h
@@ -86,6 +86,11 @@
     // Parses the HTTP response. It is called after
     // UnregistrationRequest::ParseResponse to proceed the parsing.
     virtual Status ParseResponse(const net::URLFetcher* source) = 0;
+
+    // Reports various UMAs, including status, retry count and completion time.
+    virtual void ReportUMAs(Status status,
+                            int retry_count,
+                            base::TimeDelta complete_time) = 0;
   };
 
   // Creates an instance of UnregistrationRequest. |callback| will be called
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index f64e6cf2..ab60f0d3 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -2725,8 +2725,12 @@
     'unsafe': True
   },
   'GetInternalformativ': {
-    'type': 'GETn',
+    'type': 'Custom',
+    'data_transfer_methods': ['shm'],
     'result': ['SizedResult<GLint>'],
+    'cmd_args':
+        'GLenumRenderBufferTarget target, GLenumRenderBufferFormat format, '
+        'GLenumInternalFormatParameter pname, GLint* params',
     'unsafe': True,
   },
   'GetMaxValueInBufferCHROMIUM': {
@@ -6376,11 +6380,9 @@
 }
 """
     else:
-     code = """  GLenum error = glGetError();
+     code = """  GLenum error = LOCAL_PEEK_GL_ERROR("%(func_name)s");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "%(func_name)s", "");
   }
   return error::kNoError;
 }
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index ed087ba..875cb7e 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -943,13 +943,12 @@
 void GetInternalformativ(GLenum target,
                          GLenum format,
                          GLenum pname,
-                         GLsizei bufSize,
                          uint32_t params_shm_id,
                          uint32_t params_shm_offset) {
   gles2::cmds::GetInternalformativ* c =
       GetCmdSpace<gles2::cmds::GetInternalformativ>();
   if (c) {
-    c->Init(target, format, pname, bufSize, params_shm_id, params_shm_offset);
+    c->Init(target, format, pname, params_shm_id, params_shm_offset);
   }
 }
 
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 7708bc12..e859299 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -5685,6 +5685,51 @@
   CheckGLError();
 }
 
+void GLES2Implementation::GetInternalformativ(
+    GLenum target, GLenum format, GLenum pname,
+    GLsizei buf_size, GLint* params) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetInternalformativ("
+                     << GLES2Util::GetStringRenderBufferTarget(target) << ", "
+                     << GLES2Util::GetStringRenderBufferFormat(format) << ", "
+                     << GLES2Util::GetStringInternalFormatParameter(pname)
+                     << ", " << buf_size << ", "
+                     << static_cast<const void*>(params) << ")");
+  if (buf_size < 0) {
+    SetGLError(GL_INVALID_VALUE, "glGetInternalformativ", "bufSize < 0");
+    return;
+  }
+  TRACE_EVENT0("gpu", "GLES2Implementation::GetInternalformativ");
+  if (GetInternalformativHelper(target, format, pname, buf_size, params)) {
+    return;
+  }
+  typedef cmds::GetInternalformativ::Result Result;
+  Result* result = GetResultAs<Result*>();
+  if (!result) {
+    return;
+  }
+  result->SetNumResults(0);
+  helper_->GetInternalformativ(target, format, pname,
+                               GetResultShmId(), GetResultShmOffset());
+  WaitForCmd();
+  GPU_CLIENT_LOG_CODE_BLOCK({
+    for (int32_t i = 0; i < result->GetNumResults(); ++i) {
+      GPU_CLIENT_LOG("  " << i << ": " << result->GetData()[i]);
+    }
+  });
+  if (buf_size > 0 && params) {
+    GLint* data = result->GetData();
+    if (buf_size >= result->GetNumResults()) {
+      buf_size = result->GetNumResults();
+    }
+    for (GLsizei ii = 0; ii < buf_size; ++ii) {
+      params[ii] = data[ii];
+    }
+  }
+  CheckGLError();
+}
+
 // Include the auto-generated part of this file. We split this because it means
 // we can easily edit the non-auto generated parts right here in this file
 // instead of having to edit some template or the code generator.
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index 4f4ee32..e386b514 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -1103,44 +1103,6 @@
   });
   CheckGLError();
 }
-void GLES2Implementation::GetInternalformativ(GLenum target,
-                                              GLenum format,
-                                              GLenum pname,
-                                              GLsizei bufSize,
-                                              GLint* params) {
-  GPU_CLIENT_SINGLE_THREAD_CHECK();
-  GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
-  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetInternalformativ("
-                     << GLES2Util::GetStringRenderBufferTarget(target) << ", "
-                     << GLES2Util::GetStringRenderBufferFormat(format) << ", "
-                     << GLES2Util::GetStringInternalFormatParameter(pname)
-                     << ", " << bufSize << ", "
-                     << static_cast<const void*>(params) << ")");
-  if (bufSize < 0) {
-    SetGLError(GL_INVALID_VALUE, "glGetInternalformativ", "bufSize < 0");
-    return;
-  }
-  TRACE_EVENT0("gpu", "GLES2Implementation::GetInternalformativ");
-  if (GetInternalformativHelper(target, format, pname, bufSize, params)) {
-    return;
-  }
-  typedef cmds::GetInternalformativ::Result Result;
-  Result* result = GetResultAs<Result*>();
-  if (!result) {
-    return;
-  }
-  result->SetNumResults(0);
-  helper_->GetInternalformativ(target, format, pname, bufSize, GetResultShmId(),
-                               GetResultShmOffset());
-  WaitForCmd();
-  result->CopyResult(params);
-  GPU_CLIENT_LOG_CODE_BLOCK({
-    for (int32_t i = 0; i < result->GetNumResults(); ++i) {
-      GPU_CLIENT_LOG("  " << i << ": " << result->GetData()[i]);
-    }
-  });
-  CheckGLError();
-}
 void GLES2Implementation::GetProgramiv(GLuint program,
                                        GLenum pname,
                                        GLint* params) {
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index 0b02f948..db978e1 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -3744,6 +3744,27 @@
   EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
 }
 
+TEST_F(GLES2ImplementationTest, GetInternalformativ) {
+  const GLint kNumSampleCounts = 8;
+  struct Cmds {
+    cmds::GetInternalformativ cmd;
+  };
+  typedef cmds::GetInternalformativ::Result::Type ResultType;
+  ResultType result = 0;
+  Cmds expected;
+  ExpectedMemoryInfo result1 =
+      GetExpectedResultMemory(sizeof(uint32_t) + sizeof(ResultType));
+  expected.cmd.Init(123, GL_RGBA8, GL_NUM_SAMPLE_COUNTS,
+                    result1.id, result1.offset);
+  EXPECT_CALL(*command_buffer(), OnFlush())
+      .WillOnce(SetMemory(result1.ptr,
+                          SizedResultHelper<ResultType>(kNumSampleCounts)))
+      .RetiresOnSaturation();
+  gl_->GetInternalformativ(123, GL_RGBA8, GL_NUM_SAMPLE_COUNTS, 1, &result);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+  EXPECT_EQ(static_cast<ResultType>(kNumSampleCounts), result);
+}
+
 TEST_F(GLES2ImplementationManualInitTest, LoseContextOnOOM) {
   ContextInitOptions init_options;
   init_options.lose_context_when_out_of_memory = true;
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
index f30ab896..3d462c40d 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -909,25 +909,7 @@
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
   EXPECT_EQ(static_cast<ResultType>(1), result);
 }
-
-TEST_F(GLES2ImplementationTest, GetInternalformativ) {
-  struct Cmds {
-    cmds::GetInternalformativ cmd;
-  };
-  typedef cmds::GetInternalformativ::Result::Type ResultType;
-  ResultType result = 0;
-  Cmds expected;
-  ExpectedMemoryInfo result1 =
-      GetExpectedResultMemory(sizeof(uint32_t) + sizeof(ResultType));
-  expected.cmd.Init(123, GL_RGBA4, GL_NUM_SAMPLE_COUNTS, 4, result1.id,
-                    result1.offset);
-  EXPECT_CALL(*command_buffer(), OnFlush())
-      .WillOnce(SetMemory(result1.ptr, SizedResultHelper<ResultType>(1)))
-      .RetiresOnSaturation();
-  gl_->GetInternalformativ(123, GL_RGBA4, GL_NUM_SAMPLE_COUNTS, 4, &result);
-  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
-  EXPECT_EQ(static_cast<ResultType>(1), result);
-}
+// TODO(zmo): Implement unit test for GetInternalformativ
 
 TEST_F(GLES2ImplementationTest, GetProgramiv) {
   struct Cmds {
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index c4204ac..e92c2d1 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -4624,14 +4624,12 @@
   void Init(GLenum _target,
             GLenum _format,
             GLenum _pname,
-            GLsizei _bufSize,
             uint32_t _params_shm_id,
             uint32_t _params_shm_offset) {
     SetHeader();
     target = _target;
     format = _format;
     pname = _pname;
-    bufSize = _bufSize;
     params_shm_id = _params_shm_id;
     params_shm_offset = _params_shm_offset;
   }
@@ -4640,11 +4638,10 @@
             GLenum _target,
             GLenum _format,
             GLenum _pname,
-            GLsizei _bufSize,
             uint32_t _params_shm_id,
             uint32_t _params_shm_offset) {
-    static_cast<ValueType*>(cmd)->Init(_target, _format, _pname, _bufSize,
-                                       _params_shm_id, _params_shm_offset);
+    static_cast<ValueType*>(cmd)
+        ->Init(_target, _format, _pname, _params_shm_id, _params_shm_offset);
     return NextCmdAddress<ValueType>(cmd);
   }
 
@@ -4652,13 +4649,12 @@
   uint32_t target;
   uint32_t format;
   uint32_t pname;
-  int32_t bufSize;
   uint32_t params_shm_id;
   uint32_t params_shm_offset;
 };
 
-static_assert(sizeof(GetInternalformativ) == 28,
-              "size of GetInternalformativ should be 28");
+static_assert(sizeof(GetInternalformativ) == 24,
+              "size of GetInternalformativ should be 24");
 static_assert(offsetof(GetInternalformativ, header) == 0,
               "offset of GetInternalformativ header should be 0");
 static_assert(offsetof(GetInternalformativ, target) == 4,
@@ -4667,12 +4663,10 @@
               "offset of GetInternalformativ format should be 8");
 static_assert(offsetof(GetInternalformativ, pname) == 12,
               "offset of GetInternalformativ pname should be 12");
-static_assert(offsetof(GetInternalformativ, bufSize) == 16,
-              "offset of GetInternalformativ bufSize should be 16");
-static_assert(offsetof(GetInternalformativ, params_shm_id) == 20,
-              "offset of GetInternalformativ params_shm_id should be 20");
-static_assert(offsetof(GetInternalformativ, params_shm_offset) == 24,
-              "offset of GetInternalformativ params_shm_offset should be 24");
+static_assert(offsetof(GetInternalformativ, params_shm_id) == 16,
+              "offset of GetInternalformativ params_shm_id should be 16");
+static_assert(offsetof(GetInternalformativ, params_shm_offset) == 20,
+              "offset of GetInternalformativ params_shm_offset should be 20");
 
 struct GetProgramiv {
   typedef GetProgramiv ValueType;
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
index a7ff6bd..8a9539d 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -1441,17 +1441,16 @@
   cmds::GetInternalformativ& cmd = *GetBufferAs<cmds::GetInternalformativ>();
   void* next_cmd =
       cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLenum>(12),
-              static_cast<GLenum>(13), static_cast<GLsizei>(14),
-              static_cast<uint32_t>(15), static_cast<uint32_t>(16));
+              static_cast<GLenum>(13), static_cast<uint32_t>(14),
+              static_cast<uint32_t>(15));
   EXPECT_EQ(static_cast<uint32_t>(cmds::GetInternalformativ::kCmdId),
             cmd.header.command);
   EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
   EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
   EXPECT_EQ(static_cast<GLenum>(12), cmd.format);
   EXPECT_EQ(static_cast<GLenum>(13), cmd.pname);
-  EXPECT_EQ(static_cast<GLsizei>(14), cmd.bufSize);
-  EXPECT_EQ(static_cast<uint32_t>(15), cmd.params_shm_id);
-  EXPECT_EQ(static_cast<uint32_t>(16), cmd.params_shm_offset);
+  EXPECT_EQ(static_cast<uint32_t>(14), cmd.params_shm_id);
+  EXPECT_EQ(static_cast<uint32_t>(15), cmd.params_shm_offset);
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
diff --git a/gpu/command_buffer/service/framebuffer_manager_unittest.cc b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
index e1af82d..5f42390 100644
--- a/gpu/command_buffer/service/framebuffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
@@ -446,46 +446,22 @@
 
   // Try format that doesn't work with COLOR_ATTACHMENT0
   texture_manager_->SetTarget(texture1.get(), GL_TEXTURE_2D);
-  texture_manager_->SetLevelInfo(texture1.get(),
-                                GL_TEXTURE_2D,
-                                kLevel1,
-                                kBadFormat1,
-                                kWidth1,
-                                kHeight1,
-                                kDepth,
-                                kBorder,
-                                kBadFormat1,
-                                kType,
-                                true);
+  texture_manager_->SetLevelInfo(
+      texture1.get(), GL_TEXTURE_2D, kLevel1, kBadFormat1, kWidth1, kHeight1,
+      kDepth, kBorder, kBadFormat1, kType, gfx::Rect(kWidth1, kHeight1));
   EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
             framebuffer_->IsPossiblyComplete());
 
   // Try a good format.
-  texture_manager_->SetLevelInfo(texture1.get(),
-                                GL_TEXTURE_2D,
-                                kLevel1,
-                                kFormat1,
-                                kWidth1,
-                                kHeight1,
-                                kDepth,
-                                kBorder,
-                                kFormat1,
-                                kType,
-                                false);
+  texture_manager_->SetLevelInfo(texture1.get(), GL_TEXTURE_2D, kLevel1,
+                                 kFormat1, kWidth1, kHeight1, kDepth, kBorder,
+                                 kFormat1, kType, gfx::Rect());
   EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
             framebuffer_->IsPossiblyComplete());
   EXPECT_FALSE(framebuffer_->IsCleared());
-  texture_manager_->SetLevelInfo(texture1.get(),
-                                GL_TEXTURE_2D,
-                                kLevel1,
-                                kFormat1,
-                                kWidth1,
-                                kHeight1,
-                                kDepth,
-                                kBorder,
-                                kFormat1,
-                                kType,
-                                true);
+  texture_manager_->SetLevelInfo(texture1.get(), GL_TEXTURE_2D, kLevel1,
+                                 kFormat1, kWidth1, kHeight1, kDepth, kBorder,
+                                 kFormat1, kType, gfx::Rect(kWidth1, kHeight1));
   EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
             framebuffer_->IsPossiblyComplete());
   EXPECT_TRUE(framebuffer_->IsCleared());
@@ -507,17 +483,9 @@
       texture_manager_->GetTexture(kTextureClient2Id));
   ASSERT_TRUE(texture2.get() != NULL);
   texture_manager_->SetTarget(texture2.get(), GL_TEXTURE_2D);
-  texture_manager_->SetLevelInfo(texture2.get(),
-                                GL_TEXTURE_2D,
-                                kLevel2,
-                                kFormat2,
-                                kWidth2,
-                                kHeight2,
-                                kDepth,
-                                kBorder,
-                                kFormat2,
-                                kType,
-                                true);
+  texture_manager_->SetLevelInfo(texture2.get(), GL_TEXTURE_2D, kLevel2,
+                                 kFormat2, kWidth2, kHeight2, kDepth, kBorder,
+                                 kFormat2, kType, gfx::Rect(kWidth2, kHeight2));
 
   framebuffer_->AttachTexture(
       GL_COLOR_ATTACHMENT0, texture2.get(), kTarget2, kLevel2, kSamples2);
@@ -536,17 +504,9 @@
   EXPECT_TRUE(attachment->cleared());
 
   // Check changing attachment
-  texture_manager_->SetLevelInfo(texture2.get(),
-                                GL_TEXTURE_2D,
-                                kLevel3,
-                                kFormat3,
-                                kWidth3,
-                                kHeight3,
-                                kDepth,
-                                kBorder,
-                                kFormat3,
-                                kType,
-                                false);
+  texture_manager_->SetLevelInfo(texture2.get(), GL_TEXTURE_2D, kLevel3,
+                                 kFormat3, kWidth3, kHeight3, kDepth, kBorder,
+                                 kFormat3, kType, gfx::Rect());
   attachment = framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
   ASSERT_TRUE(attachment != NULL);
   EXPECT_EQ(kWidth3, attachment->width());
@@ -561,17 +521,9 @@
   EXPECT_FALSE(framebuffer_->IsCleared());
 
   // Set to size 0
-  texture_manager_->SetLevelInfo(texture2.get(),
-                                GL_TEXTURE_2D,
-                                kLevel3,
-                                kFormat3,
-                                0,
-                                0,
-                                kDepth,
-                                kBorder,
-                                kFormat3,
-                                kType,
-                                false);
+  texture_manager_->SetLevelInfo(texture2.get(), GL_TEXTURE_2D, kLevel3,
+                                 kFormat3, 0, 0, kDepth, kBorder, kFormat3,
+                                 kType, gfx::Rect());
   EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
             framebuffer_->IsPossiblyComplete());
 
@@ -627,9 +579,9 @@
   scoped_refptr<TextureRef> texture1(
       texture_manager_->GetTexture(kTextureClientId[1]));
   texture_manager_->SetTarget(texture1.get(), GL_TEXTURE_2D);
-  texture_manager_->SetLevelInfo(
-      texture1.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4, 4,
-      1, 0, GL_RGBA, GL_UNSIGNED_BYTE, false);
+  texture_manager_->SetLevelInfo(texture1.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4,
+                                 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                                 gfx::Rect());
 
   const Framebuffer::Attachment* attachment1 =
       framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT1);
@@ -719,17 +671,9 @@
   EXPECT_EQ(static_cast<GLenum>(0), framebuffer_->GetColorAttachmentFormat());
 
   texture_manager_->SetTarget(texture.get(), GL_TEXTURE_2D);
-  texture_manager_->SetLevelInfo(texture.get(),
-                                GL_TEXTURE_2D,
-                                kLevel,
-                                kInternalFormat,
-                                kWidth,
-                                kHeight,
-                                kDepth,
-                                kBorder,
-                                kFormat,
-                                kType,
-                                false);
+  texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, kLevel,
+                                 kInternalFormat, kWidth, kHeight, kDepth,
+                                 kBorder, kFormat, kType, gfx::Rect());
   // Texture with a sized float internalformat is allowed as an attachment
   // since float color attachment extension is present.
   EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
index 974cbd7..00f510d 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
+++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -429,11 +429,10 @@
     return;
   }
 
-  DoCopyTextureInternal(decoder, source_target, source_id, dest_id, xoffset - x,
-                        yoffset - y, dest_width, dest_height, source_width,
-                        source_height, flip_y, premultiply_alpha,
-                        unpremultiply_alpha, kIdentityMatrix, xoffset, yoffset,
-                        width, height);
+  DoCopyTextureInternal(decoder, source_target, source_id, dest_id, xoffset,
+                        yoffset, x, y, width, height, dest_width, dest_height,
+                        source_width, source_height, flip_y, premultiply_alpha,
+                        unpremultiply_alpha, kIdentityMatrix);
 }
 
 void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
@@ -449,10 +448,10 @@
     const GLfloat transform_matrix[16]) {
   GLsizei dest_width = width;
   GLsizei dest_height = height;
-  DoCopyTextureInternal(decoder, source_target, source_id, dest_id, 0, 0,
-                        dest_width, dest_height, width, height, flip_y,
-                        premultiply_alpha, unpremultiply_alpha,
-                        transform_matrix, 0, 0, dest_width, dest_height);
+  DoCopyTextureInternal(decoder, source_target, source_id, dest_id, 0, 0, 0, 0,
+                        width, height, dest_width, dest_height, width, height,
+                        flip_y, premultiply_alpha, unpremultiply_alpha,
+                        transform_matrix);
 }
 
 void CopyTextureCHROMIUMResourceManager::DoCopyTextureInternal(
@@ -462,6 +461,10 @@
     GLuint dest_id,
     GLint xoffset,
     GLint yoffset,
+    GLint x,
+    GLint y,
+    GLsizei width,
+    GLsizei height,
     GLsizei dest_width,
     GLsizei dest_height,
     GLsizei source_width,
@@ -469,11 +472,7 @@
     bool flip_y,
     bool premultiply_alpha,
     bool unpremultiply_alpha,
-    const GLfloat transform_matrix[16],
-    GLint scissor_x,
-    GLint scissor_y,
-    GLsizei scissor_width,
-    GLsizei scissor_height) {
+    const GLfloat transform_matrix[16]) {
   DCHECK(source_target == GL_TEXTURE_2D ||
          source_target == GL_TEXTURE_RECTANGLE_ARB ||
          source_target == GL_TEXTURE_EXTERNAL_OES);
@@ -522,18 +521,21 @@
   }
   glUseProgram(info->program);
 
-  if (!xoffset && !yoffset) {
+  GLint x_translate = xoffset - x;
+  GLint y_translate = yoffset - y;
+  if (!x_translate && !y_translate) {
     glUniformMatrix4fv(info->matrix_handle, 1, GL_FALSE, transform_matrix);
   } else {
     // transform offsets from ([0, dest_width], [0, dest_height]) coord.
     // to ([-1, 1], [-1, 1]) coord.
-    GLfloat xoffset_on_vertex = ((2.f * xoffset) / dest_width);
-    GLfloat yoffset_on_vertex = ((2.f * yoffset) / dest_height);
+    GLfloat x_translate_on_vertex = ((2.f * x_translate) / dest_width);
+    GLfloat y_translate_on_vertex = ((2.f * y_translate) / dest_height);
 
     // Pass view_matrix * offset_matrix to the program.
     GLfloat view_transform[16];
     memcpy(view_transform, transform_matrix, 16 * sizeof(GLfloat));
-    PreTranslate(view_transform, xoffset_on_vertex, yoffset_on_vertex, 0);
+    PreTranslate(view_transform, x_translate_on_vertex, y_translate_on_vertex,
+                 0);
     glUniformMatrix4fv(info->matrix_handle, 1, GL_FALSE, view_transform);
   }
   if (source_target == GL_TEXTURE_RECTANGLE_ARB)
@@ -575,8 +577,12 @@
     glDepthMask(GL_FALSE);
     glDisable(GL_BLEND);
 
-    glEnable(GL_SCISSOR_TEST);
-    glScissor(scissor_x, scissor_y, scissor_width, scissor_height);
+    bool need_scissor =
+        xoffset || yoffset || width != dest_width || height != dest_height;
+    if (need_scissor) {
+      glEnable(GL_SCISSOR_TEST);
+      glScissor(xoffset, yoffset, width, height);
+    }
     glViewport(0, 0, dest_width, dest_height);
     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
   }
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
index 8cba517..1910d3b 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
+++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
@@ -98,6 +98,10 @@
                              GLuint dest_id,
                              GLint xoffset,
                              GLint yoffset,
+                             GLint x,
+                             GLint y,
+                             GLsizei width,
+                             GLsizei height,
                              GLsizei dest_width,
                              GLsizei dest_height,
                              GLsizei source_width,
@@ -105,11 +109,7 @@
                              bool flip_y,
                              bool premultiply_alpha,
                              bool unpremultiply_alpha,
-                             const GLfloat transform_matrix[16],
-                             GLint scissor_x,
-                             GLint scissor_y,
-                             GLsizei scissor_width,
-                             GLsizei scissor_height);
+                             const GLfloat transform_matrix[16]);
 
   bool initialized_;
   typedef std::vector<GLuint> ShaderVector;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 951bbd6..f2db39f 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -191,6 +191,33 @@
   GLfloat v[4];
 };
 
+// Returns the union of |rect1| and |rect2| if one of the rectangles is empty,
+// contains the other rectangle or shares an edge with the other rectangle.
+bool CombineAdjacentRects(const gfx::Rect& rect1,
+                          const gfx::Rect& rect2,
+                          gfx::Rect* result) {
+  // Return |rect2| if |rect1| is empty or |rect2| contains |rect1|.
+  if (rect1.IsEmpty() || rect2.Contains(rect1)) {
+    *result = rect2;
+    return true;
+  }
+
+  // Return |rect1| if |rect2| is empty or |rect1| contains |rect2|.
+  if (rect2.IsEmpty() || rect1.Contains(rect2)) {
+    *result = rect1;
+    return true;
+  }
+
+  // Return the union of |rect1| and |rect2| if they share an edge.
+  if (rect1.SharesEdgeWith(rect2)) {
+    *result = gfx::UnionRects(rect1, rect2);
+    return true;
+  }
+
+  // Return false if it's not possible to combine |rect1| and |rect2|.
+  return false;
+}
+
 }  // namespace
 
 class GLES2DecoderImpl;
@@ -685,6 +712,7 @@
   void SetAsyncPixelTransferManagerForTest(
       AsyncPixelTransferManager* manager) override;
   void SetIgnoreCachedStateForTest(bool ignore) override;
+  void SetAllowExit(bool allow_exit) override;
   void ProcessFinishedAsyncTransfers();
 
   bool GetServiceTextureId(uint32 client_texture_id,
@@ -1270,12 +1298,12 @@
   bool ClearLevel(Texture* texture,
                   unsigned target,
                   int level,
-                  unsigned internal_format,
                   unsigned format,
                   unsigned type,
+                  int xoffset,
+                  int yoffset,
                   int width,
-                  int height,
-                  bool is_texture_immutable) override;
+                  int height) override;
 
   // Restore all GL state that affects clearing.
   void RestoreClearState();
@@ -1997,6 +2025,8 @@
   GLuint validation_fbo_multisample_;
   GLuint validation_fbo_;
 
+  bool allow_exit_;
+
   typedef gpu::gles2::GLES2Decoder::Error (GLES2DecoderImpl::*CmdHandler)(
       uint32 immediate_data_size,
       const void* data);
@@ -2509,7 +2539,8 @@
       gpu_debug_commands_(false),
       validation_texture_(0),
       validation_fbo_multisample_(0),
-      validation_fbo_(0) {
+      validation_fbo_(0),
+      allow_exit_(false) {
   DCHECK(group);
 
   // The shader translator is used for WebGL even when running on EGL
@@ -3182,6 +3213,8 @@
     driver_bug_workarounds |= SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS;
   if (workarounds().regenerate_struct_names)
     driver_bug_workarounds |= SH_REGENERATE_STRUCT_NAMES;
+  if (workarounds().remove_pow_with_constant_exponent)
+    driver_bug_workarounds |= SH_REMOVE_POW_WITH_CONSTANT_EXPONENT;
 
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEmulateShaderPrecision))
@@ -3685,17 +3718,12 @@
   GLenum target = offscreen_saved_color_texture_info_->texture()->target();
   glBindTexture(target, offscreen_saved_color_texture_info_->service_id());
   texture_manager()->SetLevelInfo(
-      offscreen_saved_color_texture_info_.get(),
-      GL_TEXTURE_2D,
+      offscreen_saved_color_texture_info_.get(), GL_TEXTURE_2D,
       0,  // level
-      GL_RGBA,
-      offscreen_size_.width(),
-      offscreen_size_.height(),
+      GL_RGBA, offscreen_size_.width(), offscreen_size_.height(),
       1,  // depth
       0,  // border
-      GL_RGBA,
-      GL_UNSIGNED_BYTE,
-      true);
+      GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(offscreen_size_));
   texture_manager()->SetParameteri(
       "UpdateParentTextureInfo",
       GetErrorState(),
@@ -4492,6 +4520,10 @@
   state_.SetIgnoreCachedStateForTest(ignore);
 }
 
+void GLES2DecoderImpl::SetAllowExit(bool allow_exit) {
+  allow_exit_ = allow_exit;
+}
+
 void GLES2DecoderImpl::OnFboChanged() const {
   if (workarounds().restore_scissor_on_fbo_change)
     state_.fbo_binding_for_scissor_workaround_dirty = true;
@@ -8865,16 +8897,15 @@
       &state_, target, offset, size, data);
 }
 
-bool GLES2DecoderImpl::ClearLevel(
-    Texture* texture,
-    unsigned target,
-    int level,
-    unsigned internal_format,
-    unsigned format,
-    unsigned type,
-    int width,
-    int height,
-    bool is_texture_immutable) {
+bool GLES2DecoderImpl::ClearLevel(Texture* texture,
+                                  unsigned target,
+                                  int level,
+                                  unsigned format,
+                                  unsigned type,
+                                  int xoffset,
+                                  int yoffset,
+                                  int width,
+                                  int height) {
   uint32 channels = GLES2Util::GetChannelsForFormat(format);
   if (feature_info_->feature_flags().angle_depth_texture &&
       (channels & GLES2Util::kDepth) != 0) {
@@ -8900,9 +8931,11 @@
     state_.SetDeviceStencilMaskSeparate(GL_BACK, kDefaultStencilMask);
     glClearDepth(1.0f);
     state_.SetDeviceDepthMask(GL_TRUE);
-    state_.SetDeviceCapabilityState(GL_SCISSOR_TEST, false);
+    state_.SetDeviceCapabilityState(GL_SCISSOR_TEST, true);
+    glScissor(xoffset, yoffset, width, height);
     glClear(GL_DEPTH_BUFFER_BIT | (have_stencil ? GL_STENCIL_BUFFER_BIT : 0));
 
+    state_.SetDeviceCapabilityState(GL_SCISSOR_TEST, false);
     RestoreClearState();
 
     glDeleteFramebuffersEXT(1, &fb);
@@ -8950,17 +8983,11 @@
   memset(zero.get(), 0, size);
   glBindTexture(texture->target(), texture->service_id());
 
-  bool has_images = texture->HasImages();
   GLint y = 0;
   while (y < height) {
     GLint h = y + tile_height > height ? height - y : tile_height;
-    if (is_texture_immutable || h != height || has_images) {
-      glTexSubImage2D(target, level, 0, y, width, h, format, type, zero.get());
-    } else {
-      glTexImage2D(
-          target, level, internal_format, width, h, 0, format, type,
-          zero.get());
-    }
+    glTexSubImage2D(target, level, xoffset, yoffset + y, width, h, format, type,
+                    zero.get());
     y += tile_height;
   }
   TextureRef* bound_texture =
@@ -9321,9 +9348,9 @@
       target, level, internal_format, width, height, border, image_size, data);
   GLenum error = LOCAL_PEEK_GL_ERROR("glCompressedTexImage2D");
   if (error == GL_NO_ERROR) {
-    texture_manager()->SetLevelInfo(
-        texture_ref, target, level, internal_format,
-        width, height, 1, border, 0, 0, true);
+    texture_manager()->SetLevelInfo(texture_ref, target, level, internal_format,
+                                    width, height, 1, border, 0, 0,
+                                    gfx::Rect(width, height));
   }
 
   // This may be a slow command.  Exit command processing to allow for
@@ -9508,9 +9535,9 @@
                          border, image_size, data);
   GLenum error = LOCAL_PEEK_GL_ERROR("glCompressedTexImage3D");
   if (error == GL_NO_ERROR) {
-    texture_manager()->SetLevelInfo(
-        texture_ref, target, level, internal_format,
-        width, height, depth, border, 0, 0, true);
+    texture_manager()->SetLevelInfo(texture_ref, target, level, internal_format,
+                                    width, height, depth, border, 0, 0,
+                                    gfx::Rect(width, height));
   }
 
   // This may be a slow command.  Exit command processing to allow for
@@ -9974,19 +10001,25 @@
       copyY != y ||
       copyWidth != width ||
       copyHeight != height) {
-    // some part was clipped so clear the texture.
-    if (!ClearLevel(texture, target, level, internal_format, internal_format,
-                    GL_UNSIGNED_BYTE, width, height, texture->IsImmutable())) {
+    // some part was clipped so clear the rect.
+    uint32 pixels_size = 0;
+    if (!GLES2Util::ComputeImageDataSizes(
+            width, height, 1, internal_format, GL_UNSIGNED_BYTE,
+            state_.unpack_alignment, &pixels_size, NULL, NULL)) {
       LOCAL_SET_GL_ERROR(
           GL_OUT_OF_MEMORY, "glCopyTexImage2D", "dimensions too big");
       return;
     }
+    scoped_ptr<char[]> zero(new char[pixels_size]);
+    memset(zero.get(), 0, pixels_size);
+    ScopedModifyPixels modify(texture_ref);
+    glTexImage2D(target, level, internal_format, width, height, border,
+                 internal_format, GL_UNSIGNED_BYTE, zero.get());
     if (copyHeight > 0 && copyWidth > 0) {
       GLint dx = copyX - x;
       GLint dy = copyY - y;
       GLint destX = dx;
       GLint destY = dy;
-      ScopedModifyPixels modify(texture_ref);
       glCopyTexSubImage2D(target, level,
                           destX, destY, copyX, copyY,
                           copyWidth, copyHeight);
@@ -9998,9 +10031,9 @@
   }
   GLenum error = LOCAL_PEEK_GL_ERROR("glCopyTexImage2D");
   if (error == GL_NO_ERROR) {
-    texture_manager()->SetLevelInfo(
-        texture_ref, target, level, internal_format, width, height, 1,
-        border, internal_format, GL_UNSIGNED_BYTE, true);
+    texture_manager()->SetLevelInfo(texture_ref, target, level, internal_format,
+                                    width, height, 1, border, internal_format,
+                                    GL_UNSIGNED_BYTE, gfx::Rect(width, height));
   }
 
   // This may be a slow command.  Exit command processing to allow for
@@ -10088,11 +10121,22 @@
 
   if (xoffset != 0 || yoffset != 0 || width != size.width() ||
       height != size.height()) {
-    if (!texture_manager()->ClearTextureLevel(this, texture_ref, target,
-                                              level)) {
-      LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glCopyTexSubImage2D",
-                         "dimensions too big");
-      return;
+    gfx::Rect cleared_rect;
+    if (CombineAdjacentRects(texture->GetLevelClearedRect(target, level),
+                             gfx::Rect(xoffset, yoffset, width, height),
+                             &cleared_rect)) {
+      DCHECK_GE(cleared_rect.size().GetArea(),
+                texture->GetLevelClearedRect(target, level).size().GetArea());
+      texture_manager()->SetLevelClearedRect(texture_ref, target, level,
+                                             cleared_rect);
+    } else {
+      // Otherwise clear part of texture level that is not already cleared.
+      if (!texture_manager()->ClearTextureLevel(this, texture_ref, target,
+                                                level)) {
+        LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glCopyTexSubImage2D",
+                           "dimensions too big");
+        return;
+      }
     }
   } else {
     // Write all pixels in below.
@@ -10237,11 +10281,22 @@
   DCHECK(ok);
   if (xoffset != 0 || yoffset != 0 ||
       width != tex_width || height != tex_height) {
-    if (!texture_manager()->ClearTextureLevel(this, texture_ref,
-                                              target, level)) {
-      LOCAL_SET_GL_ERROR(
-          GL_OUT_OF_MEMORY, "glTexSubImage2D", "dimensions too big");
-      return error::kNoError;
+    gfx::Rect cleared_rect;
+    if (CombineAdjacentRects(texture->GetLevelClearedRect(target, level),
+                             gfx::Rect(xoffset, yoffset, width, height),
+                             &cleared_rect)) {
+      DCHECK_GE(cleared_rect.size().GetArea(),
+                texture->GetLevelClearedRect(target, level).size().GetArea());
+      texture_manager()->SetLevelClearedRect(texture_ref, target, level,
+                                             cleared_rect);
+    } else {
+      // Otherwise clear part of texture level that is not already cleared.
+      if (!texture_manager()->ClearTextureLevel(this, texture_ref, target,
+                                                level)) {
+        LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glTexSubImage2D",
+                           "dimensions too big");
+        return error::kNoError;
+      }
     }
     ScopedTextureUploadTimer timer(&texture_state_);
     glTexSubImage2D(
@@ -11324,11 +11379,10 @@
   current_decoder_error_ = error::kLostContext;
   context_was_lost_ = true;
 
-  // Some D3D drivers cannot recover from device lost in the GPU process
-  // sandbox. Allow a new GPU process to launch.
-  if (workarounds().exit_on_context_lost) {
-    LOG(ERROR) << "Exiting GPU process because some drivers cannot reset"
-               << " a D3D device in the Chrome GPU process sandbox.";
+  // Work around issues with recovery by allowing a new GPU process to launch.
+  if (workarounds().exit_on_context_lost && allow_exit_) {
+    LOG(ERROR) << "Exiting GPU process because some drivers cannot recover"
+               << " from problems.";
 #if defined(OS_WIN)
     base::win::SetShouldCrashOnProcessDetach(false);
 #endif
@@ -11757,8 +11811,8 @@
   }
 
   texture_manager()->SetLevelInfo(
-      texture_ref, target, 0, GL_RGBA, width, height, 1, 0,
-      GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, true);
+      texture_ref, target, 0, GL_RGBA, width, height, 1, 0, GL_BGRA,
+      GL_UNSIGNED_INT_8_8_8_8_REV, gfx::Rect(width, height));
 
 #else
   LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
@@ -11981,7 +12035,8 @@
 
     texture_manager()->SetLevelInfo(
         dest_texture_ref, GL_TEXTURE_2D, 0, internal_format, source_width,
-        source_height, 1, 0, internal_format, dest_type, true);
+        source_height, 1, 0, internal_format, dest_type,
+        gfx::Rect(source_width, source_height));
   } else {
     texture_manager()->SetLevelCleared(dest_texture_ref, GL_TEXTURE_2D, 0,
                                        true);
@@ -12127,11 +12182,22 @@
   DCHECK(ok);
   if (xoffset != 0 || yoffset != 0 || width != dest_width ||
       height != dest_height) {
-    if (!texture_manager()->ClearTextureLevel(this, dest_texture_ref, target,
-                                              0)) {
-      LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glCopySubTextureCHROMIUM",
-                         "destination texture dimensions too big");
-      return;
+    gfx::Rect cleared_rect;
+    if (CombineAdjacentRects(dest_texture->GetLevelClearedRect(target, 0),
+                             gfx::Rect(xoffset, yoffset, width, height),
+                             &cleared_rect)) {
+      DCHECK_GE(cleared_rect.size().GetArea(),
+                dest_texture->GetLevelClearedRect(target, 0).size().GetArea());
+      texture_manager()->SetLevelClearedRect(dest_texture_ref, target, 0,
+                                             cleared_rect);
+    } else {
+      // Otherwise clear part of texture level that is not already cleared.
+      if (!texture_manager()->ClearTextureLevel(this, dest_texture_ref, target,
+                                                0)) {
+        LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glCopySubTextureCHROMIUM",
+                           "destination texture dimensions too big");
+        return;
+      }
     }
   } else {
     texture_manager()->SetLevelCleared(dest_texture_ref, GL_TEXTURE_2D, 0,
@@ -12277,9 +12343,9 @@
     GLsizei level_width = width;
     GLsizei level_height = height;
     for (int ii = 0; ii < levels; ++ii) {
-      texture_manager()->SetLevelInfo(
-          texture_ref, target, ii, format,
-          level_width, level_height, 1, 0, format, type, false);
+      texture_manager()->SetLevelInfo(texture_ref, target, ii, format,
+                                      level_width, level_height, 1, 0, format,
+                                      type, gfx::Rect());
       level_width = std::max(1, level_width >> 1);
       level_height = std::max(1, level_height >> 1);
     }
@@ -12629,9 +12695,9 @@
 
   gfx::Size size = gl_image->GetSize();
   texture_manager()->SetLevelInfo(
-      texture_ref, target, 0, gl_image->GetInternalFormat(),
-      size.width(), size.height(), 1, 0,
-      gl_image->GetInternalFormat(), GL_UNSIGNED_BYTE, true);
+      texture_ref, target, 0, gl_image->GetInternalFormat(), size.width(),
+      size.height(), 1, 0, gl_image->GetInternalFormat(), GL_UNSIGNED_BYTE,
+      gfx::Rect(size));
   texture_manager()->SetLevelImage(texture_ref, target, 0, gl_image);
 }
 
@@ -12670,7 +12736,7 @@
 
   texture_manager()->SetLevelInfo(
       texture_ref, target, 0, gl_image->GetInternalFormat(), 0, 0, 1, 0,
-      gl_image->GetInternalFormat(), GL_UNSIGNED_BYTE, false);
+      gl_image->GetInternalFormat(), GL_UNSIGNED_BYTE, gfx::Rect());
 }
 
 error::Error GLES2DecoderImpl::HandleTraceBeginCHROMIUM(
@@ -13167,6 +13233,59 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleGetInternalformativ(
+    uint32_t immediate_data_size, const void* cmd_data) {
+  if (!unsafe_es3_apis_enabled())
+    return error::kUnknownCommand;
+  const gles2::cmds::GetInternalformativ& c =
+      *static_cast<const gles2::cmds::GetInternalformativ*>(cmd_data);
+  GLenum target = static_cast<GLenum>(c.target);
+  GLenum format = static_cast<GLenum>(c.format);
+  GLenum pname = static_cast<GLenum>(c.pname);
+  if (!validators_->render_buffer_target.IsValid(target)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetInternalformativ", target, "target");
+    return error::kNoError;
+  }
+  if (!validators_->render_buffer_format.IsValid(format)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetInternalformativ", format, "format");
+    return error::kNoError;
+  }
+  if (!validators_->internal_format_parameter.IsValid(pname)) {
+    LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetInternalformativ", pname, "pname");
+    return error::kNoError;
+  }
+  typedef cmds::GetInternalformativ::Result Result;
+  GLsizei num_values = 0;
+  switch (pname) {
+    case GL_NUM_SAMPLE_COUNTS:
+      num_values = 1;
+      break;
+    case GL_SAMPLES:
+      {
+        GLint value = 0;
+        glGetInternalformativ(target, format, GL_NUM_SAMPLE_COUNTS, 1, &value);
+        num_values = static_cast<GLsizei>(value);
+      }
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
+  Result* result = GetSharedMemoryAs<Result*>(
+      c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+  GLint* params = result ? result->GetData() : NULL;
+  if (params == NULL) {
+    return error::kOutOfBounds;
+  }
+  // Check that the client initialized the result.
+  if (result->size != 0) {
+    return error::kInvalidArguments;
+  }
+  glGetInternalformativ(target, format, pname, num_values, params);
+  result->SetNumResults(num_values);
+  return error::kNoError;
+}
+
 error::Error GLES2DecoderImpl::HandleMapBufferRange(
     uint32_t immediate_data_size, const void* cmd_data) {
   if (!unsafe_es3_apis_enabled()) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index ac01c958..26f695c 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -171,6 +171,10 @@
 
   virtual void SetIgnoreCachedStateForTest(bool ignore) = 0;
 
+  // Allow the decoder to exit the current process.
+  // Defaults to |false|.
+  virtual void SetAllowExit(bool allow_exit) = 0;
+
   // Gets the QueryManager for this context.
   virtual QueryManager* GetQueryManager() = 0;
 
@@ -210,18 +214,17 @@
   // Provides detail about a lost context if one occurred.
   virtual error::ContextLostReason GetContextLostReason() = 0;
 
-  // Clears a level of a texture
+  // Clears a level sub area of a texture
   // Returns false if a GL error should be generated.
-  virtual bool ClearLevel(
-      Texture* texture,
-      unsigned target,
-      int level,
-      unsigned internal_format,
-      unsigned format,
-      unsigned type,
-      int width,
-      int height,
-      bool is_texture_immutable) = 0;
+  virtual bool ClearLevel(Texture* texture,
+                          unsigned target,
+                          int level,
+                          unsigned format,
+                          unsigned type,
+                          int xoffset,
+                          int yoffset,
+                          int width,
+                          int height) = 0;
 
   virtual ErrorState* GetErrorState() = 0;
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 09d07c0b..9c910a22 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -1381,11 +1381,9 @@
     return error::kInvalidArguments;
   }
   DoGetBooleanv(pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetBooleanv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetBooleanv", "");
   }
   return error::kNoError;
 }
@@ -1463,11 +1461,9 @@
     return error::kInvalidArguments;
   }
   DoGetFloatv(pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetFloatv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetFloatv", "");
   }
   return error::kNoError;
 }
@@ -1512,11 +1508,9 @@
     return error::kInvalidArguments;
   }
   DoGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetFramebufferAttachmentParameteriv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetFramebufferAttachmentParameteriv", "");
   }
   return error::kNoError;
 }
@@ -1544,11 +1538,9 @@
     return error::kInvalidArguments;
   }
   DoGetInteger64v(pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetInteger64v");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetInteger64v", "");
   }
   return error::kNoError;
 }
@@ -1577,11 +1569,9 @@
     return error::kInvalidArguments;
   }
   glGetIntegeri_v(pname, index, data);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetIntegeri_v");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetIntegeri_v", "");
   }
   return error::kNoError;
 }
@@ -1611,11 +1601,9 @@
     return error::kInvalidArguments;
   }
   glGetInteger64i_v(pname, index, data);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetInteger64i_v");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetInteger64i_v", "");
   }
   return error::kNoError;
 }
@@ -1645,47 +1633,9 @@
     return error::kInvalidArguments;
   }
   DoGetIntegerv(pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetIntegerv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetIntegerv", "");
-  }
-  return error::kNoError;
-}
-
-error::Error GLES2DecoderImpl::HandleGetInternalformativ(
-    uint32_t immediate_data_size,
-    const void* cmd_data) {
-  if (!unsafe_es3_apis_enabled())
-    return error::kUnknownCommand;
-  const gles2::cmds::GetInternalformativ& c =
-      *static_cast<const gles2::cmds::GetInternalformativ*>(cmd_data);
-  (void)c;
-  GLenum target = static_cast<GLenum>(c.target);
-  GLenum format = static_cast<GLenum>(c.format);
-  GLenum pname = static_cast<GLenum>(c.pname);
-  GLsizei bufSize = static_cast<GLsizei>(c.bufSize);
-  typedef cmds::GetInternalformativ::Result Result;
-  GLsizei num_values = 0;
-  GetNumValuesReturnedForGLGet(pname, &num_values);
-  Result* result = GetSharedMemoryAs<Result*>(
-      c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
-  GLint* params = result ? result->GetData() : NULL;
-  if (params == NULL) {
-    return error::kOutOfBounds;
-  }
-  LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetInternalformativ");
-  // Check that the client initialized the result.
-  if (result->size != 0) {
-    return error::kInvalidArguments;
-  }
-  glGetInternalformativ(target, format, pname, bufSize, params);
-  GLenum error = glGetError();
-  if (error == GL_NO_ERROR) {
-    result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetInternalformativ", "");
   }
   return error::kNoError;
 }
@@ -1716,11 +1666,9 @@
     return error::kInvalidArguments;
   }
   DoGetProgramiv(program, pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetProgramiv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetProgramiv", "");
   }
   return error::kNoError;
 }
@@ -1758,11 +1706,9 @@
     return error::kInvalidArguments;
   }
   DoGetRenderbufferParameteriv(target, pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetRenderbufferParameteriv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetRenderbufferParameteriv", "");
   }
   return error::kNoError;
 }
@@ -1797,11 +1743,9 @@
     return error::kNoError;
   }
   glGetSamplerParameterfv(sampler, pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetSamplerParameterfv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetSamplerParameterfv", "");
   }
   return error::kNoError;
 }
@@ -1836,11 +1780,9 @@
     return error::kNoError;
   }
   glGetSamplerParameteriv(sampler, pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetSamplerParameteriv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetSamplerParameteriv", "");
   }
   return error::kNoError;
 }
@@ -1871,11 +1813,9 @@
     return error::kInvalidArguments;
   }
   DoGetShaderiv(shader, pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetShaderiv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetShaderiv", "");
   }
   return error::kNoError;
 }
@@ -1909,11 +1849,9 @@
     return error::kNoError;
   }
   glGetSynciv(service_sync, pname, num_values, nullptr, values);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetSynciv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetSynciv", "");
   }
   return error::kNoError;
 }
@@ -1949,11 +1887,9 @@
     return error::kInvalidArguments;
   }
   DoGetTexParameterfv(target, pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetTexParameterfv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetTexParameterfv", "");
   }
   return error::kNoError;
 }
@@ -1989,11 +1925,9 @@
     return error::kInvalidArguments;
   }
   DoGetTexParameteriv(target, pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetTexParameteriv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetTexParameteriv", "");
   }
   return error::kNoError;
 }
@@ -2025,11 +1959,9 @@
     return error::kInvalidArguments;
   }
   DoGetVertexAttribfv(index, pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetVertexAttribfv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetVertexAttribfv", "");
   }
   return error::kNoError;
 }
@@ -2061,11 +1993,9 @@
     return error::kInvalidArguments;
   }
   DoGetVertexAttribiv(index, pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetVertexAttribiv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetVertexAttribiv", "");
   }
   return error::kNoError;
 }
@@ -2095,11 +2025,9 @@
     return error::kInvalidArguments;
   }
   DoGetVertexAttribIiv(index, pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetVertexAttribIiv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetVertexAttribIiv", "");
   }
   return error::kNoError;
 }
@@ -2129,11 +2057,9 @@
     return error::kInvalidArguments;
   }
   DoGetVertexAttribIuiv(index, pname, params);
-  GLenum error = glGetError();
+  GLenum error = LOCAL_PEEK_GL_ERROR("GetVertexAttribIuiv");
   if (error == GL_NO_ERROR) {
     result->SetNumResults(num_values);
-  } else {
-    LOCAL_SET_GL_ERROR(error, "GetVertexAttribIuiv", "");
   }
   return error::kNoError;
 }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
index 65df53c..48d17a2 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -89,6 +89,7 @@
   MOCK_METHOD1(SetAsyncPixelTransferManagerForTest,
       void(AsyncPixelTransferManager*));
   MOCK_METHOD1(SetIgnoreCachedStateForTest, void(bool ignore));
+  MOCK_METHOD1(SetAllowExit, void(bool allow));
   MOCK_METHOD3(DoCommand, error::Error(unsigned int command,
                                        unsigned int arg_count,
                                        const void* cmd_data));
@@ -101,16 +102,16 @@
                                          uint32* service_texture_id));
   MOCK_METHOD0(GetContextLostReason, error::ContextLostReason());
   MOCK_CONST_METHOD1(GetCommandName, const char*(unsigned int command_id));
-  MOCK_METHOD9(ClearLevel, bool(
-      Texture* texture,
-      unsigned target,
-      int level,
-      unsigned internal_format,
-      unsigned format,
-      unsigned type,
-      int width,
-      int height,
-      bool is_texture_immutable));
+  MOCK_METHOD9(ClearLevel,
+               bool(Texture* texture,
+                    unsigned target,
+                    int level,
+                    unsigned format,
+                    unsigned type,
+                    int x_offset,
+                    int y_offset,
+                    int width,
+                    int height));
   MOCK_METHOD0(GetErrorState, ErrorState *());
 
   MOCK_METHOD0(GetLogger, Logger*());
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index 1dd2fdc2..dee67f72 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -44,7 +44,6 @@
 using ::testing::Return;
 using ::testing::SaveArg;
 using ::testing::SetArrayArgument;
-using ::testing::SetArgumentPointee;
 using ::testing::SetArgPointee;
 using ::testing::StrEq;
 using ::testing::StrictMock;
@@ -282,7 +281,53 @@
   EXPECT_FALSE(DoIsTexture(client_texture_id_));
 }
 
-TEST_P(GLES2DecoderTest, ClientWaitSyncValid) {
+TEST_P(GLES3DecoderTest, GetInternalformativValidArgsSamples) {
+  const GLint kNumSampleCounts = 8;
+  typedef cmds::GetInternalformativ::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  EXPECT_CALL(*gl_, GetInternalformativ(GL_RENDERBUFFER, GL_RGBA8,
+                                        GL_NUM_SAMPLE_COUNTS, 1, _))
+      .WillOnce(SetArgPointee<4>(kNumSampleCounts))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*gl_, GetInternalformativ(GL_RENDERBUFFER, GL_RGBA8,
+                                        GL_SAMPLES, kNumSampleCounts,
+                                        result->GetData()))
+      .Times(1)
+      .RetiresOnSaturation();
+  result->size = 0;
+  cmds::GetInternalformativ cmd;
+  cmd.Init(GL_RENDERBUFFER, GL_RGBA8, GL_SAMPLES,
+           shared_memory_id_, shared_memory_offset_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(kNumSampleCounts, result->GetNumResults());
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES3DecoderTest, GetInternalformativValidArgsNumSampleCounts) {
+  const GLint kNumSampleCounts = 8;
+  typedef cmds::GetInternalformativ::Result Result;
+  Result* result = static_cast<Result*>(shared_memory_address_);
+  EXPECT_CALL(*gl_, GetInternalformativ(GL_RENDERBUFFER, GL_RGBA8,
+                                        GL_NUM_SAMPLE_COUNTS, 1, _))
+      .WillOnce(SetArgPointee<4>(kNumSampleCounts))
+      .RetiresOnSaturation();
+  result->size = 0;
+  cmds::GetInternalformativ cmd;
+  cmd.Init(GL_RENDERBUFFER, GL_RGBA8, GL_NUM_SAMPLE_COUNTS,
+           shared_memory_id_, shared_memory_offset_);
+  decoder_->set_unsafe_es3_apis_enabled(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(1, result->GetNumResults());
+  EXPECT_EQ(kNumSampleCounts, result->GetData()[0]);
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+  decoder_->set_unsafe_es3_apis_enabled(false);
+  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES3DecoderTest, ClientWaitSyncValid) {
   typedef cmds::ClientWaitSync::Result Result;
   Result* result = static_cast<Result*>(shared_memory_address_);
   cmds::ClientWaitSync cmd;
@@ -461,7 +506,7 @@
 
   // Test valid parameters work.
   EXPECT_CALL(*gl_, GenQueries(1, _))
-      .WillOnce(SetArgumentPointee<1>(kNewServiceId))
+      .WillOnce(SetArgPointee<1>(kNewServiceId))
       .RetiresOnSaturation();
   EXPECT_CALL(*gl_, BeginQuery(GL_ANY_SAMPLES_PASSED_EXT, kNewServiceId))
       .Times(1)
@@ -552,7 +597,7 @@
 
   if (query_type.is_gl) {
     EXPECT_CALL(*gl, GenQueries(1, _))
-        .WillOnce(SetArgumentPointee<1>(service_id))
+        .WillOnce(SetArgPointee<1>(service_id))
         .RetiresOnSaturation();
     EXPECT_CALL(*gl, BeginQuery(query_type.type, service_id))
         .Times(1)
@@ -593,10 +638,10 @@
   if (query_type.is_gl) {
     EXPECT_CALL(
         *gl, GetQueryObjectuiv(service_id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
-        .WillOnce(SetArgumentPointee<2>(1))
+        .WillOnce(SetArgPointee<2>(1))
         .RetiresOnSaturation();
     EXPECT_CALL(*gl, GetQueryObjectuiv(service_id, GL_QUERY_RESULT_EXT, _))
-        .WillOnce(SetArgumentPointee<2>(1))
+        .WillOnce(SetArgPointee<2>(1))
         .RetiresOnSaturation();
   }
   if (query_type.type == GL_COMMANDS_COMPLETED_CHROMIUM) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
index 7881a55..32e1dcc 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
@@ -1552,31 +1552,7 @@
   EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
   EXPECT_EQ(0u, result->size);
 }
-
-TEST_P(GLES2DecoderTest1, GetInternalformativValidArgs) {
-  EXPECT_CALL(*gl_, GetError())
-      .WillOnce(Return(GL_NO_ERROR))
-      .WillOnce(Return(GL_NO_ERROR))
-      .RetiresOnSaturation();
-  SpecializedSetup<cmds::GetInternalformativ, 0>(true);
-  typedef cmds::GetInternalformativ::Result Result;
-  Result* result = static_cast<Result*>(shared_memory_address_);
-  EXPECT_CALL(
-      *gl_, GetInternalformativ(GL_RENDERBUFFER, GL_RGBA4, GL_NUM_SAMPLE_COUNTS,
-                                4, result->GetData()));
-  result->size = 0;
-  cmds::GetInternalformativ cmd;
-  cmd.Init(GL_RENDERBUFFER, GL_RGBA4, GL_NUM_SAMPLE_COUNTS, 4,
-           shared_memory_id_, shared_memory_offset_);
-  decoder_->set_unsafe_es3_apis_enabled(true);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
-  EXPECT_EQ(
-      decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_NUM_SAMPLE_COUNTS),
-      result->GetNumResults());
-  EXPECT_EQ(GL_NO_ERROR, GetGLError());
-  decoder_->set_unsafe_es3_apis_enabled(false);
-  EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
-}
+// TODO(gman): GetInternalformativ
 
 TEST_P(GLES2DecoderTest1, GetProgramivValidArgs) {
   SpecializedSetup<cmds::GetProgramiv, 0>(true);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index 6bd6156..b9fd068 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -657,22 +657,23 @@
   ClearSharedMemory();
 }
 
-void GLES2DecoderTestBase::SetupClearTextureExpectations(
-      GLuint service_id,
-      GLuint old_service_id,
-      GLenum bind_target,
-      GLenum target,
-      GLint level,
-      GLenum internal_format,
-      GLenum format,
-      GLenum type,
-      GLsizei width,
-      GLsizei height) {
+void GLES2DecoderTestBase::SetupClearTextureExpectations(GLuint service_id,
+                                                         GLuint old_service_id,
+                                                         GLenum bind_target,
+                                                         GLenum target,
+                                                         GLint level,
+                                                         GLenum internal_format,
+                                                         GLenum format,
+                                                         GLenum type,
+                                                         GLint xoffset,
+                                                         GLint yoffset,
+                                                         GLsizei width,
+                                                         GLsizei height) {
   EXPECT_CALL(*gl_, BindTexture(bind_target, service_id))
       .Times(1)
       .RetiresOnSaturation();
-  EXPECT_CALL(*gl_, TexImage2D(
-      target, level, internal_format, width, height, 0, format, type, _))
+  EXPECT_CALL(*gl_, TexSubImage2D(target, level, xoffset, yoffset, width,
+                                  height, format, type, _))
       .Times(1)
       .RetiresOnSaturation();
   EXPECT_CALL(*gl_, BindTexture(bind_target, old_service_id))
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
index 7719cdf..1583462 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -335,17 +335,18 @@
 
   void DeleteIndexBuffer();
 
-  void SetupClearTextureExpectations(
-      GLuint service_id,
-      GLuint old_service_id,
-      GLenum bind_target,
-      GLenum target,
-      GLint level,
-      GLenum internal_format,
-      GLenum format,
-      GLenum type,
-      GLsizei width,
-      GLsizei height);
+  void SetupClearTextureExpectations(GLuint service_id,
+                                     GLuint old_service_id,
+                                     GLenum bind_target,
+                                     GLenum target,
+                                     GLint level,
+                                     GLenum internal_format,
+                                     GLenum format,
+                                     GLenum type,
+                                     GLint xoffset,
+                                     GLint yoffset,
+                                     GLsizei width,
+                                     GLsizei height);
 
   void SetupExpectationsForRestoreClearState(
       GLclampf restore_red,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc
index bb0286d..dfcccf5 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc
@@ -1820,26 +1820,12 @@
   DoTexImage2D(
       GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
   // Expect 2 levels will be cleared.
-  SetupClearTextureExpectations(kServiceTextureId,
-                                kServiceTextureId,
-                                GL_TEXTURE_2D,
-                                GL_TEXTURE_2D,
-                                0,
-                                GL_RGBA,
-                                GL_RGBA,
-                                GL_UNSIGNED_BYTE,
-                                2,
-                                2);
-  SetupClearTextureExpectations(kServiceTextureId,
-                                kServiceTextureId,
-                                GL_TEXTURE_2D,
-                                GL_TEXTURE_2D,
-                                1,
-                                GL_RGBA,
-                                GL_RGBA,
-                                GL_UNSIGNED_BYTE,
-                                1,
-                                1);
+  SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
+                                GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA,
+                                GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 2, 2);
+  SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
+                                GL_TEXTURE_2D, GL_TEXTURE_2D, 1, GL_RGBA,
+                                GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 1, 1);
   SetupExpectationsForApplyingDefaultDirtyState();
   EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
       .Times(1)
@@ -1867,26 +1853,12 @@
   DoTexImage2D(
       GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
   // Expect 2 levels will be cleared.
-  SetupClearTextureExpectations(kServiceTextureId,
-                                kServiceTextureId,
-                                GL_TEXTURE_2D,
-                                GL_TEXTURE_2D,
-                                0,
-                                GL_RGBA,
-                                GL_RGBA,
-                                GL_UNSIGNED_BYTE,
-                                2,
-                                2);
-  SetupClearTextureExpectations(kServiceTextureId,
-                                kServiceTextureId,
-                                GL_TEXTURE_2D,
-                                GL_TEXTURE_2D,
-                                1,
-                                GL_RGBA,
-                                GL_RGBA,
-                                GL_UNSIGNED_BYTE,
-                                1,
-                                1);
+  SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
+                                GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA,
+                                GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 2, 2);
+  SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
+                                GL_TEXTURE_2D, GL_TEXTURE_2D, 1, GL_RGBA,
+                                GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 1, 1);
   SetupExpectationsForApplyingDefaultDirtyState();
 
   EXPECT_CALL(*gl_,
@@ -2107,26 +2079,14 @@
                  shm_offset);
   }
   // Expect 2 levels will be cleared.
-  SetupClearTextureExpectations(kServiceTextureId,
-                                kServiceTextureId,
+  SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
                                 GL_TEXTURE_CUBE_MAP,
-                                GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
-                                0,
-                                GL_RGBA,
-                                GL_RGBA,
-                                GL_UNSIGNED_BYTE,
-                                2,
-                                2);
-  SetupClearTextureExpectations(kServiceTextureId,
-                                kServiceTextureId,
+                                GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA,
+                                GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 2, 2);
+  SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
                                 GL_TEXTURE_CUBE_MAP,
-                                GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
-                                1,
-                                GL_RGBA,
-                                GL_RGBA,
-                                GL_UNSIGNED_BYTE,
-                                1,
-                                1);
+                                GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 1, GL_RGBA,
+                                GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 1, 1);
   AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
   SetupExpectationsForApplyingDefaultDirtyState();
   EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
@@ -2310,9 +2270,9 @@
                0,
                0);
 
-  // Enable GL_SCISSOR_TEST to make sure we disable it in the clear,
-  // then re-enable it.
-  DoEnableDisable(GL_SCISSOR_TEST, true);
+  // Disable GL_SCISSOR_TEST to make sure we enable it in the clear,
+  // then disable it again.
+  DoEnableDisable(GL_SCISSOR_TEST, false);
 
   EXPECT_CALL(*gl_, GenFramebuffersEXT(1, _)).Times(1).RetiresOnSaturation();
   EXPECT_CALL(*gl_, BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, _))
@@ -2336,10 +2296,13 @@
                                   GLES2Decoder::kDefaultStencilMask);
   EXPECT_CALL(*gl_, ClearDepth(1.0f)).Times(1).RetiresOnSaturation();
   SetupExpectationsForDepthMask(true);
-  SetupExpectationsForEnableDisable(GL_SCISSOR_TEST, false);
+  EXPECT_CALL(*gl_, Scissor(0.0f, 0.0f, 1.0f, 1.0f))
+      .Times(1)
+      .RetiresOnSaturation();
 
   EXPECT_CALL(*gl_, Clear(GL_DEPTH_BUFFER_BIT)).Times(1).RetiresOnSaturation();
 
+  EXPECT_CALL(*gl_, Disable(GL_SCISSOR_TEST)).Times(1).RetiresOnSaturation();
   SetupExpectationsForRestoreClearState(0.0f, 0.0f, 0.0f, 0.0f, 0, 1.0f, true);
 
   EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, _)).Times(1).RetiresOnSaturation();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
index c41f34e..159813d46 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
@@ -103,16 +103,9 @@
   DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
   DoTexImage2D(
       GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
-  SetupClearTextureExpectations(kServiceTextureId,
-                                kServiceTextureId,
-                                GL_TEXTURE_2D,
-                                GL_TEXTURE_2D,
-                                0,
-                                GL_RGBA,
-                                GL_RGBA,
-                                GL_UNSIGNED_BYTE,
-                                2,
-                                2);
+  SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
+                                GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA,
+                                GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 2, 2);
   EXPECT_CALL(*gl_, GenerateMipmapEXT(GL_TEXTURE_2D));
   EXPECT_CALL(*gl_, GetError())
       .WillOnce(Return(GL_NO_ERROR))
@@ -139,16 +132,9 @@
   DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
   DoTexImage2D(
       GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
-  SetupClearTextureExpectations(kServiceTextureId,
-                                kServiceTextureId,
-                                GL_TEXTURE_2D,
-                                GL_TEXTURE_2D,
-                                0,
-                                GL_RGBA,
-                                GL_RGBA,
-                                GL_UNSIGNED_BYTE,
-                                2,
-                                2);
+  SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
+                                GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA,
+                                GL_RGBA, GL_UNSIGNED_BYTE, 0, 0, 2, 2);
   EXPECT_CALL(
       *gl_,
       TexParameteri(
@@ -511,16 +497,6 @@
                kSharedMemoryId,
                kSharedMemoryOffset);
     } else {
-      SetupClearTextureExpectations(kServiceTextureId,
-                                    kServiceTextureId,
-                                    GL_TEXTURE_2D,
-                                    GL_TEXTURE_2D,
-                                    0,
-                                    GL_RGBA,
-                                    GL_RGBA,
-                                    GL_UNSIGNED_BYTE,
-                                    kWidth,
-                                    kHeight);
       cmd.Init(GL_TEXTURE_2D,
                0,
                GL_RGBA,
@@ -1776,52 +1752,23 @@
   DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
   DoTexImage2D(
       GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
-  SetupClearTextureExpectations(kServiceTextureId,
-                                kServiceTextureId,
-                                GL_TEXTURE_2D,
-                                GL_TEXTURE_2D,
-                                0,
-                                GL_RGBA,
-                                GL_RGBA,
-                                GL_UNSIGNED_BYTE,
-                                2,
-                                2);
-  EXPECT_CALL(*gl_,
-              TexSubImage2D(GL_TEXTURE_2D,
-                            0,
-                            1,
-                            1,
-                            1,
-                            1,
-                            GL_RGBA,
-                            GL_UNSIGNED_BYTE,
-                            shared_memory_address_))
-      .Times(1)
+  SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
+                                GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA,
+                                GL_RGBA, GL_UNSIGNED_BYTE, 0, 1, 2, 1);
+  EXPECT_CALL(*gl_, TexSubImage2D(GL_TEXTURE_2D, 0, 0, _, _, 1, GL_RGBA,
+                                  GL_UNSIGNED_BYTE, shared_memory_address_))
+      .Times(2)
       .RetiresOnSaturation();
   TexSubImage2D cmd;
-  cmd.Init(GL_TEXTURE_2D,
-           0,
-           1,
-           1,
-           1,
-           1,
-           GL_RGBA,
-           GL_UNSIGNED_BYTE,
-           kSharedMemoryId,
-           kSharedMemoryOffset,
-           GL_FALSE);
+  cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 2, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+           kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  cmd.Init(GL_TEXTURE_2D, 0, 0, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+           kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
   // Test if we call it again it does not clear.
-  EXPECT_CALL(*gl_,
-              TexSubImage2D(GL_TEXTURE_2D,
-                            0,
-                            1,
-                            1,
-                            1,
-                            1,
-                            GL_RGBA,
-                            GL_UNSIGNED_BYTE,
-                            shared_memory_address_))
+  EXPECT_CALL(*gl_, TexSubImage2D(GL_TEXTURE_2D, 0, 0, 1, 1, 1, GL_RGBA,
+                                  GL_UNSIGNED_BYTE, shared_memory_address_))
       .Times(1)
       .RetiresOnSaturation();
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
@@ -1978,40 +1925,19 @@
   // It won't actually call TexImage2D, just mark it as uncleared.
   EXPECT_EQ(error::kNoError, ExecuteCmd(tex_cmd));
   // Next call to TexSubImage2d should clear.
-  SetupClearTextureExpectations(kServiceTextureId,
-                                kServiceTextureId,
-                                GL_TEXTURE_2D,
-                                GL_TEXTURE_2D,
-                                0,
-                                GL_RGBA,
-                                GL_RGBA,
-                                GL_UNSIGNED_BYTE,
-                                2,
-                                2);
-  EXPECT_CALL(*gl_,
-              TexSubImage2D(GL_TEXTURE_2D,
-                            0,
-                            1,
-                            1,
-                            1,
-                            1,
-                            GL_RGBA,
-                            GL_UNSIGNED_BYTE,
-                            shared_memory_address_))
-      .Times(1)
+  SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
+                                GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA,
+                                GL_RGBA, GL_UNSIGNED_BYTE, 0, 1, 2, 1);
+  EXPECT_CALL(*gl_, TexSubImage2D(GL_TEXTURE_2D, 0, 0, _, _, 1, GL_RGBA,
+                                  GL_UNSIGNED_BYTE, shared_memory_address_))
+      .Times(2)
       .RetiresOnSaturation();
   TexSubImage2D cmd;
-  cmd.Init(GL_TEXTURE_2D,
-           0,
-           1,
-           1,
-           1,
-           1,
-           GL_RGBA,
-           GL_UNSIGNED_BYTE,
-           kSharedMemoryId,
-           kSharedMemoryOffset,
-           GL_FALSE);
+  cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 2, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+           kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  cmd.Init(GL_TEXTURE_2D, 0, 0, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+           kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
 }
 
@@ -2039,27 +1965,67 @@
   EXPECT_TRUE(texture->SafeToRenderFrom());
 }
 
-TEST_P(GLES2DecoderTest, CopyTexSubImage2DClearsUnclearedTexture) {
+TEST_P(GLES2DecoderTest, CopyTexSubImage2DTwiceMarksTextureAsCleared) {
   DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
   DoTexImage2D(
       GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
 
-  SetupClearTextureExpectations(kServiceTextureId,
-                                kServiceTextureId,
-                                GL_TEXTURE_2D,
-                                GL_TEXTURE_2D,
-                                0,
-                                GL_RGBA,
-                                GL_RGBA,
-                                GL_UNSIGNED_BYTE,
-                                2,
-                                2);
-  EXPECT_CALL(*gl_, CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1))
-      .Times(1)
-      .RetiresOnSaturation();
-  CopyTexSubImage2D cmd;
-  cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
-  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  // This will initialize the top part.
+  {
+    EXPECT_CALL(*gl_, CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 2, 1))
+        .Times(1)
+        .RetiresOnSaturation();
+    CopyTexSubImage2D cmd;
+    cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 2, 1);
+    EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  }
+
+  // This will initialize the bottom part.
+  {
+    EXPECT_CALL(*gl_, CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 1, 0, 0, 2, 1))
+        .Times(1)
+        .RetiresOnSaturation();
+    CopyTexSubImage2D cmd;
+    cmd.Init(GL_TEXTURE_2D, 0, 0, 1, 0, 0, 2, 1);
+    EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  }
+
+  TextureManager* manager = group().texture_manager();
+  TextureRef* texture_ref = manager->GetTexture(client_texture_id_);
+  ASSERT_TRUE(texture_ref != NULL);
+  Texture* texture = texture_ref->texture();
+  EXPECT_TRUE(texture->SafeToRenderFrom());
+}
+
+TEST_P(GLES2DecoderTest, CopyTexSubImage2DTwiceClearsUnclearedTexture) {
+  DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+  DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0,
+               0);
+
+  // This will initialize the top part.
+  {
+    EXPECT_CALL(*gl_, CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 2, 1))
+        .Times(1)
+        .RetiresOnSaturation();
+    CopyTexSubImage2D cmd;
+    cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 2, 1);
+    EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  }
+
+  SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
+                                GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA,
+                                GL_RGBA, GL_UNSIGNED_BYTE, 0, 1, 2, 1);
+
+  // This will clear the bottom part as a rectangle is not sufficient to keep
+  // track of the initialized area.
+  {
+    EXPECT_CALL(*gl_, CopyTexSubImage2D(GL_TEXTURE_2D, 0, 1, 1, 0, 0, 1, 1))
+        .Times(1)
+        .RetiresOnSaturation();
+    CopyTexSubImage2D cmd;
+    cmd.Init(GL_TEXTURE_2D, 0, 1, 1, 0, 0, 1, 1);
+    EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  }
 
   TextureManager* manager = group().texture_manager();
   TextureRef* texture_ref = manager->GetTexture(client_texture_id_);
@@ -2680,8 +2646,8 @@
                                   height, format, type, _))
       .Times(1)
       .RetiresOnSaturation();
-  GetDecoder()->ClearLevel(texture, target, level, format, format, type, width,
-                           height, false);
+  GetDecoder()->ClearLevel(texture, target, level, format, type, 0, 0, width,
+                           height);
   EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == image.get());
 }
 
@@ -2895,17 +2861,9 @@
   TextureRef* texture_ref = GetTexture(client_texture_id_);
   scoped_refptr<MockGLImage> image(new MockGLImage);
   group().texture_manager()->SetTarget(texture_ref, GL_TEXTURE_EXTERNAL_OES);
-  group().texture_manager()->SetLevelInfo(texture_ref,
-                                          GL_TEXTURE_EXTERNAL_OES,
-                                          0,
-                                          GL_RGBA,
-                                          0,
-                                          0,
-                                          1,
-                                          0,
-                                          GL_RGBA,
-                                          GL_UNSIGNED_BYTE,
-                                          true);
+  group().texture_manager()->SetLevelInfo(texture_ref, GL_TEXTURE_EXTERNAL_OES,
+                                          0, GL_RGBA, 0, 0, 1, 0, GL_RGBA,
+                                          GL_UNSIGNED_BYTE, gfx::Rect());
   group().texture_manager()->SetLevelImage(
       texture_ref, GL_TEXTURE_EXTERNAL_OES, 0, image.get());
 
@@ -3058,40 +3016,19 @@
                GL_FLOAT,
                0,
                0);
-  SetupClearTextureExpectations(kServiceTextureId,
-                                kServiceTextureId,
-                                GL_TEXTURE_2D,
-                                GL_TEXTURE_2D,
-                                0,
-                                GL_RGBA32F,
-                                GL_RGBA,
-                                GL_FLOAT,
-                                kWidth,
-                                kHeight);
-  EXPECT_CALL(*gl_,
-              TexSubImage2D(GL_TEXTURE_2D,
-                            0,
-                            1,
-                            0,
-                            kWidth - 1,
-                            kHeight,
-                            GL_RGBA,
-                            GL_FLOAT,
-                            shared_memory_address_))
-      .Times(1)
+  SetupClearTextureExpectations(kServiceTextureId, kServiceTextureId,
+                                GL_TEXTURE_2D, GL_TEXTURE_2D, 0, GL_RGBA32F,
+                                GL_RGBA, GL_FLOAT, 0, kHeight - 1, kWidth, 1);
+  EXPECT_CALL(*gl_, TexSubImage2D(GL_TEXTURE_2D, 0, 0, _, _, _, GL_RGBA,
+                                  GL_FLOAT, shared_memory_address_))
+      .Times(2)
       .RetiresOnSaturation();
   TexSubImage2D cmd;
-  cmd.Init(GL_TEXTURE_2D,
-           0,
-           1,
-           0,
-           kWidth - 1,
-           kHeight,
-           GL_RGBA,
-           GL_FLOAT,
-           kSharedMemoryId,
-           kSharedMemoryOffset,
-           GL_FALSE);
+  cmd.Init(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight - 1, GL_RGBA, GL_FLOAT,
+           kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  cmd.Init(GL_TEXTURE_2D, 0, 0, kHeight - 1, kWidth - 1, 1, GL_RGBA, GL_FLOAT,
+           kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
   EXPECT_EQ(GL_NO_ERROR, GetGLError());
 }
diff --git a/gpu/command_buffer/service/mailbox_manager_unittest.cc b/gpu/command_buffer/service/mailbox_manager_unittest.cc
index 0e064d4..3e14b76 100644
--- a/gpu/command_buffer/service/mailbox_manager_unittest.cc
+++ b/gpu/command_buffer/service/mailbox_manager_unittest.cc
@@ -47,29 +47,19 @@
     texture->SetTarget(NULL, target, max_level);
   }
 
-  void SetLevelInfo(
-      Texture* texture,
-      GLenum target,
-      GLint level,
-      GLenum internal_format,
-      GLsizei width,
-      GLsizei height,
-      GLsizei depth,
-      GLint border,
-      GLenum format,
-      GLenum type,
-      bool cleared) {
-    texture->SetLevelInfo(NULL,
-                          target,
-                          level,
-                          internal_format,
-                          width,
-                          height,
-                          depth,
-                          border,
-                          format,
-                          type,
-                          cleared);
+  void SetLevelInfo(Texture* texture,
+                    GLenum target,
+                    GLint level,
+                    GLenum internal_format,
+                    GLsizei width,
+                    GLsizei height,
+                    GLsizei depth,
+                    GLint border,
+                    GLenum format,
+                    GLenum type,
+                    const gfx::Rect& cleared_rect) {
+    texture->SetLevelInfo(NULL, target, level, internal_format, width, height,
+                          depth, border, format, type, cleared_rect);
   }
 
   void SetLevelCleared(Texture* texture,
@@ -211,17 +201,8 @@
     const GLsizei levels_needed = TextureManager::ComputeMipMapCount(
         GL_TEXTURE_2D, kMaxTextureWidth, kMaxTextureHeight, kMaxTextureDepth);
     SetTarget(texture, GL_TEXTURE_2D, levels_needed);
-    SetLevelInfo(texture,
-                 GL_TEXTURE_2D,
-                 0,
-                 GL_RGBA,
-                 1,
-                 1,
-                 1,
-                 0,
-                 GL_RGBA,
-                 GL_UNSIGNED_BYTE,
-                 true);
+    SetLevelInfo(texture, GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA,
+                 GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
     SetParameter(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     SetParameter(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     return texture;
@@ -352,17 +333,8 @@
   EXPECT_EQ(kNewTextureId, new_texture->service_id());
 
   // Resize original texture
-  SetLevelInfo(texture,
-               GL_TEXTURE_2D,
-               0,
-               GL_RGBA,
-               16,
-               32,
-               1,
-               0,
-               GL_RGBA,
-               GL_UNSIGNED_BYTE,
-               true);
+  SetLevelInfo(texture, GL_TEXTURE_2D, 0, GL_RGBA, 16, 32, 1, 0, GL_RGBA,
+               GL_UNSIGNED_BYTE, gfx::Rect(16, 32));
   // Should have been orphaned
   EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL);
 
@@ -379,17 +351,8 @@
   // Should have gotten a new attachment
   EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) != NULL);
   // Resize original texture again....
-  SetLevelInfo(texture,
-               GL_TEXTURE_2D,
-               0,
-               GL_RGBA,
-               64,
-               64,
-               1,
-               0,
-               GL_RGBA,
-               GL_UNSIGNED_BYTE,
-               true);
+  SetLevelInfo(texture, GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 1, 0, GL_RGBA,
+               GL_UNSIGNED_BYTE, gfx::Rect(64, 64));
   // ...and immediately delete the texture which should save the changes.
   SetupUpdateTexParamExpectations(
       kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
@@ -624,17 +587,8 @@
   EXPECT_FALSE(new_texture->IsDefined());
 
   // Change cleared to false.
-  SetLevelInfo(texture,
-               GL_TEXTURE_2D,
-               0,
-               GL_RGBA,
-               1,
-               1,
-               1,
-               0,
-               GL_RGBA,
-               GL_UNSIGNED_BYTE,
-               true);
+  SetLevelInfo(texture, GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA,
+               GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
   SetParameter(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   SetParameter(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   EXPECT_TRUE(texture->IsDefined());
diff --git a/gpu/command_buffer/service/shader_translator_unittest.cc b/gpu/command_buffer/service/shader_translator_unittest.cc
index b9efe24..5f61738 100644
--- a/gpu/command_buffer/service/shader_translator_unittest.cc
+++ b/gpu/command_buffer/service/shader_translator_unittest.cc
@@ -282,39 +282,6 @@
   EXPECT_STREQ("bar[1].foo.color[0]", original_name.c_str());
 }
 
-#if defined(OS_MACOSX)
-TEST_F(ShaderTranslatorTest, BuiltInFunctionEmulation) {
-  // This test might become invalid in the future when ANGLE Translator is no
-  // longer emulate dot(float, float) in Mac, or the emulated function name is
-  // no longer webgl_dot_emu.
-  const char* shader =
-      "void main() {\n"
-      "  gl_Position = vec4(dot(1.0, 1.0), 1.0, 1.0, 1.0);\n"
-      "}";
-
-  std::string info_log, translated_source;
-  int shader_version;
-  AttributeMap attrib_map;
-  UniformMap uniform_map;
-  VaryingMap varying_map;
-  NameMap name_map;
-  EXPECT_TRUE(vertex_translator_->Translate(shader,
-                                            &info_log,
-                                            &translated_source,
-                                            &shader_version,
-                                            &attrib_map,
-                                            &uniform_map,
-                                            &varying_map,
-                                            &name_map));
-  // Info log must be NULL.
-  EXPECT_TRUE(info_log.empty());
-  // Translated shader must be valid and non-empty.
-  ASSERT_FALSE(translated_source.empty());
-  EXPECT_TRUE(strstr(translated_source.c_str(),
-                     "webgl_dot_emu") != NULL);
-}
-#endif
-
 TEST_F(ShaderTranslatorTest, OptionsString) {
   scoped_refptr<ShaderTranslator> translator_1 = new ShaderTranslator();
   scoped_refptr<ShaderTranslator> translator_2 = new ShaderTranslator();
diff --git a/gpu/command_buffer/service/stream_texture_manager_in_process_android.cc b/gpu/command_buffer/service/stream_texture_manager_in_process_android.cc
index 58e58d0..caf3fb6 100644
--- a/gpu/command_buffer/service/stream_texture_manager_in_process_android.cc
+++ b/gpu/command_buffer/service/stream_texture_manager_in_process_android.cc
@@ -135,17 +135,9 @@
 
   gfx::Size size = gl_image->GetSize();
   texture_manager->SetTarget(texture, GL_TEXTURE_EXTERNAL_OES);
-  texture_manager->SetLevelInfo(texture,
-                                GL_TEXTURE_EXTERNAL_OES,
-                                0,
-                                GL_RGBA,
-                                size.width(),
-                                size.height(),
-                                1,
-                                0,
-                                GL_RGBA,
-                                GL_UNSIGNED_BYTE,
-                                true);
+  texture_manager->SetLevelInfo(texture, GL_TEXTURE_EXTERNAL_OES, 0, GL_RGBA,
+                                size.width(), size.height(), 1, 0, GL_RGBA,
+                                GL_UNSIGNED_BYTE, gfx::Rect(size));
   texture_manager->SetLevelImage(
       texture, GL_TEXTURE_EXTERNAL_OES, 0, gl_image.get());
 
diff --git a/gpu/command_buffer/service/texture_definition.cc b/gpu/command_buffer/service/texture_definition.cc
index 511a428..c19b5d3d 100644
--- a/gpu/command_buffer/service/texture_definition.cc
+++ b/gpu/command_buffer/service/texture_definition.cc
@@ -311,8 +311,7 @@
       depth(0),
       border(0),
       format(0),
-      type(0),
-      cleared(false) {
+      type(0) {
 }
 
 TextureDefinition::LevelInfo::LevelInfo(GLenum target,
@@ -323,7 +322,7 @@
                                         GLint border,
                                         GLenum format,
                                         GLenum type,
-                                        bool cleared)
+                                        const gfx::Rect& cleared_rect)
     : target(target),
       internal_format(internal_format),
       width(width),
@@ -332,7 +331,8 @@
       border(border),
       format(format),
       type(type),
-      cleared(cleared) {}
+      cleared_rect(cleared_rect) {
+}
 
 TextureDefinition::LevelInfo::~LevelInfo() {}
 
@@ -379,7 +379,7 @@
   const Texture::LevelInfo& level = first_face.level_infos[0];
   level_info_ = LevelInfo(level.target, level.internal_format, level.width,
                           level.height, level.depth, level.border, level.format,
-                          level.type, level.cleared);
+                          level.type, level.cleared_rect);
 }
 
 TextureDefinition::~TextureDefinition() {
@@ -421,7 +421,7 @@
                           level_info_.internal_format, level_info_.width,
                           level_info_.height, level_info_.depth,
                           level_info_.border, level_info_.format,
-                          level_info_.type, level_info_.cleared);
+                          level_info_.type, level_info_.cleared_rect);
   }
 
   if (image_buffer_.get()) {
@@ -489,7 +489,8 @@
 }
 
 bool TextureDefinition::SafeToRenderFrom() const {
-  return level_info_.cleared;
+  return level_info_.cleared_rect.Contains(
+      gfx::Rect(level_info_.width, level_info_.height));
 }
 
 }  // namespace gles2
diff --git a/gpu/command_buffer/service/texture_definition.h b/gpu/command_buffer/service/texture_definition.h
index e531184..19c953cb1 100644
--- a/gpu/command_buffer/service/texture_definition.h
+++ b/gpu/command_buffer/service/texture_definition.h
@@ -9,6 +9,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "gpu/command_buffer/service/gl_utils.h"
+#include "ui/gfx/geometry/rect.h"
 
 namespace gfx {
 class GLImage;
@@ -84,7 +85,7 @@
               GLint border,
               GLenum format,
               GLenum type,
-              bool cleared);
+              const gfx::Rect& cleared_rect);
     ~LevelInfo();
 
     GLenum target;
@@ -95,7 +96,7 @@
     GLint border;
     GLenum format;
     GLenum type;
-    bool cleared;
+    gfx::Rect cleared_rect;
   };
 
   unsigned int version_;
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index 2596dca..c7150ee9 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -379,8 +379,7 @@
 }
 
 Texture::LevelInfo::LevelInfo()
-    : cleared(true),
-      target(0),
+    : target(0),
       level(-1),
       internal_format(0),
       width(0),
@@ -393,7 +392,7 @@
 }
 
 Texture::LevelInfo::LevelInfo(const LevelInfo& rhs)
-    : cleared(rhs.cleared),
+    : cleared_rect(rhs.cleared_rect),
       target(rhs.target),
       level(rhs.level),
       internal_format(rhs.internal_format),
@@ -540,17 +539,9 @@
       width = std::max(1, width >> 1);
       height = std::max(1, height >> 1);
       depth = std::max(1, depth >> 1);
-      SetLevelInfo(feature_info,
-                   target,
-                   level,
-                   level0_info.internal_format,
-                   width,
-                   height,
-                   depth,
-                   level0_info.border,
-                   level0_info.format,
-                   level0_info.type,
-                   true);
+      SetLevelInfo(feature_info, target, level, level0_info.internal_format,
+                   width, height, depth, level0_info.border, level0_info.format,
+                   level0_info.type, gfx::Rect(width, height));
     }
   }
 
@@ -665,7 +656,9 @@
   return complete;
 }
 
-void Texture::SetLevelCleared(GLenum target, GLint level, bool cleared) {
+void Texture::SetLevelClearedRect(GLenum target,
+                                  GLint level,
+                                  const gfx::Rect& cleared_rect) {
   DCHECK_GE(level, 0);
   size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
   DCHECK_LT(static_cast<size_t>(face_index),
@@ -674,7 +667,19 @@
             face_infos_[face_index].level_infos.size());
   Texture::LevelInfo& info =
       face_infos_[face_index].level_infos[level];
-  UpdateMipCleared(&info, cleared);
+  UpdateMipCleared(&info, info.width, info.height, cleared_rect);
+  UpdateCleared();
+}
+
+void Texture::SetLevelCleared(GLenum target, GLint level, bool cleared) {
+  DCHECK_GE(level, 0);
+  size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
+  DCHECK_LT(static_cast<size_t>(face_index), face_infos_.size());
+  DCHECK_LT(static_cast<size_t>(level),
+            face_infos_[face_index].level_infos.size());
+  Texture::LevelInfo& info = face_infos_[face_index].level_infos[level];
+  UpdateMipCleared(&info, info.width, info.height,
+                   cleared ? gfx::Rect(info.width, info.height) : gfx::Rect());
   UpdateCleared();
 }
 
@@ -703,10 +708,17 @@
     (*it)->manager()->UpdateSafeToRenderFrom(delta);
 }
 
-void Texture::UpdateMipCleared(LevelInfo* info, bool cleared) {
-  if (info->cleared == cleared)
+void Texture::UpdateMipCleared(LevelInfo* info,
+                               GLsizei width,
+                               GLsizei height,
+                               const gfx::Rect& cleared_rect) {
+  bool was_cleared = info->cleared_rect == gfx::Rect(info->width, info->height);
+  info->width = width;
+  info->height = height;
+  info->cleared_rect = cleared_rect;
+  bool cleared = info->cleared_rect == gfx::Rect(info->width, info->height);
+  if (cleared == was_cleared)
     return;
-  info->cleared = cleared;
   int delta = cleared ? -1 : +1;
   num_uncleared_mips_ += delta;
   for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
@@ -751,18 +763,17 @@
     (*it)->manager()->IncFramebufferStateChangeCount();
 }
 
-void Texture::SetLevelInfo(
-    const FeatureInfo* feature_info,
-    GLenum target,
-    GLint level,
-    GLenum internal_format,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    bool cleared) {
+void Texture::SetLevelInfo(const FeatureInfo* feature_info,
+                           GLenum target,
+                           GLint level,
+                           GLenum internal_format,
+                           GLsizei width,
+                           GLsizei height,
+                           GLsizei depth,
+                           GLint border,
+                           GLenum format,
+                           GLenum type,
+                           const gfx::Rect& cleared_rect) {
   DCHECK_GE(level, 0);
   size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
   DCHECK_LT(static_cast<size_t>(face_index),
@@ -807,20 +818,19 @@
   info.target = target;
   info.level = level;
   info.internal_format = internal_format;
-  info.width = width;
-  info.height = height;
   info.depth = depth;
   info.border = border;
   info.format = format;
   info.type = type;
   info.image = 0;
 
+  UpdateMipCleared(&info, width, height, cleared_rect);
+
   estimated_size_ -= info.estimated_size;
   GLES2Util::ComputeImageDataSizes(
       width, height, 1, format, type, 4, &info.estimated_size, NULL, NULL);
   estimated_size_ += info.estimated_size;
 
-  UpdateMipCleared(&info, cleared);
   max_level_set_ = std::max(max_level_set_, level);
   Update(feature_info);
   UpdateCleared();
@@ -1146,6 +1156,18 @@
   return true;
 }
 
+gfx::Rect Texture::GetLevelClearedRect(GLenum target, GLint level) const {
+  size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
+  if (face_index >= face_infos_.size() ||
+      level >= static_cast<GLint>(face_infos_[face_index].level_infos.size())) {
+    return gfx::Rect();
+  }
+
+  const Texture::LevelInfo& info = face_infos_[face_index].level_infos[level];
+
+  return info.cleared_rect;
+}
+
 bool Texture::IsLevelCleared(GLenum target, GLint level) const {
   size_t face_index = GLES2Util::GLTargetToFaceIndex(target);
   if (face_index >= face_infos_.size() ||
@@ -1155,7 +1177,7 @@
 
   const Texture::LevelInfo& info = face_infos_[face_index].level_infos[level];
 
-  return info.cleared;
+  return info.cleared_rect == gfx::Rect(info.width, info.height);
 }
 
 void Texture::InitTextureMaxAnisotropyIfNeeded(GLenum target) {
@@ -1180,21 +1202,41 @@
   DCHECK(target == info.target);
 
   if (info.target == 0 ||
-      info.cleared ||
-      info.width == 0 ||
-      info.height == 0 ||
-      info.depth == 0) {
+      info.cleared_rect == gfx::Rect(info.width, info.height) ||
+      info.width == 0 || info.height == 0 || info.depth == 0) {
     return true;
   }
 
-  // NOTE: It seems kind of gross to call back into the decoder for this
-  // but only the decoder knows all the state (like unpack_alignment_) that's
-  // needed to be able to call GL correctly.
-  bool cleared = decoder->ClearLevel(
-      this, info.target, info.level, info.internal_format, info.format,
-      info.type, info.width, info.height, immutable_);
-  UpdateMipCleared(&info, cleared);
-  return info.cleared;
+  // Clear all remaining sub regions.
+  const int x[] = {
+      0, info.cleared_rect.x(), info.cleared_rect.right(), info.width};
+  const int y[] = {
+      0, info.cleared_rect.y(), info.cleared_rect.bottom(), info.height};
+
+  for (size_t j = 0; j < 3; ++j) {
+    for (size_t i = 0; i < 3; ++i) {
+      // Center of nine patch is already cleared.
+      if (j == 1 && i == 1)
+        continue;
+
+      gfx::Rect rect(x[i], y[j], x[i + 1] - x[i], y[j + 1] - y[j]);
+      if (rect.IsEmpty())
+        continue;
+
+      // NOTE: It seems kind of gross to call back into the decoder for this
+      // but only the decoder knows all the state (like unpack_alignment_)
+      // that's needed to be able to call GL correctly.
+      bool cleared = decoder->ClearLevel(this, info.target, info.level,
+                                         info.format, info.type, rect.x(),
+                                         rect.y(), rect.width(), rect.height());
+      if (!cleared)
+        return false;
+    }
+  }
+
+  UpdateMipCleared(&info, info.width, info.height,
+                   gfx::Rect(info.width, info.height));
+  return true;
 }
 
 void Texture::SetLevelImage(
@@ -1373,43 +1415,17 @@
     SetTarget(default_texture.get(), target);
     if (needs_faces) {
       for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) {
-        SetLevelInfo(default_texture.get(),
-                     GLES2Util::IndexToGLFaceTarget(ii),
-                     0,
-                     GL_RGBA,
-                     1,
-                     1,
-                     1,
-                     0,
-                     GL_RGBA,
-                     GL_UNSIGNED_BYTE,
-                     true);
+        SetLevelInfo(default_texture.get(), GLES2Util::IndexToGLFaceTarget(ii),
+                     0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                     gfx::Rect(1, 1));
       }
     } else {
       if (needs_initialization) {
-        SetLevelInfo(default_texture.get(),
-                     GL_TEXTURE_2D,
-                     0,
-                     GL_RGBA,
-                     1,
-                     1,
-                     1,
-                     0,
-                     GL_RGBA,
-                     GL_UNSIGNED_BYTE,
-                     true);
+        SetLevelInfo(default_texture.get(), GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1,
+                     0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
       } else {
-        SetLevelInfo(default_texture.get(),
-                     GL_TEXTURE_EXTERNAL_OES,
-                     0,
-                     GL_RGBA,
-                     1,
-                     1,
-                     1,
-                     0,
-                     GL_RGBA,
-                     GL_UNSIGNED_BYTE,
-                     true);
+        SetLevelInfo(default_texture.get(), GL_TEXTURE_EXTERNAL_OES, 0, GL_RGBA,
+                     1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
       }
     }
   }
@@ -1443,6 +1459,14 @@
       ->SetTarget(feature_info_.get(), target, MaxLevelsForTarget(target));
 }
 
+void TextureManager::SetLevelClearedRect(TextureRef* ref,
+                                         GLenum target,
+                                         GLint level,
+                                         const gfx::Rect& cleared_rect) {
+  DCHECK(ref);
+  ref->texture()->SetLevelClearedRect(target, level, cleared_rect);
+}
+
 void TextureManager::SetLevelCleared(TextureRef* ref,
                                      GLenum target,
                                      GLint level,
@@ -1470,33 +1494,25 @@
   return result;
 }
 
-void TextureManager::SetLevelInfo(
-    TextureRef* ref,
-    GLenum target,
-    GLint level,
-    GLenum internal_format,
-    GLsizei width,
-    GLsizei height,
-    GLsizei depth,
-    GLint border,
-    GLenum format,
-    GLenum type,
-    bool cleared) {
+void TextureManager::SetLevelInfo(TextureRef* ref,
+                                  GLenum target,
+                                  GLint level,
+                                  GLenum internal_format,
+                                  GLsizei width,
+                                  GLsizei height,
+                                  GLsizei depth,
+                                  GLint border,
+                                  GLenum format,
+                                  GLenum type,
+                                  const gfx::Rect& cleared_rect) {
+  DCHECK(gfx::Rect(width, height).Contains(cleared_rect));
   DCHECK(ref);
   Texture* texture = ref->texture();
 
   texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
-  texture->SetLevelInfo(feature_info_.get(),
-                        target,
-                        level,
-                        internal_format,
-                        width,
-                        height,
-                        depth,
-                        border,
-                        format,
-                        type,
-                        cleared);
+  texture->SetLevelInfo(feature_info_.get(), target, level, internal_format,
+                        width, height, depth, border, format, type,
+                        cleared_rect);
   texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
 }
 
@@ -1947,10 +1963,9 @@
 
   if (level_is_same && !args.pixels) {
     // Just set the level texture but mark the texture as uncleared.
-    SetLevelInfo(
-        texture_ref,
-        args.target, args.level, args.internal_format, args.width, args.height,
-        args.depth, args.border, args.format, args.type, false);
+    SetLevelInfo(texture_ref, args.target, args.level, args.internal_format,
+                 args.width, args.height, args.depth, args.border, args.format,
+                 args.type, gfx::Rect());
     texture_state->tex_image_failed = false;
     return;
   }
@@ -1993,9 +2008,9 @@
   GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, function_name);
   if (error == GL_NO_ERROR) {
     SetLevelInfo(
-        texture_ref,
-        args.target, args.level, args.internal_format, args.width, args.height,
-        args.depth, args.border, args.format, args.type, args.pixels != NULL);
+        texture_ref, args.target, args.level, args.internal_format, args.width,
+        args.height, args.depth, args.border, args.format, args.type,
+        args.pixels != NULL ? gfx::Rect(args.width, args.height) : gfx::Rect());
     texture_state->tex_image_failed = false;
   }
 }
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h
index bc4c5c85..d72ffb6 100644
--- a/gpu/command_buffer/service/texture_manager.h
+++ b/gpu/command_buffer/service/texture_manager.h
@@ -17,6 +17,7 @@
 #include "gpu/command_buffer/service/gl_utils.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
 #include "gpu/gpu_export.h"
+#include "ui/gfx/geometry/rect.h"
 #include "ui/gl/gl_image.h"
 
 namespace gpu {
@@ -182,6 +183,10 @@
     return immutable_;
   }
 
+  // Get the cleared rectangle for a particular level. Returns an empty
+  // rectangle if level does not exist.
+  gfx::Rect GetLevelClearedRect(GLenum target, GLint level) const;
+
   // Whether a particular level/face is cleared.
   bool IsLevelCleared(GLenum target, GLint level) const;
 
@@ -227,7 +232,7 @@
     LevelInfo(const LevelInfo& rhs);
     ~LevelInfo();
 
-    bool cleared;
+    gfx::Rect cleared_rect;
     GLenum target;
     GLint level;
     GLenum internal_format;
@@ -250,18 +255,17 @@
   };
 
   // Set the info for a particular level.
-  void SetLevelInfo(
-      const FeatureInfo* feature_info,
-      GLenum target,
-      GLint level,
-      GLenum internal_format,
-      GLsizei width,
-      GLsizei height,
-      GLsizei depth,
-      GLint border,
-      GLenum format,
-      GLenum type,
-      bool cleared);
+  void SetLevelInfo(const FeatureInfo* feature_info,
+                    GLenum target,
+                    GLint level,
+                    GLenum internal_format,
+                    GLsizei width,
+                    GLsizei height,
+                    GLsizei depth,
+                    GLint border,
+                    GLenum format,
+                    GLenum type,
+                    const gfx::Rect& cleared_rect);
 
   // In GLES2 "texture complete" means it has all required mips for filtering
   // down to a 1x1 pixel texture, they are in the correct order, they are all
@@ -281,6 +285,11 @@
     return npot_;
   }
 
+  // Marks a |rect| of a particular level as cleared.
+  void SetLevelClearedRect(GLenum target,
+                           GLint level,
+                           const gfx::Rect& cleared_rect);
+
   // Marks a particular level as cleared or uncleared.
   void SetLevelCleared(GLenum target, GLint level, bool cleared);
 
@@ -374,7 +383,10 @@
 
   // Updates the uncleared mip count in all the managers referencing this
   // texture.
-  void UpdateMipCleared(LevelInfo* info, bool cleared);
+  void UpdateMipCleared(LevelInfo* info,
+                        GLsizei width,
+                        GLsizei height,
+                        const gfx::Rect& cleared_rect);
 
   // Computes the CanRenderCondition flag.
   CanRenderCondition GetCanRenderCondition() const;
@@ -649,27 +661,25 @@
       GLenum target);
 
   // Set the info for a particular level in a TexureInfo.
-  void SetLevelInfo(
-      TextureRef* ref,
-      GLenum target,
-      GLint level,
-      GLenum internal_format,
-      GLsizei width,
-      GLsizei height,
-      GLsizei depth,
-      GLint border,
-      GLenum format,
-      GLenum type,
-      bool cleared);
+  void SetLevelInfo(TextureRef* ref,
+                    GLenum target,
+                    GLint level,
+                    GLenum internal_format,
+                    GLsizei width,
+                    GLsizei height,
+                    GLsizei depth,
+                    GLint border,
+                    GLenum format,
+                    GLenum type,
+                    const gfx::Rect& cleared_rect);
 
   // Adapter to call above function.
   void SetLevelInfoFromParams(TextureRef* ref,
                               const gpu::AsyncTexImage2DParams& params) {
-    SetLevelInfo(
-        ref, params.target, params.level, params.internal_format,
-        params.width, params.height, 1 /* depth */,
-        params.border, params.format,
-        params.type, true /* cleared */);
+    SetLevelInfo(ref, params.target, params.level, params.internal_format,
+                 params.width, params.height, 1 /* depth */, params.border,
+                 params.format, params.type,
+                 gfx::Rect(params.width, params.height) /* cleared_rect */);
   }
 
   Texture* Produce(TextureRef* ref);
@@ -677,6 +687,12 @@
   // Maps an existing texture into the texture manager, at a given client ID.
   TextureRef* Consume(GLuint client_id, Texture* texture);
 
+  // Sets |rect| of mip as cleared.
+  void SetLevelClearedRect(TextureRef* ref,
+                           GLenum target,
+                           GLint level,
+                           const gfx::Rect& cleared_rect);
+
   // Sets a mip as cleared.
   void SetLevelCleared(TextureRef* ref, GLenum target,
                        GLint level, bool cleared);
diff --git a/gpu/command_buffer/service/texture_manager_unittest.cc b/gpu/command_buffer/service/texture_manager_unittest.cc
index 532e25f..ed25a7d 100644
--- a/gpu/command_buffer/service/texture_manager_unittest.cc
+++ b/gpu/command_buffer/service/texture_manager_unittest.cc
@@ -548,87 +548,33 @@
 TEST_F(TextureTest, ZeroSizeCanNotRender) {
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
   EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         1,
-                         1,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
   EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         0,
-                         0,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
   EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
 }
 
 TEST_F(TextureTest, EstimatedSize) {
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         8,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 8, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(8, 4));
   EXPECT_EQ(8u * 4u * 4u, texture_ref_->texture()->estimated_size());
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         2,
-                         GL_RGBA,
-                         8,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 2, GL_RGBA, 8, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(8, 4));
   EXPECT_EQ(8u * 4u * 4u * 2u, texture_ref_->texture()->estimated_size());
 }
 
 TEST_F(TextureMemoryTrackerTest, EstimatedSize) {
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
   EXPECT_MEMORY_ALLOCATION_CHANGE(0, 128, MemoryTracker::kUnmanaged);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         8,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 8, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(8, 4));
   EXPECT_MEMORY_ALLOCATION_CHANGE(128, 0, MemoryTracker::kUnmanaged);
   EXPECT_MEMORY_ALLOCATION_CHANGE(0, 256, MemoryTracker::kUnmanaged);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         2,
-                         GL_RGBA,
-                         8,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 2, GL_RGBA, 8, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(8, 4));
   // Add expectation for texture deletion.
   EXPECT_MEMORY_ALLOCATION_CHANGE(256, 0, MemoryTracker::kUnmanaged);
   EXPECT_MEMORY_ALLOCATION_CHANGE(0, 0, MemoryTracker::kUnmanaged);
@@ -637,17 +583,8 @@
 TEST_F(TextureMemoryTrackerTest, SetParameterPool) {
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
   EXPECT_MEMORY_ALLOCATION_CHANGE(0, 128, MemoryTracker::kUnmanaged);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         8,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 8, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(8, 4));
   EXPECT_MEMORY_ALLOCATION_CHANGE(128, 0, MemoryTracker::kUnmanaged);
   EXPECT_MEMORY_ALLOCATION_CHANGE(0, 128, MemoryTracker::kManaged);
   SetParameter(texture_ref_.get(),
@@ -665,21 +602,12 @@
   Texture* texture = texture_ref_->texture();
   EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
   // Check Setting level 0 to POT
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(4, 4));
   EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
   EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
   EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
-  EXPECT_EQ(0, texture->num_uncleared_mips());
+  EXPECT_TRUE(texture->SafeToRenderFrom());
   EXPECT_TRUE(manager_->HaveUnrenderableTextures());
   // Set filters to something that will work with a single mip.
   SetParameter(
@@ -700,34 +628,16 @@
   EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
   EXPECT_FALSE(manager_->HaveUnrenderableTextures());
   // Change a mip.
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 4, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(4, 4));
   EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
   EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
   EXPECT_TRUE(manager_->CanGenerateMipmaps(texture_ref_.get()));
   EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
   EXPECT_TRUE(manager_->HaveUnrenderableTextures());
   // Set a level past the number of mips that would get generated.
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         3,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 3, GL_RGBA, 4, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(4, 4));
   EXPECT_TRUE(manager_->CanGenerateMipmaps(texture_ref_.get()));
   // Make mips.
   EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture_ref_.get()));
@@ -739,17 +649,8 @@
 TEST_F(TextureMemoryTrackerTest, MarkMipmapsGenerated) {
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
   EXPECT_MEMORY_ALLOCATION_CHANGE(0, 64, MemoryTracker::kUnmanaged);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(4, 4));
   EXPECT_MEMORY_ALLOCATION_CHANGE(64, 0, MemoryTracker::kUnmanaged);
   EXPECT_MEMORY_ALLOCATION_CHANGE(0, 84, MemoryTracker::kUnmanaged);
   EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture_ref_.get()));
@@ -762,51 +663,24 @@
   Texture* texture = texture_ref_->texture();
   EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
   // Set level zero to large size.
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(4, 4));
   EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture_ref_.get()));
   EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
   EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
   EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
   EXPECT_FALSE(manager_->HaveUnrenderableTextures());
   // Set level zero to large smaller (levels unused mips)
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         2,
-                         2,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(2, 2));
   EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture_ref_.get()));
   EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
   EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
   EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
   EXPECT_FALSE(manager_->HaveUnrenderableTextures());
   // Set an unused level to some size
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         4,
-                         GL_RGBA,
-                         16,
-                         16,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 4, GL_RGBA, 16, 16,
+                         1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(16, 16));
   EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
   EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
   EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
@@ -818,17 +692,8 @@
   Texture* texture = texture_ref_->texture();
   EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
   // Check Setting level 0 to NPOT
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         4,
-                         5,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4, 5, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(4, 5));
   EXPECT_TRUE(TextureTestHelper::IsNPOT(texture));
   EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
   EXPECT_FALSE(manager_->CanGenerateMipmaps(texture_ref_.get()));
@@ -847,17 +712,8 @@
   EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
   EXPECT_FALSE(manager_->HaveUnrenderableTextures());
   // Change it to POT.
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(4, 4));
   EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
   EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
   EXPECT_TRUE(manager_->CanGenerateMipmaps(texture_ref_.get()));
@@ -884,8 +740,8 @@
   manager.SetTarget(texture_ref, GL_TEXTURE_2D);
   EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
   // Check Setting level 0 to NPOT
-  manager.SetLevelInfo(texture_ref,
-      GL_TEXTURE_2D, 0, GL_RGBA, 4, 5, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
+  manager.SetLevelInfo(texture_ref, GL_TEXTURE_2D, 0, GL_RGBA, 4, 5, 1, 0,
+                       GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(4, 5));
   EXPECT_TRUE(TextureTestHelper::IsNPOT(texture));
   EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
   EXPECT_TRUE(manager.CanGenerateMipmaps(texture_ref));
@@ -903,102 +759,54 @@
   Texture* texture = texture_ref_->texture();
   EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP), texture->target());
   // Check Setting level 0 each face to POT
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_CUBE_MAP_POSITIVE_X,
-                         0,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0,
+                         GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                         gfx::Rect(4, 4));
   EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
   EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
   EXPECT_FALSE(TextureTestHelper::IsCubeComplete(texture));
   EXPECT_FALSE(manager_->CanGenerateMipmaps(texture_ref_.get()));
   EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
   EXPECT_TRUE(manager_->HaveUnrenderableTextures());
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
-                         0,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0,
+                         GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                         gfx::Rect(4, 4));
   EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
   EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
   EXPECT_FALSE(TextureTestHelper::IsCubeComplete(texture));
   EXPECT_FALSE(manager_->CanGenerateMipmaps(texture_ref_.get()));
   EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
   EXPECT_TRUE(manager_->HaveUnrenderableTextures());
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
-                         0,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0,
+                         GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                         gfx::Rect(4, 4));
   EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
   EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
   EXPECT_FALSE(TextureTestHelper::IsCubeComplete(texture));
   EXPECT_FALSE(manager_->CanGenerateMipmaps(texture_ref_.get()));
   EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
   EXPECT_TRUE(manager_->HaveUnrenderableTextures());
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
-                         0,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0,
+                         GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                         gfx::Rect(4, 4));
   EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
   EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
   EXPECT_FALSE(TextureTestHelper::IsCubeComplete(texture));
   EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
   EXPECT_FALSE(manager_->CanGenerateMipmaps(texture_ref_.get()));
   EXPECT_TRUE(manager_->HaveUnrenderableTextures());
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
-                         0,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0,
+                         GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                         gfx::Rect(4, 4));
   EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
   EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
   EXPECT_FALSE(TextureTestHelper::IsCubeComplete(texture));
   EXPECT_FALSE(manager_->CanGenerateMipmaps(texture_ref_.get()));
   EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
   EXPECT_TRUE(manager_->HaveUnrenderableTextures());
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
-                         0,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0,
+                         GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                         gfx::Rect(4, 4));
   EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
   EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
   EXPECT_TRUE(TextureTestHelper::IsCubeComplete(texture));
@@ -1014,33 +822,17 @@
   EXPECT_FALSE(manager_->HaveUnrenderableTextures());
 
   // Change a mip.
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
-                         1,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 1,
+                         GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                         gfx::Rect(4, 4));
   EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
   EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
   EXPECT_TRUE(TextureTestHelper::IsCubeComplete(texture));
   EXPECT_TRUE(manager_->CanGenerateMipmaps(texture_ref_.get()));
   // Set a level past the number of mips that would get generated.
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
-                         3,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 3,
+                         GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                         gfx::Rect(4, 4));
   EXPECT_TRUE(manager_->CanGenerateMipmaps(texture_ref_.get()));
   // Make mips.
   EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture_ref_.get()));
@@ -1050,17 +842,8 @@
 
 TEST_F(TextureTest, GetLevelSize) {
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_3D);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_3D,
-                         1,
-                         GL_RGBA,
-                         4,
-                         5,
-                         6,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_3D, 1, GL_RGBA, 4, 5, 6,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(4, 5));
   GLsizei width = -1;
   GLsizei height = -1;
   GLsizei depth = -1;
@@ -1084,17 +867,8 @@
 
 TEST_F(TextureTest, GetLevelType) {
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         4,
-                         5,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 4, 5, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(4, 5));
   GLenum type = 0;
   GLenum format = 0;
   Texture* texture = texture_ref_->texture();
@@ -1112,17 +886,8 @@
 
 TEST_F(TextureTest, ValidForTexture) {
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         4,
-                         5,
-                         6,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 4, 5, 6,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(4, 5));
   // Check bad face.
   Texture* texture = texture_ref_->texture();
   EXPECT_FALSE(texture->ValidForTexture(
@@ -1190,8 +955,8 @@
   manager.SetTarget(texture_ref, GL_TEXTURE_2D);
   Texture* texture = texture_ref->texture();
   EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
-  manager.SetLevelInfo(texture_ref,
-      GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_FLOAT, true);
+  manager.SetLevelInfo(texture_ref, GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0,
+                       GL_RGBA, GL_FLOAT, gfx::Rect(1, 1));
   EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
   TestHelper::SetTexParameteriWithExpectations(
       gl_.get(), error_state_.get(), &manager,
@@ -1222,8 +987,8 @@
   manager.SetTarget(texture_ref, GL_TEXTURE_2D);
   Texture* texture = texture_ref->texture();
   EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
-  manager.SetLevelInfo(texture_ref,
-      GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_FLOAT, true);
+  manager.SetLevelInfo(texture_ref, GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0,
+                       GL_RGBA, GL_FLOAT, gfx::Rect(1, 1));
   EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
   manager.Destroy(false);
 }
@@ -1246,8 +1011,8 @@
   manager.SetTarget(texture_ref, GL_TEXTURE_2D);
   Texture* texture = texture_ref->texture();
   EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
-  manager.SetLevelInfo(texture_ref,
-      GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_HALF_FLOAT_OES, true);
+  manager.SetLevelInfo(texture_ref, GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0,
+                       GL_RGBA, GL_HALF_FLOAT_OES, gfx::Rect(1, 1));
   EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
   TestHelper::SetTexParameteriWithExpectations(
       gl_.get(), error_state_.get(), &manager,
@@ -1278,8 +1043,8 @@
   manager.SetTarget(texture_ref, GL_TEXTURE_2D);
   Texture* texture = texture_ref->texture();
   EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
-  manager.SetLevelInfo(texture_ref,
-      GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_HALF_FLOAT_OES, true);
+  manager.SetLevelInfo(texture_ref, GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0,
+                       GL_RGBA, GL_HALF_FLOAT_OES, gfx::Rect(1, 1));
   EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
   manager.Destroy(false);
 }
@@ -1322,9 +1087,8 @@
   TextureRef* texture_ref = manager.GetTexture(kClient1Id);
   ASSERT_TRUE(texture_ref != NULL);
   manager.SetTarget(texture_ref, GL_TEXTURE_2D);
-  manager.SetLevelInfo(
-      texture_ref, GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 4, 4, 1, 0,
-      GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, false);
+  manager.SetLevelInfo(texture_ref, GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 4, 4,
+                       1, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, gfx::Rect());
   EXPECT_FALSE(manager.CanGenerateMipmaps(texture_ref));
   manager.Destroy(false);
 }
@@ -1338,17 +1102,8 @@
   Texture* texture = texture_ref_->texture();
   EXPECT_EQ(0, texture->num_uncleared_mips());
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
   EXPECT_FALSE(texture->SafeToRenderFrom());
   EXPECT_TRUE(manager_->HaveUnsafeTextures());
   EXPECT_TRUE(manager_->HaveUnclearedMips());
@@ -1358,17 +1113,8 @@
   EXPECT_FALSE(manager_->HaveUnsafeTextures());
   EXPECT_FALSE(manager_->HaveUnclearedMips());
   EXPECT_EQ(0, texture->num_uncleared_mips());
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         8,
-                         8,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
   EXPECT_FALSE(texture->SafeToRenderFrom());
   EXPECT_TRUE(manager_->HaveUnsafeTextures());
   EXPECT_TRUE(manager_->HaveUnclearedMips());
@@ -1378,28 +1124,10 @@
   EXPECT_FALSE(manager_->HaveUnsafeTextures());
   EXPECT_FALSE(manager_->HaveUnclearedMips());
   EXPECT_EQ(0, texture->num_uncleared_mips());
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         8,
-                         8,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
   EXPECT_FALSE(texture->SafeToRenderFrom());
   EXPECT_TRUE(manager_->HaveUnsafeTextures());
   EXPECT_TRUE(manager_->HaveUnclearedMips());
@@ -1414,17 +1142,8 @@
   EXPECT_FALSE(manager_->HaveUnsafeTextures());
   EXPECT_FALSE(manager_->HaveUnclearedMips());
   EXPECT_EQ(0, texture->num_uncleared_mips());
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         8,
-                         8,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 8, 8, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
   EXPECT_FALSE(texture->SafeToRenderFrom());
   EXPECT_TRUE(manager_->HaveUnsafeTextures());
   EXPECT_TRUE(manager_->HaveUnclearedMips());
@@ -1444,31 +1163,13 @@
   EXPECT_FALSE(manager_->HaveUnclearedMips());
   Texture* texture2 = texture_ref2->texture();
   EXPECT_EQ(0, texture2->num_uncleared_mips());
-  manager_->SetLevelInfo(texture_ref2.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         8,
-                         8,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref2.get(), GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(8, 8));
   EXPECT_FALSE(manager_->HaveUnsafeTextures());
   EXPECT_FALSE(manager_->HaveUnclearedMips());
   EXPECT_EQ(0, texture2->num_uncleared_mips());
-  manager_->SetLevelInfo(texture_ref2.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         8,
-                         8,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref2.get(), GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
   EXPECT_TRUE(manager_->HaveUnsafeTextures());
   EXPECT_TRUE(manager_->HaveUnclearedMips());
   EXPECT_EQ(1, texture2->num_uncleared_mips());
@@ -1478,17 +1179,8 @@
       manager_->GetTexture(kClient3Id));
   ASSERT_TRUE(texture_ref3.get() != NULL);
   manager_->SetTarget(texture_ref3.get(), GL_TEXTURE_2D);
-  manager_->SetLevelInfo(texture_ref3.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         8,
-                         8,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref3.get(), GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(2, 2));
   EXPECT_TRUE(manager_->HaveUnsafeTextures());
   EXPECT_TRUE(manager_->HaveUnclearedMips());
   Texture* texture3 = texture_ref3->texture();
@@ -1502,28 +1194,10 @@
   EXPECT_FALSE(manager_->HaveUnclearedMips());
   EXPECT_EQ(0, texture3->num_uncleared_mips());
 
-  manager_->SetLevelInfo(texture_ref2.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         8,
-                         8,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
-  manager_->SetLevelInfo(texture_ref3.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         8,
-                         8,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref2.get(), GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(1, 1, 1, 1));
+  manager_->SetLevelInfo(texture_ref3.get(), GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(4, 4, 4, 4));
   EXPECT_TRUE(manager_->HaveUnsafeTextures());
   EXPECT_TRUE(manager_->HaveUnclearedMips());
   EXPECT_EQ(1, texture2->num_uncleared_mips());
@@ -1552,28 +1226,10 @@
   EXPECT_CALL(*decoder_, ClearLevel(_, _, _, _, _, _, _, _, _))
       .WillRepeatedly(Return(true));
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 4, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
   Texture* texture = texture_ref_->texture();
   EXPECT_FALSE(texture->SafeToRenderFrom());
   EXPECT_TRUE(manager_->HaveUnsafeTextures());
@@ -1584,28 +1240,10 @@
   EXPECT_FALSE(manager_->HaveUnsafeTextures());
   EXPECT_FALSE(manager_->HaveUnclearedMips());
   EXPECT_EQ(0, texture->num_uncleared_mips());
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         4,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(2, 2));
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 4, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(4, 3));
   EXPECT_FALSE(texture->SafeToRenderFrom());
   EXPECT_TRUE(manager_->HaveUnsafeTextures());
   EXPECT_TRUE(manager_->HaveUnclearedMips());
@@ -1629,17 +1267,8 @@
   static const GLuint kService2Id = 12;
   // Make the default texture renderable
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         1,
-                         1,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
   EXPECT_FALSE(manager_->HaveUnrenderableTextures());
   // Make a new texture
   manager_->CreateTexture(kClient2Id, kService2Id);
@@ -1653,17 +1282,8 @@
   EXPECT_FALSE(manager_->CanRender(texture_ref.get()));
   EXPECT_TRUE(manager_->HaveUnrenderableTextures());
   // Check that we can still manipulate it and it effects the manager.
-  manager_->SetLevelInfo(texture_ref.get(),
-                         GL_TEXTURE_2D,
-                         0,
-                         GL_RGBA,
-                         1,
-                         1,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref.get(), GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
   EXPECT_TRUE(manager_->CanRender(texture_ref.get()));
   EXPECT_FALSE(manager_->HaveUnrenderableTextures());
   EXPECT_CALL(*gl_, DeleteTextures(1, ::testing::Pointee(kService2Id)))
@@ -1674,17 +1294,8 @@
 
 TEST_F(TextureTest, GetLevelImage) {
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         2,
-                         2,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(2, 2));
   Texture* texture = texture_ref_->texture();
   EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 1) == NULL);
   // Set image.
@@ -1696,17 +1307,8 @@
   EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 1) == NULL);
   manager_->SetLevelImage(texture_ref_.get(), GL_TEXTURE_2D, 1, image.get());
   // Image should be reset when SetLevelInfo is called.
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         2,
-                         2,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(2, 2));
   EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 1) == NULL);
 }
 
@@ -1722,17 +1324,8 @@
 
 TEST_F(TextureTest, AddToSignature) {
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         2,
-                         2,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(2, 2));
   std::string signature1;
   std::string signature2;
   manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature1);
@@ -1741,140 +1334,59 @@
   EXPECT_FALSE(InSet(&string_set, signature1));
 
   // check changing 1 thing makes a different signature.
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         4,
-                         2,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 4, 2, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(4, 2));
   manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
   EXPECT_FALSE(InSet(&string_set, signature2));
 
   // check putting it back makes the same signature.
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         2,
-                         2,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(2, 2));
   signature2.clear();
   manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
   EXPECT_EQ(signature1, signature2);
 
   // Check setting cleared status does not change signature.
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         2,
-                         2,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
   signature2.clear();
   manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
   EXPECT_EQ(signature1, signature2);
 
   // Check changing other settings changes signature.
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         2,
-                         4,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 4, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
   signature2.clear();
   manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
   EXPECT_FALSE(InSet(&string_set, signature2));
 
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         2,
-                         2,
-                         2,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 2,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
   signature2.clear();
   manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
   EXPECT_FALSE(InSet(&string_set, signature2));
 
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         2,
-                         2,
-                         1,
-                         1,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1,
+                         1, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
   signature2.clear();
   manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
   EXPECT_FALSE(InSet(&string_set, signature2));
 
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         2,
-                         2,
-                         1,
-                         0,
-                         GL_RGB,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1,
+                         0, GL_RGB, GL_UNSIGNED_BYTE, gfx::Rect());
   signature2.clear();
   manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
   EXPECT_FALSE(InSet(&string_set, signature2));
 
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         2,
-                         2,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_FLOAT,
-                         false);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1,
+                         0, GL_RGBA, GL_FLOAT, gfx::Rect());
   signature2.clear();
   manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
   EXPECT_FALSE(InSet(&string_set, signature2));
 
   // put it back
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         GL_TEXTURE_2D,
-                         1,
-                         GL_RGBA,
-                         2,
-                         2,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         false);
+  manager_->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 2, 1,
+                         0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
   signature2.clear();
   manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
   EXPECT_EQ(signature1, signature2);
@@ -1958,7 +1470,7 @@
               GLsizei depth,
               GLint border,
               GLenum type,
-              bool cleared)
+              const gfx::Rect& cleared_rect)
         : target(target),
           format(format),
           width(width),
@@ -1966,7 +1478,7 @@
           depth(depth),
           border(border),
           type(type),
-          cleared(cleared) {}
+          cleared_rect(cleared_rect) {}
 
     LevelInfo()
         : target(0),
@@ -1975,14 +1487,13 @@
           height(-1),
           depth(1),
           border(0),
-          type(0),
-          cleared(false) {}
+          type(0) {}
 
     bool operator==(const LevelInfo& other) const {
       return target == other.target && format == other.format &&
              width == other.width && height == other.height &&
              depth == other.depth && border == other.border &&
-             type == other.type && cleared == other.cleared;
+             type == other.type && cleared_rect == other.cleared_rect;
     }
 
     GLenum target;
@@ -1992,23 +1503,15 @@
     GLsizei depth;
     GLint border;
     GLenum type;
-    bool cleared;
+    gfx::Rect cleared_rect;
   };
 
   void SetLevelInfo(TextureRef* texture_ref,
                     GLint level,
                     const LevelInfo& info) {
-    manager_->SetLevelInfo(texture_ref,
-                           info.target,
-                           level,
-                           info.format,
-                           info.width,
-                           info.height,
-                           info.depth,
-                           info.border,
-                           info.format,
-                           info.type,
-                           info.cleared);
+    manager_->SetLevelInfo(texture_ref, info.target, level, info.format,
+                           info.width, info.height, info.depth, info.border,
+                           info.format, info.type, info.cleared_rect);
   }
 
   static LevelInfo GetLevelInfo(const TextureRef* texture_ref,
@@ -2021,7 +1524,7 @@
                                       &info.height, &info.depth));
     EXPECT_TRUE(texture->GetLevelType(target, level, &info.type,
                                       &info.format));
-    info.cleared = texture->IsLevelCleared(target, level);
+    info.cleared_rect = texture->GetLevelClearedRect(target, level);
     return info;
   }
 
@@ -2049,8 +1552,8 @@
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
   Texture* texture = texture_ref_->texture();
   EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
-  LevelInfo level0(
-      GL_TEXTURE_2D, GL_RGBA, 4, 4, 1, 0, GL_UNSIGNED_BYTE, true);
+  LevelInfo level0(GL_TEXTURE_2D, GL_RGBA, 4, 4, 1, 0, GL_UNSIGNED_BYTE,
+                   gfx::Rect(4, 4));
   SetLevelInfo(texture_ref_.get(), 0, level0);
   EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture_ref_.get()));
   EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
@@ -2062,10 +1565,8 @@
   // Make this texture bigger with more levels, and make sure they get
   // clobbered correctly during Consume().
   manager_->SetTarget(texture2_.get(), GL_TEXTURE_2D);
-  SetLevelInfo(
-      texture2_.get(),
-      0,
-      LevelInfo(GL_TEXTURE_2D, GL_RGBA, 16, 16, 1, 0, GL_UNSIGNED_BYTE, false));
+  SetLevelInfo(texture2_.get(), 0, LevelInfo(GL_TEXTURE_2D, GL_RGBA, 16, 16, 1,
+                                             0, GL_UNSIGNED_BYTE, gfx::Rect()));
   EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture2_.get()));
   texture = texture2_->texture();
   EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
@@ -2093,8 +1594,8 @@
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_RECTANGLE_ARB);
   Texture* texture = texture_ref_->texture();
   EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_RECTANGLE_ARB), texture->target());
-  LevelInfo level0(
-      GL_TEXTURE_RECTANGLE_ARB, GL_RGBA, 1, 1, 1, 0, GL_UNSIGNED_BYTE, false);
+  LevelInfo level0(GL_TEXTURE_RECTANGLE_ARB, GL_RGBA, 1, 1, 1, 0,
+                   GL_UNSIGNED_BYTE, gfx::Rect());
   SetLevelInfo(texture_ref_.get(), 0, level0);
   EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
   Texture* produced_texture = Produce(texture_ref_.get());
@@ -2121,8 +1622,8 @@
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_EXTERNAL_OES);
   Texture* texture = texture_ref_->texture();
   EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), texture->target());
-  LevelInfo level0(
-      GL_TEXTURE_EXTERNAL_OES, GL_RGBA, 1, 1, 1, 0, GL_UNSIGNED_BYTE, false);
+  LevelInfo level0(GL_TEXTURE_EXTERNAL_OES, GL_RGBA, 1, 1, 1, 0,
+                   GL_UNSIGNED_BYTE, gfx::Rect());
   SetLevelInfo(texture_ref_.get(), 0, level0);
   EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
   Texture* produced_texture = Produce(texture_ref_.get());
@@ -2143,17 +1644,8 @@
   Texture* texture = texture_ref_->texture();
   EXPECT_EQ(static_cast<GLenum>(target), texture->target());
   scoped_refptr<gfx::GLImage> image(new gfx::GLImageStub);
-  manager_->SetLevelInfo(texture_ref_.get(),
-                         target,
-                         0,
-                         GL_RGBA,
-                         0,
-                         0,
-                         1,
-                         0,
-                         GL_RGBA,
-                         GL_UNSIGNED_BYTE,
-                         true);
+  manager_->SetLevelInfo(texture_ref_.get(), target, 0, GL_RGBA, 0, 0, 1, 0,
+                         GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
   manager_->SetLevelImage(texture_ref_.get(), target, 0, image.get());
   GLuint service_id = texture->service_id();
   Texture* produced_texture = Produce(texture_ref_.get());
@@ -2178,22 +1670,10 @@
   manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_CUBE_MAP);
   Texture* texture = texture_ref_->texture();
   EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP), texture->target());
-  LevelInfo face0(GL_TEXTURE_CUBE_MAP_POSITIVE_X,
-                  GL_RGBA,
-                  1,
-                  1,
-                  1,
-                  0,
-                  GL_UNSIGNED_BYTE,
-                  true);
-  LevelInfo face5(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
-                  GL_RGBA,
-                  3,
-                  3,
-                  1,
-                  0,
-                  GL_UNSIGNED_BYTE,
-                  true);
+  LevelInfo face0(GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_RGBA, 1, 1, 1, 0,
+                  GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
+  LevelInfo face5(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, GL_RGBA, 3, 3, 1, 0,
+                  GL_UNSIGNED_BYTE, gfx::Rect(1, 1));
   SetLevelInfo(texture_ref_.get(), 0, face0);
   SetLevelInfo(texture_ref_.get(), 0, face5);
   EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
@@ -2343,17 +1823,8 @@
   EXPECT_FALSE(texture_manager2_->HaveUnsafeTextures());
   EXPECT_FALSE(texture_manager2_->HaveUnclearedMips());
 
-  texture_manager1_->SetLevelInfo(ref1.get(),
-                                  GL_TEXTURE_2D,
-                                  0,
-                                  GL_RGBA,
-                                  1,
-                                  1,
-                                  1,
-                                  0,
-                                  GL_RGBA,
-                                  GL_UNSIGNED_BYTE,
-                                  false);
+  texture_manager1_->SetLevelInfo(ref1.get(), GL_TEXTURE_2D, 0, GL_RGBA, 1, 1,
+                                  1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
   EXPECT_FALSE(texture_manager1_->HaveUnrenderableTextures());
   EXPECT_TRUE(texture_manager1_->HaveUnsafeTextures());
   EXPECT_TRUE(texture_manager1_->HaveUnclearedMips());
@@ -2393,17 +1864,9 @@
 
   // Make FBO complete in manager 1.
   texture_manager1_->SetTarget(ref1.get(), GL_TEXTURE_2D);
-  texture_manager1_->SetLevelInfo(ref1.get(),
-                                  GL_TEXTURE_2D,
-                                  0,
-                                  GL_RGBA,
-                                  1,
-                                  1,
-                                  1,
-                                  0,
-                                  GL_RGBA,
-                                  GL_UNSIGNED_BYTE,
-                                  true);
+  texture_manager1_->SetLevelInfo(ref1.get(), GL_TEXTURE_2D, 0, GL_RGBA, 1, 1,
+                                  1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                                  gfx::Rect(1, 1));
   EXPECT_EQ(kCompleteValue, framebuffer1->IsPossiblyComplete());
   framebuffer_manager1.MarkAsComplete(framebuffer1.get());
   EXPECT_TRUE(framebuffer_manager1.IsComplete(framebuffer1.get()));
@@ -2422,17 +1885,9 @@
   EXPECT_TRUE(framebuffer_manager2.IsComplete(framebuffer2.get()));
 
   // Change level for texture, both FBOs should be marked incomplete
-  texture_manager1_->SetLevelInfo(ref1.get(),
-                                  GL_TEXTURE_2D,
-                                  0,
-                                  GL_RGBA,
-                                  1,
-                                  1,
-                                  1,
-                                  0,
-                                  GL_RGBA,
-                                  GL_UNSIGNED_BYTE,
-                                  true);
+  texture_manager1_->SetLevelInfo(ref1.get(), GL_TEXTURE_2D, 0, GL_RGBA, 1, 1,
+                                  1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                                  gfx::Rect(1, 1));
   EXPECT_FALSE(framebuffer_manager1.IsComplete(framebuffer1.get()));
   EXPECT_EQ(kCompleteValue, framebuffer1->IsPossiblyComplete());
   framebuffer_manager1.MarkAsComplete(framebuffer1.get());
@@ -2461,17 +1916,8 @@
   // Newly created texture is unrenderable.
   scoped_refptr<TextureRef> ref1 = texture_manager1_->CreateTexture(10, 10);
   texture_manager1_->SetTarget(ref1.get(), GL_TEXTURE_2D);
-  texture_manager1_->SetLevelInfo(ref1.get(),
-                                  GL_TEXTURE_2D,
-                                  0,
-                                  GL_RGBA,
-                                  10,
-                                  10,
-                                  1,
-                                  0,
-                                  GL_RGBA,
-                                  GL_UNSIGNED_BYTE,
-                                  false);
+  texture_manager1_->SetLevelInfo(ref1.get(), GL_TEXTURE_2D, 0, GL_RGBA, 10, 10,
+                                  1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
 
   EXPECT_LT(0u, ref1->texture()->estimated_size());
   EXPECT_EQ(initial_memory1 + ref1->texture()->estimated_size(),
@@ -2509,17 +1955,9 @@
       texture_manager2_->Consume(20, ref1->texture());
 
   texture_manager1_->SetTarget(ref1.get(), GL_TEXTURE_2D);
-  texture_manager1_->SetLevelInfo(ref1.get(),
-                                  GL_TEXTURE_2D,
-                                  1,
-                                  GL_RGBA,
-                                  2,
-                                  2,
-                                  1,
-                                  0,
-                                  GL_RGBA,
-                                  GL_UNSIGNED_BYTE,
-                                  true);
+  texture_manager1_->SetLevelInfo(ref1.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 2,
+                                  1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                                  gfx::Rect(2, 2));
   EXPECT_FALSE(ref1->texture()->HasImages());
   EXPECT_FALSE(ref2->texture()->HasImages());
   EXPECT_FALSE(texture_manager1_->HaveImages());
@@ -2536,17 +1974,9 @@
   EXPECT_TRUE(ref2->texture()->HasImages());
   EXPECT_TRUE(texture_manager1_->HaveImages());
   EXPECT_TRUE(texture_manager2_->HaveImages());
-  texture_manager1_->SetLevelInfo(ref1.get(),
-                                  GL_TEXTURE_2D,
-                                  1,
-                                  GL_RGBA,
-                                  2,
-                                  2,
-                                  1,
-                                  0,
-                                  GL_RGBA,
-                                  GL_UNSIGNED_BYTE,
-                                  true);
+  texture_manager1_->SetLevelInfo(ref1.get(), GL_TEXTURE_2D, 1, GL_RGBA, 2, 2,
+                                  1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                                  gfx::Rect(2, 2));
   EXPECT_FALSE(ref1->texture()->HasImages());
   EXPECT_FALSE(ref2->texture()->HasImages());
   EXPECT_FALSE(texture_manager1_->HaveImages());
diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc
index b13f601..191cca9 100644
--- a/gpu/config/gpu_driver_bug_list_json.cc
+++ b/gpu/config/gpu_driver_bug_list_json.cc
@@ -19,7 +19,7 @@
 {
   "name": "gpu driver bug list",
   // Please update the version number whenever you change this file.
-  "version": "8.08",
+  "version": "8.10",
   "entries": [
     {
       "id": 1,
@@ -1395,6 +1395,35 @@
       "features": [
         "disable_blend_equation_advanced"
       ]
+    },
+    {
+      "id": 118,
+      "cr_bugs": [477306],
+      "description": "NVIDIA 331 series drivers shader compiler may crash when attempting to optimize pow()",
+      "os": {
+        "type": "linux"
+      },
+      "driver_version": {
+        "op": "<=",
+        "value": "331"
+      },
+      "vendor_id": "0x10de",
+      "features": [
+        "remove_pow_with_constant_exponent"
+      ]
+    },
+    {
+      "id": 119,
+      "description": "Context lost recovery often fails on Mali-400 on Android.",
+      "cr_bugs": [496438],
+      "os": {
+        "type": "android"
+      },
+      "gl_vendor": "ARM.*",
+      "gl_renderer": ".*Mali-400.*",
+      "features": [
+        "exit_on_context_lost"
+      ]
     }
   ]
 }
diff --git a/gpu/config/gpu_driver_bug_workaround_type.h b/gpu/config/gpu_driver_bug_workaround_type.h
index 83e143d20..015aea3 100644
--- a/gpu/config/gpu_driver_bug_workaround_type.h
+++ b/gpu/config/gpu_driver_bug_workaround_type.h
@@ -94,6 +94,8 @@
          needs_offscreen_buffer_workaround)                  \
   GPU_OP(REGENERATE_STRUCT_NAMES,                            \
          regenerate_struct_names)                            \
+  GPU_OP(REMOVE_POW_WITH_CONSTANT_EXPONENT,                  \
+         remove_pow_with_constant_exponent)                  \
   GPU_OP(RESTORE_SCISSOR_ON_FBO_CHANGE,                      \
          restore_scissor_on_fbo_change)                      \
   GPU_OP(REVERSE_POINT_SPRITE_COORD_ORIGIN,                  \
diff --git a/gpu/config/gpu_info_collector_android.cc b/gpu/config/gpu_info_collector_android.cc
index 97a79e5..d05e85b 100644
--- a/gpu/config/gpu_info_collector_android.cc
+++ b/gpu/config/gpu_info_collector_android.cc
@@ -18,10 +18,13 @@
 namespace {
 
 std::string GetDriverVersionFromString(const std::string& version_string) {
-  // Extract driver version from the second number in a string like:
-  // "OpenGL ES 2.0 V@6.0 AU@ (CL@2946718)"
-
-  // Exclude first "2.0".
+  // We expect that android GL_VERSION strings will be of a form
+  // similar to: "OpenGL ES 2.0 V@6.0 AU@ (CL@2946718)" where the
+  // first match to [0-9][0-9.]* is the OpenGL ES version number, and
+  // the second match to [0-9][0-9.]* is the driver version (in this
+  // case, 6.0).
+  // It is currently assumed that the driver version has at least one
+  // period in it, and only the first two components are significant.
   size_t begin = version_string.find_first_of("0123456789");
   if (begin == std::string::npos)
     return "0";
diff --git a/gpu/config/gpu_info_collector_unittest.cc b/gpu/config/gpu_info_collector_unittest.cc
index 359461ad..f89eb4d 100644
--- a/gpu/config/gpu_info_collector_unittest.cc
+++ b/gpu/config/gpu_info_collector_unittest.cc
@@ -151,5 +151,76 @@
   EXPECT_EQ(test_values_.gl_extensions, gpu_info.gl_extensions);
 }
 
+class CollectDriverInfoGLTest : public testing::Test {
+ public:
+  CollectDriverInfoGLTest() {}
+  ~CollectDriverInfoGLTest() override {}
+
+  void SetUp() override {}
+  void TearDown() override {}
+};
+
+TEST_F(CollectDriverInfoGLTest, CollectDriverInfoGL) {
+  const struct {
+    const char* gl_renderer;
+    const char* gl_vendor;
+    const char* gl_version;
+    const char* expected_driver_version;
+  } kTestStrings[] = {
+#if defined(OS_ANDROID)
+    {"Adreno (TM) 320",
+     "Qualcomm",
+     "OpenGL ES 2.0 V@14.0 AU@04.02 (CL@3206)",
+     "14.0"},
+    {"Adreno (TM) 420", "Qualcomm", "OpenGL ES 3.0 V@84.0 AU@ (CL@)", "84.0"},
+    {"PowerVR Rogue G6430",
+     "Imagination Technologies",
+     "OpenGL ES 3.1 build 1.4@3283119",
+     "1.4"},
+    {"Mali-T604", "ARM", "OpenGL ES 3.1", "0"},
+    {"NVIDIA Tegra",
+     "NVIDIA Corporation",
+     "OpenGL ES 3.1 NVIDIA 343.00",
+     "343.00"},
+    {"NVIDIA Tegra 3",
+     "NVIDIA Corporation",
+     "OpenGL ES 2.0 14.01003",
+     "14.01003"},
+    {"random GPU",
+     "random vendor",
+     "OpenGL ES 2.0 with_long_version_string=1.2.3.4",
+     "1.2"},
+    {"random GPU",
+     "random vendor",
+     "OpenGL ES 2.0 with_short_version_string=1",
+     "0"},
+    {"random GPU",
+     "random vendor",
+     "OpenGL ES 2.0 with_no_version_string",
+     "0"},
+#elif defined(OS_MACOSX)
+    {"Intel Iris Pro OpenGL Engine",
+     "Intel Inc.",
+     "2.1 INTEL-10.6.20",
+     "10.6.20"},
+#elif defined(OS_LINUX)
+    {"Quadro K2000/PCIe/SSE2",
+     "NVIDIA Corporation",
+     "4.4.0 NVIDIA 331.79",
+     "331.79"},
+#endif
+    {NULL, NULL, NULL, NULL}
+  };
+
+  GPUInfo gpu_info;
+  for (int i = 0; kTestStrings[i].gl_renderer != NULL; ++i) {
+    gpu_info.gl_renderer = kTestStrings[i].gl_renderer;
+    gpu_info.gl_vendor = kTestStrings[i].gl_vendor;
+    gpu_info.gl_version = kTestStrings[i].gl_version;
+    EXPECT_EQ(CollectDriverInfoGL(&gpu_info), kCollectInfoSuccess);
+    EXPECT_EQ(gpu_info.driver_version, kTestStrings[i].expected_driver_version);
+  }
+}
+
 }  // namespace gpu
 
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg
index 4d8dff3..b9dc50e 100644
--- a/infra/config/cq.cfg
+++ b/infra/config/cq.cfg
@@ -92,6 +92,10 @@
         name: "win8_chromium_ng"
         experiment_percentage: 0.1
       }
+      builders {
+        name: "win_chromium_compile_dbg_ng_exp"
+        experiment_percentage: 0.1
+      }
       builders { name: "win8_chromium_rel" }
       builders { name: "win_chromium_compile_dbg_ng" }
       builders { name: "win_chromium_rel_ng" }
diff --git a/ios/build/grit_whitelist.txt b/ios/build/grit_whitelist.txt
deleted file mode 100644
index b1ba0ed..0000000
--- a/ios/build/grit_whitelist.txt
+++ /dev/null
@@ -1 +0,0 @@
-IDR_INFOBAR_TRANSLATE_IOS
diff --git a/ios/chrome/browser/autofill/OWNERS b/ios/chrome/browser/autofill/OWNERS
index 5d88be5..634a146c 100644
--- a/ios/chrome/browser/autofill/OWNERS
+++ b/ios/chrome/browser/autofill/OWNERS
@@ -1,2 +1,2 @@
-dconnelly@chromium.org
+bondd@chromium.org
 jdonnelly@chromium.org
diff --git a/ios/chrome/browser/enhanced_bookmarks/bookmark_server_cluster_service_factory.cc b/ios/chrome/browser/enhanced_bookmarks/bookmark_server_cluster_service_factory.cc
index 2202d68..8dff4eb6 100644
--- a/ios/chrome/browser/enhanced_bookmarks/bookmark_server_cluster_service_factory.cc
+++ b/ios/chrome/browser/enhanced_bookmarks/bookmark_server_cluster_service_factory.cc
@@ -11,6 +11,7 @@
 #include "components/signin/core/browser/signin_manager.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/browser_state_otr_helper.h"
+#include "ios/chrome/browser/enhanced_bookmarks/enhanced_bookmark_model_factory.h"
 #include "ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/public/provider/chrome/browser/keyed_service_provider.h"
@@ -39,7 +40,7 @@
       ios::GetChromeBrowserProvider()->GetKeyedServiceProvider();
   DependsOn(provider->GetProfileOAuth2TokenServiceFactory());
   DependsOn(provider->GetSigninManagerFactory());
-  DependsOn(provider->GetEnhancedBookmarkModelFactory());
+  DependsOn(EnhancedBookmarkModelFactory::GetInstance());
   DependsOn(provider->GetSyncServiceFactory());
 }
 
@@ -58,7 +59,7 @@
       browser_state->GetRequestContext(),
       provider->GetProfileOAuth2TokenServiceForBrowserState(browser_state),
       provider->GetSigninManagerForBrowserState(browser_state),
-      provider->GetEnhancedBookmarkModelForBrowserState(browser_state),
+      EnhancedBookmarkModelFactory::GetForBrowserState(browser_state),
       provider->GetSyncServiceForBrowserState(browser_state),
       browser_state->GetPrefs());
 }
diff --git a/ios/chrome/browser/enhanced_bookmarks/bookmark_server_cluster_service_factory.h b/ios/chrome/browser/enhanced_bookmarks/bookmark_server_cluster_service_factory.h
index ac83c41..5ff0873 100644
--- a/ios/chrome/browser/enhanced_bookmarks/bookmark_server_cluster_service_factory.h
+++ b/ios/chrome/browser/enhanced_bookmarks/bookmark_server_cluster_service_factory.h
@@ -34,6 +34,7 @@
   BookmarkServerClusterServiceFactory();
   ~BookmarkServerClusterServiceFactory() override;
 
+  // BrowserStateKeyedServiceFactory implementation.
   KeyedService* BuildServiceInstanceFor(
       web::BrowserState* context) const override;
   web::BrowserState* GetBrowserStateToUse(
@@ -42,6 +43,6 @@
   DISALLOW_COPY_AND_ASSIGN(BookmarkServerClusterServiceFactory);
 };
 
-}  // namespace enhanced_bookmarsk
+}  // namespace enhanced_bookmarks
 
 #endif  // IOS_CHROME_BROWSER_ENHANCED_BOOKMARKS_BOOKMARK_SERVER_CLUSTER_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/enhanced_bookmarks/enhanced_bookmark_model_factory.cc b/ios/chrome/browser/enhanced_bookmarks/enhanced_bookmark_model_factory.cc
new file mode 100644
index 0000000..80b1e801
--- /dev/null
+++ b/ios/chrome/browser/enhanced_bookmarks/enhanced_bookmark_model_factory.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 "ios/chrome/browser/enhanced_bookmarks/enhanced_bookmark_model_factory.h"
+
+#include "base/memory/singleton.h"
+#include "components/enhanced_bookmarks/enhanced_bookmark_model.h"
+#include "components/keyed_service/ios/browser_state_dependency_manager.h"
+#include "ios/chrome/browser/browser_state/browser_state_otr_helper.h"
+#include "ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
+#include "ios/public/provider/chrome/browser/keyed_service_provider.h"
+
+namespace {
+const char kVersionPrefix[] = "chrome.";
+}
+
+namespace enhanced_bookmarks {
+
+// static
+EnhancedBookmarkModelFactory* EnhancedBookmarkModelFactory::GetInstance() {
+  return Singleton<EnhancedBookmarkModelFactory>::get();
+}
+
+// static
+EnhancedBookmarkModel* EnhancedBookmarkModelFactory::GetForBrowserState(
+    ios::ChromeBrowserState* browser_state) {
+  return static_cast<EnhancedBookmarkModel*>(
+      GetInstance()->GetServiceForBrowserState(browser_state, true));
+}
+
+EnhancedBookmarkModelFactory::EnhancedBookmarkModelFactory()
+    : BrowserStateKeyedServiceFactory(
+          "EnhancedBookmarkModel",
+          BrowserStateDependencyManager::GetInstance()) {
+  ios::KeyedServiceProvider* provider =
+      ios::GetChromeBrowserProvider()->GetKeyedServiceProvider();
+  DependsOn(provider->GetBookmarkModelFactory());
+}
+
+EnhancedBookmarkModelFactory::~EnhancedBookmarkModelFactory() {
+}
+
+KeyedService* EnhancedBookmarkModelFactory::BuildServiceInstanceFor(
+    web::BrowserState* context) const {
+  DCHECK(!context->IsOffTheRecord());
+  ios::ChromeBrowserState* browser_state =
+      ios::ChromeBrowserState::FromBrowserState(context);
+  ios::KeyedServiceProvider* provider =
+      ios::GetChromeBrowserProvider()->GetKeyedServiceProvider();
+  return new EnhancedBookmarkModel(
+      provider->GetBookmarkModelForBrowserState(browser_state),
+      ios::GetChromeBrowserProvider()->GetProductVersionWithPrefix(
+          kVersionPrefix));
+}
+
+web::BrowserState* EnhancedBookmarkModelFactory::GetBrowserStateToUse(
+    web::BrowserState* context) const {
+  return GetBrowserStateRedirectedInIncognito(context);
+}
+
+}  // namespace enhanced_bookmarks
diff --git a/ios/chrome/browser/enhanced_bookmarks/enhanced_bookmark_model_factory.h b/ios/chrome/browser/enhanced_bookmarks/enhanced_bookmark_model_factory.h
new file mode 100644
index 0000000..9c47b97
--- /dev/null
+++ b/ios/chrome/browser/enhanced_bookmarks/enhanced_bookmark_model_factory.h
@@ -0,0 +1,47 @@
+// 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_BROWSER_ENHANCED_BOOKMARKS_ENHANCED_BOOKMARK_MODEL_FACTORY_H_
+#define IOS_CHROME_BROWSER_ENHANCED_BOOKMARKS_ENHANCED_BOOKMARK_MODEL_FACTORY_H_
+
+#include "base/macros.h"
+#include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+
+template <typename T>
+struct DefaultSingletonTraits;
+
+namespace ios {
+class ChromeBrowserState;
+}
+
+namespace enhanced_bookmarks {
+
+class EnhancedBookmarkModel;
+
+// A factory to create BookmarkServerClusterService and associate them to
+// ios::ChromeBrowserState.
+class EnhancedBookmarkModelFactory : public BrowserStateKeyedServiceFactory {
+ public:
+  static EnhancedBookmarkModelFactory* GetInstance();
+  static EnhancedBookmarkModel* GetForBrowserState(
+      ios::ChromeBrowserState* browser_state);
+
+ private:
+  friend struct DefaultSingletonTraits<EnhancedBookmarkModelFactory>;
+
+  EnhancedBookmarkModelFactory();
+  ~EnhancedBookmarkModelFactory() override;
+
+  // BrowserStateKeyedServiceFactory implementation.
+  KeyedService* BuildServiceInstanceFor(
+      web::BrowserState* context) const override;
+  web::BrowserState* GetBrowserStateToUse(
+      web::BrowserState* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(EnhancedBookmarkModelFactory);
+};
+
+}  // namespace enhanced_bookmarks
+
+#endif  // IOS_CHROME_BROWSER_ENHANCED_BOOKMARKS_ENHANCED_BOOKMARK_MODEL_FACTORY_H_
diff --git a/ios/chrome/browser/experimental_flags.h b/ios/chrome/browser/experimental_flags.h
index 7c26855..c30efc6 100644
--- a/ios/chrome/browser/experimental_flags.h
+++ b/ios/chrome/browser/experimental_flags.h
@@ -15,6 +15,12 @@
 // Whether background crash report upload should generate a local notification.
 bool IsAlertOnBackgroundUploadEnabled();
 
+// Whether the new bookmark collection experience is enabled.
+bool IsBookmarkCollectionEnabled();
+
+// Whether to extract salient images from pages at load time if bookmarked.
+bool IsBookmarkImageFetchingOnVisitEnabled();
+
 // Whether the app uses WKWebView instead of UIWebView.
 bool IsWKWebViewEnabled();
 
diff --git a/ios/chrome/browser/experimental_flags.mm b/ios/chrome/browser/experimental_flags.mm
index dbd79fd..6659c60 100644
--- a/ios/chrome/browser/experimental_flags.mm
+++ b/ios/chrome/browser/experimental_flags.mm
@@ -7,6 +7,8 @@
 
 #include "ios/chrome/browser/experimental_flags.h"
 
+#import <Foundation/Foundation.h>
+
 #include <string>
 
 #include "base/command_line.h"
@@ -15,11 +17,14 @@
 #include "base/strings/string_util.h"
 #include "components/variations/variations_associated_data.h"
 #include "ios/chrome/browser/chrome_switches.h"
+#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/web/public/web_view_util.h"
 
 namespace {
 NSString* const kEnableAlertOnBackgroundUpload =
     @"EnableAlertsOnBackgroundUpload";
+NSString* const kEnableBookmarkRefreshImageOnEachVisit =
+    @"EnableBookmarkRefreshImageOnEachVisit";
 }  // namespace
 
 namespace experimental_flags {
@@ -29,6 +34,24 @@
       boolForKey:kEnableAlertOnBackgroundUpload];
 }
 
+bool IsBookmarkCollectionEnabled() {
+  return ios::GetChromeBrowserProvider()->IsBookmarkCollectionEnabled();
+}
+
+bool IsBookmarkImageFetchingOnVisitEnabled() {
+  if (!IsBookmarkCollectionEnabled())
+    return false;
+
+  NSUserDefaults* user_defaults = [NSUserDefaults standardUserDefaults];
+  if ([user_defaults boolForKey:kEnableBookmarkRefreshImageOnEachVisit])
+    return true;
+
+  const char kFieldTrialName[] = "EnhancedBookmarks";
+  std::string enable_fetching = variations::GetVariationParamValue(
+      kFieldTrialName, "EnableImagesFetchingOnVisit");
+  return !enable_fetching.empty();
+}
+
 bool IsWKWebViewEnabled() {
   // If WKWebView isn't supported, don't activate the experiment at all. This
   // avoids someone being slotted into the WKWebView bucket (and thus reporting
diff --git a/ios/chrome/browser/infobars/infobar_manager_impl.cc b/ios/chrome/browser/infobars/infobar_manager_impl.cc
index a3ed407..55eecccd 100644
--- a/ios/chrome/browser/infobars/infobar_manager_impl.cc
+++ b/ios/chrome/browser/infobars/infobar_manager_impl.cc
@@ -21,18 +21,14 @@
 infobars::InfoBarDelegate::NavigationDetails
 NavigationDetailsFromLoadCommittedDetails(
     const web::LoadCommittedDetails& load_details) {
-  const ui::PageTransition transition = load_details.item->GetTransitionType();
   infobars::InfoBarDelegate::NavigationDetails navigation_details;
-  navigation_details.is_main_frame = ui::PageTransitionIsMainFrame(transition);
-  navigation_details.is_redirect = ui::PageTransitionIsRedirect(transition);
-  navigation_details.is_reload =
-      ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD);
-
-  // web::LoadCommittedDetails don't store this information, default to false.
-  navigation_details.did_replace_entry = false;
   navigation_details.entry_id = load_details.item->GetUniqueID();
+  const ui::PageTransition transition = load_details.item->GetTransitionType();
   navigation_details.is_navigation_to_different_page =
-      navigation_details.is_main_frame && !load_details.is_in_page;
+      ui::PageTransitionIsMainFrame(transition) && !load_details.is_in_page;
+  // web::LoadCommittedDetails doesn't store this information, default to false.
+  navigation_details.did_replace_entry = false;
+  navigation_details.is_redirect = ui::PageTransitionIsRedirect(transition);
 
   return navigation_details;
 }
diff --git a/ios/chrome/browser/net/retryable_url_fetcher_unittest.mm b/ios/chrome/browser/net/retryable_url_fetcher_unittest.mm
index 6f73234..9c8f48b1 100644
--- a/ios/chrome/browser/net/retryable_url_fetcher_unittest.mm
+++ b/ios/chrome/browser/net/retryable_url_fetcher_unittest.mm
@@ -60,7 +60,7 @@
 
 TEST_F(RetryableURLFetcherTest, TestResponse200) {
   scoped_refptr<net::URLRequestContextGetter> request_context_getter =
-      new net::TestURLRequestContextGetter(message_loop_.message_loop_proxy());
+      new net::TestURLRequestContextGetter(message_loop_.task_runner());
   base::scoped_nsobject<RetryableURLFetcher> retryableFetcher(
       [[RetryableURLFetcher alloc]
           initWithRequestContextGetter:request_context_getter.get()
@@ -81,7 +81,7 @@
 
 TEST_F(RetryableURLFetcherTest, TestResponse404) {
   scoped_refptr<net::URLRequestContextGetter> request_context_getter =
-      new net::TestURLRequestContextGetter(message_loop_.message_loop_proxy());
+      new net::TestURLRequestContextGetter(message_loop_.task_runner());
   base::scoped_nsobject<RetryableURLFetcher> retryableFetcher(
       [[RetryableURLFetcher alloc]
           initWithRequestContextGetter:request_context_getter.get()
diff --git a/ios/chrome/browser/snapshots/snapshot_cache.mm b/ios/chrome/browser/snapshots/snapshot_cache.mm
index 2ba98177..c33bfe9 100644
--- a/ios/chrome/browser/snapshots/snapshot_cache.mm
+++ b/ios/chrome/browser/snapshots/snapshot_cache.mm
@@ -212,8 +212,8 @@
   }
 
   base::PostTaskAndReplyWithResult(
-      web::WebThread::GetMessageLoopProxyForThread(
-          web::WebThread::FILE_USER_BLOCKING).get(),
+      web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE_USER_BLOCKING)
+          .get(),
       FROM_HERE, base::BindBlock(^base::scoped_nsobject<UIImage>() {
         // Retrieve the image on a high priority thread.
         return base::scoped_nsobject<UIImage>([ReadImageFromDisk(
@@ -401,10 +401,9 @@
   // already in the cache, use it.
   UIImage* img = [imageDictionary_ objectForKey:sessionID];
   base::PostTaskAndReplyWithResult(
-      web::WebThread::GetMessageLoopProxyForThread(
-          web::WebThread::FILE_USER_BLOCKING).get(),
-      FROM_HERE,
-      base::BindBlock(^base::scoped_nsobject<UIImage>() {
+      web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE_USER_BLOCKING)
+          .get(),
+      FROM_HERE, base::BindBlock(^base::scoped_nsobject<UIImage>() {
         base::scoped_nsobject<UIImage> result([img retain]);
         // If the image is not in the cache, load it from disk.
         if (!result)
@@ -465,10 +464,9 @@
   }
 
   base::PostTaskAndReplyWithResult(
-      web::WebThread::GetMessageLoopProxyForThread(
-          web::WebThread::FILE_USER_BLOCKING).get(),
-      FROM_HERE,
-      base::BindBlock(^base::scoped_nsobject<UIImage>() {
+      web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE_USER_BLOCKING)
+          .get(),
+      FROM_HERE, base::BindBlock(^base::scoped_nsobject<UIImage>() {
         // Retrieve the image on a high priority thread.
         // Loading the file into NSData is more reliable.
         // -imageWithContentsOfFile would ocassionally claim the image was not a
diff --git a/ios/chrome/ios_chrome.gyp b/ios/chrome/ios_chrome.gyp
index 897d12e5..79cada922 100644
--- a/ios/chrome/ios_chrome.gyp
+++ b/ios/chrome/ios_chrome.gyp
@@ -137,6 +137,8 @@
         'browser/dom_distiller/dom_distiller_service_factory.h',
         'browser/enhanced_bookmarks/bookmark_server_cluster_service_factory.cc',
         'browser/enhanced_bookmarks/bookmark_server_cluster_service_factory.h',
+        'browser/enhanced_bookmarks/enhanced_bookmark_model_factory.cc',
+        'browser/enhanced_bookmarks/enhanced_bookmark_model_factory.h',
         'browser/experimental_flags.h',
         'browser/experimental_flags.mm',
         'browser/file_metadata_util.h',
diff --git a/ios/chrome/ios_chrome_resources.gyp b/ios/chrome/ios_chrome_resources.gyp
index 5e99526d..fa003623 100644
--- a/ios/chrome/ios_chrome_resources.gyp
+++ b/ios/chrome/ios_chrome_resources.gyp
@@ -52,8 +52,7 @@
         {
           'action_name': 'ios_theme_resources',
           'variables': {
-            # TODO(lliabraa): Remove this whitelist.
-            'grit_whitelist': '<(DEPTH)/ios/build/grit_whitelist.txt',
+            'grit_whitelist': '',
             'grit_grd_file': 'app/theme/ios_theme_resources.grd',
           },
           'includes': [ '../../build/grit_action.gypi' ],
@@ -71,6 +70,93 @@
         ],
       },
     },
+    {
+      'target_name': 'ios_packed_resources',
+      'type': 'none',
+      'dependencies': [
+        '../../components/components_strings.gyp:components_strings',
+        '../../net/net.gyp:net_resources',
+        '../../ui/resources/ui_resources.gyp:ui_resources',
+        '../../ui/strings/ui_strings.gyp:ui_strings',
+        'ios_chrome_resources',
+      ],
+      'actions': [
+        {
+          'action_name': 'repack_ios_locales',
+          'variables': {
+            'repack_locales_path': 'tools/build/ios_repack_locales.py',
+          },
+          'inputs': [
+            'tools/build/ios_repack_locales.py',
+            '<!@pymod_do_main(ios_repack_locales -i '
+              '-s <(SHARED_INTERMEDIATE_DIR) '
+              '-x <(SHARED_INTERMEDIATE_DIR)/repack_ios '
+              '<(locales))'
+          ],
+          'outputs': [
+            '<!@pymod_do_main(ios_repack_locales -o '
+              '-s <(SHARED_INTERMEDIATE_DIR) '
+              '-x <(SHARED_INTERMEDIATE_DIR)/repack_ios '
+              '<(locales))'
+          ],
+          'action': [
+            'python',
+            'tools/build/ios_repack_locales.py',
+            '-x', '<(SHARED_INTERMEDIATE_DIR)/repack_ios',
+            '-s', '<(SHARED_INTERMEDIATE_DIR)',
+            '<@(locales)',
+          ],
+        },
+        {
+          'action_name': 'repack_ios_resources_100_percent',
+          'variables': {
+            'pak_inputs': [
+              '<(SHARED_INTERMEDIATE_DIR)/components/components_resources_100_percent.pak',
+              '<(SHARED_INTERMEDIATE_DIR)/ios/chrome/ios_theme_resources_100_percent.pak',
+              '<(SHARED_INTERMEDIATE_DIR)/ui/resources/ui_resources_100_percent.pak',
+            ],
+            'pak_output': '<(SHARED_INTERMEDIATE_DIR)/repack_ios/chrome_100_percent.pak',
+          },
+          'includes': [ '../../build/repack_action.gypi' ],
+        },
+        {
+          'action_name': 'repack_ios_resources_200_percent',
+          'variables': {
+            'pak_inputs': [
+              '<(SHARED_INTERMEDIATE_DIR)/components/components_resources_200_percent.pak',
+              '<(SHARED_INTERMEDIATE_DIR)/ios/chrome/ios_theme_resources_200_percent.pak',
+              '<(SHARED_INTERMEDIATE_DIR)/ui/resources/ui_resources_200_percent.pak',
+            ],
+            'pak_output': '<(SHARED_INTERMEDIATE_DIR)/repack_ios/chrome_200_percent.pak',
+          },
+          'includes': [ '../../build/repack_action.gypi' ],
+        },
+        {
+          'action_name': 'repack_ios_resources_300_percent',
+          'variables': {
+            'pak_inputs': [
+              '<(SHARED_INTERMEDIATE_DIR)/components/components_resources_300_percent.pak',
+              '<(SHARED_INTERMEDIATE_DIR)/ios/chrome/ios_theme_resources_300_percent.pak',
+              '<(SHARED_INTERMEDIATE_DIR)/ui/resources/ui_resources_300_percent.pak',
+            ],
+            'pak_output': '<(SHARED_INTERMEDIATE_DIR)/repack_ios/chrome_300_percent.pak',
+          },
+          'includes': [ '../../build/repack_action.gypi' ],
+        },
+        {
+          'action_name': 'repack_ios_resources',
+          'variables': {
+            'pak_inputs': [
+              '<(SHARED_INTERMEDIATE_DIR)/components/components_resources.pak',
+              '<(SHARED_INTERMEDIATE_DIR)/net/net_resources.pak',
+              '<(SHARED_INTERMEDIATE_DIR)/ui/resources/webui_resources.pak',
+            ],
+            'pak_output': '<(SHARED_INTERMEDIATE_DIR)/repack_ios/resources.pak',
+          },
+          'includes': [ '../../build/repack_action.gypi' ],
+        },
+      ],
+    },
   ],
 }
 
diff --git a/ios/chrome/ios_chrome_resources_bundle.gypi b/ios/chrome/ios_chrome_resources_bundle.gypi
new file mode 100644
index 0000000..f37a61a6
--- /dev/null
+++ b/ios/chrome/ios_chrome_resources_bundle.gypi
@@ -0,0 +1,16 @@
+# 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.
+{
+  'dependencies': [
+    '<(DEPTH)/ios/chrome/ios_chrome_resources.gyp:ios_packed_resources',
+  ],
+  'mac_bundle_resources': [
+    '<(SHARED_INTERMEDIATE_DIR)/repack_ios/chrome_100_percent.pak',
+    '<(SHARED_INTERMEDIATE_DIR)/repack_ios/chrome_200_percent.pak',
+    '<(SHARED_INTERMEDIATE_DIR)/repack_ios/chrome_300_percent.pak',
+    '<(SHARED_INTERMEDIATE_DIR)/repack_ios/resources.pak',
+    '<!@pymod_do_main(ios_repack_locales -o -s <(SHARED_INTERMEDIATE_DIR) '
+      '-x <(SHARED_INTERMEDIATE_DIR)/repack_ios <(locales))',
+  ],
+}
diff --git a/ios/chrome/ios_chrome_tests.gyp b/ios/chrome/ios_chrome_tests.gyp
index 55597fc..d6bb2ed 100644
--- a/ios/chrome/ios_chrome_tests.gyp
+++ b/ios/chrome/ios_chrome_tests.gyp
@@ -45,6 +45,7 @@
         'browser/ui/uikit_ui_util_unittest.mm',
         'common/string_util_unittest.mm',
       ],
+      'includes': ['ios_chrome_resources_bundle.gypi'],
     },
     {
       'target_name': 'ios_chrome_test_support',
diff --git a/ios/chrome/tools/build/ios_repack_locales.py b/ios/chrome/tools/build/ios_repack_locales.py
new file mode 100755
index 0000000..4801f064
--- /dev/null
+++ b/ios/chrome/tools/build/ios_repack_locales.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+# 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.
+
+"""Helper script to repack paks for a list of locales for iOS.
+
+Gyp doesn't have any built-in looping capability, so this just provides a way to
+loop over a list of locales when repacking pak files, thus avoiding a
+proliferation of mostly duplicate, cut-n-paste gyp actions.
+"""
+
+import optparse
+import os
+import sys
+
+script_dir = os.path.dirname(__file__)
+src_dir = os.path.join(script_dir, os.pardir, os.pardir, os.pardir, os.pardir)
+sys.path.append(os.path.join(src_dir, 'tools', 'grit'))
+
+from grit.format import data_pack
+
+
+def calc_output(options, locale):
+  """Determine the file that will be generated for the given locale."""
+  #e.g. '<(INTERMEDIATE_DIR)/repack/da.pak',
+  # For Fake Bidi, generate it at a fixed path so that tests can safely
+  # reference it.
+  if locale == 'fake-bidi':
+    return os.path.join(options.share_int_dir, locale + '.pak')
+  # For Cocoa to find the locale at runtime, it needs to use '_' instead
+  # of '-' (http://crbug.com/20441).  Also, 'en-US' should be represented
+  # simply as 'en' (http://crbug.com/19165, http://crbug.com/25578).
+  if locale == 'en-US':
+    locale = 'en'
+  else:
+    locale = locale.replace('-', '_')
+  return os.path.join(options.out_dir, locale + '.lproj', 'locale.pak')
+
+
+def calc_inputs(options, locale):
+  """Determine the files that need processing for the given locale."""
+  inputs = []
+
+  #e.g. '<(SHARED_INTERMEDIATE_DIR)/components/strings/
+  # components_strings_da.pak',
+  inputs.append(os.path.join(options.share_int_dir, 'components', 'strings',
+                'components_strings_%s.pak' % locale))
+
+  #e.g. '<(SHARED_INTERMEDIATE_DIR)/ui/strings/ui_strings_da.pak',
+  inputs.append(os.path.join(options.share_int_dir, 'ui', 'strings',
+                'ui_strings_%s.pak' % locale))
+
+  #e.g. '<(SHARED_INTERMEDIATE_DIR)/ios/chrome/ios_strings_resources_da.pak'
+  inputs.append(os.path.join(options.share_int_dir, 'ios', 'chrome',
+                'ios_strings_resources_%s.pak' % locale))
+
+  if options.branding:
+    #e.g. '<(SHARED_INTERMEDIATE_DIR)/ios/chrome/google_chrome_strings_da.pak'
+    #     or
+    #     '<(SHARED_INTERMEDIATE_DIR)/ios/chrome/chromium_strings_da.pak'
+    inputs.append(os.path.join(options.share_int_dir, 'ios', 'chrome',
+        '%s_strings_%s.pak' % (options.branding, locale)))
+
+  # Add any extra input files.
+  for extra_file in options.extra_input:
+    inputs.append('%s_%s.pak' % (extra_file, locale))
+
+  return inputs
+
+
+def list_outputs(options, locales):
+  """Returns the names of files that will be generated for the given locales.
+
+  This is to provide gyp the list of output files, so build targets can
+  properly track what needs to be built.
+  """
+  outputs = []
+  for locale in locales:
+    outputs.append(calc_output(options, locale))
+  return outputs
+
+
+def list_inputs(options, locales):
+  """Returns the names of files that will be processed for the given locales.
+
+  This is to provide gyp the list of input files, so build targets can properly
+  track their prerequisites.
+  """
+  inputs = []
+  for locale in locales:
+    inputs.extend(calc_inputs(options, locale))
+  return inputs
+
+
+def quote_filenames(filenames):
+  """Quote each elements so filename spaces don't mess up gyp's attempt to parse
+  it into a list."""
+  return " ".join(['"%s"' % x for x in filenames])
+
+
+def repack_locales(options, locales):
+  """ Loop over and repack the given locales."""
+  for locale in locales:
+    inputs = calc_inputs(options, locale)
+    output = calc_output(options, locale)
+    data_pack.DataPack.RePack(output, inputs, whitelist_file=options.whitelist)
+
+
+def DoMain(argv):
+  parser = optparse.OptionParser("usage: %prog [options] locales")
+  parser.add_option(
+      "-i", action="store_true", dest="print_inputs", default=False,
+      help="Print the expected input file list, then exit.")
+  parser.add_option(
+      "-o", action="store_true", dest="print_outputs", default=False,
+      help="Print the expected output file list, then exit.")
+  parser.add_option(
+      "-x", action="store", dest="out_dir",
+      help="Intermediate build files output directory.")
+  parser.add_option(
+      "-s", action="store", dest="share_int_dir",
+      help="Shared intermediate build files output directory.")
+  parser.add_option(
+      "-b", action="store", dest="branding",
+      help="Branding type of this build.")
+  parser.add_option(
+      "-e", action="append", dest="extra_input", default=[],
+      help="Full path to an extra input pak file without the "
+           "locale suffix and \".pak\" extension.")
+  parser.add_option(
+      "--whitelist", action="store", help="Full path to the "
+      "whitelist used to filter output pak file resource IDs")
+  options, locales = parser.parse_args(argv)
+
+  if not locales:
+    parser.error('Please specificy at least one locale to process.\n')
+
+  if not (options.out_dir and options.share_int_dir):
+    parser.error('Please specify all of "-x" and "-s".\n')
+  if options.print_inputs and options.print_outputs:
+    parser.error('Please specify only one of "-i" or "-o".\n')
+
+  if options.print_inputs:
+    return quote_filenames(list_inputs(options, locales))
+
+  if options.print_outputs:
+    return quote_filenames(list_outputs(options, locales))
+
+  return repack_locales(options, locales)
+
+if __name__ == '__main__':
+  results = DoMain(sys.argv[1:])
+  if results:
+    print results
diff --git a/ios/crnet/crnet.gyp b/ios/crnet/crnet.gyp
index 53358c2..23f3024 100644
--- a/ios/crnet/crnet.gyp
+++ b/ios/crnet/crnet.gyp
@@ -31,8 +31,6 @@
         'CrNet.mm',
         'crnet_environment.h',
         'crnet_environment.mm',
-        'crnet_net_log.h',
-        'crnet_net_log.cc',
       ],
       'defines': [
         # TODO(stuartmorgan): Revisit the way this is set, and the above is
diff --git a/ios/crnet/crnet_environment.h b/ios/crnet/crnet_environment.h
index e3a71c3..30678fa 100644
--- a/ios/crnet/crnet_environment.h
+++ b/ios/crnet/crnet_environment.h
@@ -10,16 +10,17 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
 #import "ios/crnet/CrNet.h"
-#include "ios/crnet/crnet_net_log.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_context.h"
 
 namespace net {
 class HttpCache;
 class NetworkChangeNotifier;
+class NetLog;
 class ProxyConfigService;
 class SdchManager;
 class URLRequestContextGetter;
+class WriteToFileNetLogObserver;
 }
 
 class CrNetHttpProtocolHandlerDelegate;
@@ -143,9 +144,8 @@
   scoped_ptr<net::URLRequestContext> main_context_;
   scoped_ptr<CrNetHttpProtocolHandlerDelegate> http_protocol_handler_delegate_;
   std::string user_agent_product_name_;
-  base::Lock net_log_lock_;
-  bool net_log_started_;
-  scoped_ptr<CrNetNetLog> net_log_;
+  scoped_ptr<net::NetLog> net_log_;
+  scoped_ptr<net::WriteToFileNetLogObserver> net_log_observer_;
 
   DISALLOW_COPY_AND_ASSIGN(CrNetEnvironment);
 };
diff --git a/ios/crnet/crnet_environment.mm b/ios/crnet/crnet_environment.mm
index d2161590..d139b7f 100644
--- a/ios/crnet/crnet_environment.mm
+++ b/ios/crnet/crnet_environment.mm
@@ -8,6 +8,9 @@
 
 #include "base/at_exit.h"
 #include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
 #include "base/i18n/icu_util.h"
 #include "base/json/json_writer.h"
 #include "base/mac/bind_objc_block.h"
@@ -32,6 +35,8 @@
 #include "net/http/http_server_properties_impl.h"
 #include "net/http/http_stream_factory.h"
 #include "net/http/http_util.h"
+#include "net/log/net_log.h"
+#include "net/log/write_to_file_net_log_observer.h"
 #include "net/proxy/proxy_service.h"
 #include "net/socket/next_proto.h"
 #include "net/ssl/channel_id_service.h"
@@ -55,21 +60,21 @@
  public:
   CrNetURLRequestContextGetter(
       net::URLRequestContext* context,
-      const scoped_refptr<base::MessageLoopProxy>& loop)
-      : context_(context), loop_(loop) {}
+      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
+      : context_(context), task_runner_(task_runner) {}
 
   net::URLRequestContext* GetURLRequestContext() override { return context_; }
 
   scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
       const override {
-    return loop_;
+    return task_runner_;
   }
  private:
   // Must be called on the IO thread.
   ~CrNetURLRequestContextGetter() override {}
 
   net::URLRequestContext* context_;
-  scoped_refptr<base::MessageLoopProxy> loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   DISALLOW_COPY_AND_ASSIGN(CrNetURLRequestContextGetter);
 };
 
@@ -154,11 +159,6 @@
 void CrNetEnvironment::StartNetLog(base::FilePath::StringType file_name,
     bool log_bytes) {
   DCHECK(file_name.length());
-  base::AutoLock lock(net_log_lock_);
-  if (net_log_started_) {
-    return;
-  }
-  net_log_started_ = true;
   PostToFileUserBlockingThread(FROM_HERE,
       base::Bind(&CrNetEnvironment::StartNetLogInternal,
                  base::Unretained(this), file_name, log_bytes));
@@ -169,21 +169,31 @@
   DCHECK(base::MessageLoop::current() ==
          file_user_blocking_thread_->message_loop());
   DCHECK(file_name.length());
-  if (!net_log_.get()) {
-    net_log_.reset(new CrNetNetLog());
-    main_context_.get()->set_net_log(net_log_.get());
-  }
-  CrNetNetLog::Mode mode = log_bytes ? CrNetNetLog::LOG_ALL_BYTES :
-                                       CrNetNetLog::LOG_STRIP_PRIVATE_DATA;
-  net_log_->Start(base::FilePath(file_name), mode);
+  DCHECK(net_log_);
+
+  if (net_log_observer_)
+    return;
+
+  base::FilePath temp_dir;
+  if (!base::GetTempDir(&temp_dir))
+    return;
+
+  base::FilePath full_path = temp_dir.Append(file_name);
+  base::ScopedFILE file(base::OpenFile(full_path, "w"));
+  if (!file)
+    return;
+
+  net::NetLogCaptureMode capture_mode = log_bytes ?
+      net::NetLogCaptureMode::IncludeSocketBytes() :
+      net::NetLogCaptureMode::Default();
+
+  net_log_observer_.reset(new net::WriteToFileNetLogObserver());
+  net_log_observer_->set_capture_mode(capture_mode);
+  net_log_observer_->StartObserving(net_log_.get(), file.Pass(), nullptr,
+                                    nullptr);
 }
 
 void CrNetEnvironment::StopNetLog() {
-  base::AutoLock lock(net_log_lock_);
-  if (!net_log_started_) {
-    return;
-  }
-  net_log_started_ = false;
   PostToFileUserBlockingThread(FROM_HERE,
       base::Bind(&CrNetEnvironment::StopNetLogInternal,
       base::Unretained(this)));
@@ -192,8 +202,9 @@
 void CrNetEnvironment::StopNetLogInternal() {
   DCHECK(base::MessageLoop::current() ==
          file_user_blocking_thread_->message_loop());
-  if (net_log_.get()) {
-    net_log_->Stop();
+  if (net_log_observer_) {
+    net_log_observer_->StopObserving(nullptr);
+    net_log_observer_.reset();
   }
 }
 
@@ -260,7 +271,7 @@
   // delegates will receive callbacks.
   network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
   proxy_config_service_.reset(net::ProxyService::CreateSystemProxyConfigService(
-      network_io_thread_->message_loop_proxy(), nullptr));
+      network_io_thread_->task_runner(), nullptr));
 
   PostToNetworkThread(FROM_HERE,
       base::Bind(&CrNetEnvironment::InitializeOnNetworkThread,
@@ -268,9 +279,8 @@
 
   net::SetURLRequestContextForNSSHttpIO(main_context_.get());
   main_context_getter_ = new CrNetURLRequestContextGetter(
-      main_context_.get(), network_io_thread_->message_loop_proxy());
+      main_context_.get(), network_io_thread_->task_runner());
   SetRequestFilterBlock(nil);
-  net_log_started_ = false;
 }
 
 void CrNetEnvironment::InstallIntoSessionConfiguration(
@@ -310,7 +320,7 @@
   net::RequestTracker::AddGlobalNetworkClientFactory(
       [[[WebPNetworkClientFactory alloc]
           initWithTaskRunner:file_user_blocking_thread_
-                                 ->message_loop_proxy()] autorelease]);
+                                 ->task_runner()] autorelease]);
 
 #if 0
   // TODO(huey): Re-enable this once SDCH supports SSL and dictionaries from
@@ -373,12 +383,10 @@
       base::mac::NSStringToFilePath([dirs objectAtIndex:0]);
   cache_path = cache_path.Append(FILE_PATH_LITERAL("crnet"));
   net::HttpCache::DefaultBackend* main_backend =
-      new net::HttpCache::DefaultBackend(
-          net::DISK_CACHE,
-          net::CACHE_BACKEND_DEFAULT,
-          cache_path,
-          0,  // Default cache size.
-          network_cache_thread_->message_loop_proxy());
+      new net::HttpCache::DefaultBackend(net::DISK_CACHE,
+                                         net::CACHE_BACKEND_DEFAULT, cache_path,
+                                         0,  // Default cache size.
+                                         network_cache_thread_->task_runner());
 
   net::HttpNetworkSession::Params params;
   params.host_resolver = main_context_->host_resolver();
@@ -421,8 +429,11 @@
       new net::URLRequestJobFactoryImpl;
   job_factory->SetProtocolHandler("data", new net::DataProtocolHandler);
   job_factory->SetProtocolHandler(
-      "file", new net::FileProtocolHandler(file_thread_->message_loop_proxy()));
+      "file", new net::FileProtocolHandler(file_thread_->task_runner()));
   main_context_->set_job_factory(job_factory);
+
+  net_log_.reset(new net::NetLog());
+  main_context_->set_net_log(net_log_.get());
 }
 
 std::string CrNetEnvironment::user_agent() {
diff --git a/ios/crnet/crnet_net_log.cc b/ios/crnet/crnet_net_log.cc
deleted file mode 100644
index 4ad3d30..0000000
--- a/ios/crnet/crnet_net_log.cc
+++ /dev/null
@@ -1,46 +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 "ios/crnet/crnet_net_log.h"
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_file.h"
-#include "base/values.h"
-#include "net/log/net_log.h"
-#include "net/log/net_log_util.h"
-#include "net/log/write_to_file_net_log_observer.h"
-
-CrNetNetLog::CrNetNetLog() { }
-CrNetNetLog::~CrNetNetLog() { }
-
-bool CrNetNetLog::Start(const base::FilePath& log_file,
-                        CrNetNetLog::Mode mode) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  base::FilePath temp_dir;
-  if (!base::GetTempDir(&temp_dir))
-    return false;
-
-  base::FilePath full_path = temp_dir.Append(log_file);
-  base::ScopedFILE file(base::OpenFile(full_path, "w"));
-  if (!file)
-    return false;
-
-  scoped_ptr<base::Value> constants(net::GetNetConstants().Pass());
-
-  net::NetLogCaptureMode capture_mode = mode == LOG_ALL_BYTES ?
-      net::NetLogCaptureMode::IncludeSocketBytes() :
-      net::NetLogCaptureMode::Default();
-  write_to_file_observer_.reset(new net::WriteToFileNetLogObserver());
-  write_to_file_observer_->set_capture_mode(capture_mode);
-  write_to_file_observer_->StartObserving(this, file.Pass(), constants.get(),
-                                          nullptr);
-  return true;
-}
-
-void CrNetNetLog::Stop() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  write_to_file_observer_->StopObserving(nullptr);
-  write_to_file_observer_.reset();
-}
diff --git a/ios/crnet/crnet_net_log.h b/ios/crnet/crnet_net_log.h
deleted file mode 100644
index 6bdc076..0000000
--- a/ios/crnet/crnet_net_log.h
+++ /dev/null
@@ -1,51 +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 IOS_CRNET_CRNET_NET_LOG_H_
-#define IOS_CRNET_CRNET_NET_LOG_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "net/log/net_log.h"
-
-namespace base {
-class FilePath;
-class DictionaryValue;
-}
-
-namespace net {
-class WriteToFileNetLogObserver;
-}
-
-// CrNet-specific NetLog subclass.
-// This class can be used as a NetLog where needed; it logs all log entries to
-// the file specified in Start().
-class CrNetNetLog : public net::NetLog {
- public:
-  enum Mode {
-    LOG_ALL_BYTES,
-    LOG_STRIP_PRIVATE_DATA,
-  };
-
-  CrNetNetLog();
-  ~CrNetNetLog() override;
-
-  // Starts logging to the file named |log_file|. If |mode| is LOG_ALL_BYTES,
-  // logs all network traffic, including raw bytes. If |mode| is
-  // LOG_STRIP_PRIVATE_DATA, strips cookies and other private data, and does
-  // not log raw bytes.
-  bool Start(const base::FilePath& log_file, Mode mode);
-
-  // Stops logging.
-  void Stop();
-
- private:
-  // Underlying file writer. This observer observes NetLog events and writes
-  // them back to the file this class is logging to.
-  scoped_ptr<net::WriteToFileNetLogObserver> write_to_file_observer_;
-
-  base::ThreadChecker thread_checker_;
-};
-
-#endif  // IOS_CRNET_CRNET_NET_LOG_H
diff --git a/ios/net/cookies/cookie_store_ios.mm b/ios/net/cookies/cookie_store_ios.mm
index bd071509..b54f731 100644
--- a/ios/net/cookies/cookie_store_ios.mm
+++ b/ios/net/cookies/cookie_store_ios.mm
@@ -15,13 +15,13 @@
 #include "base/mac/foundation_util.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/metrics/histogram.h"
 #include "base/observer_list.h"
 #include "base/sequenced_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/task_runner_util.h"
+#include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_restrictions.h"
 #include "ios/net/cookies/cookie_creation_time_manager.h"
 #include "ios/net/cookies/cookie_store_ios_client.h"
@@ -798,7 +798,7 @@
 
   flush_closure_.Reset(base::Bind(&CookieStoreIOS::Flush,
                                   base::Unretained(this), base::Closure()));
-  base::MessageLoopProxy::current()->PostDelayedTask(
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, flush_closure_.callback(), flush_delay_);
 }
 
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.cc b/ios/public/provider/chrome/browser/chrome_browser_provider.cc
index b626226..7db527b 100644
--- a/ios/public/provider/chrome/browser/chrome_browser_provider.cc
+++ b/ios/public/provider/chrome/browser/chrome_browser_provider.cc
@@ -4,6 +4,8 @@
 
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 
+#include "base/logging.h"
+
 namespace ios {
 
 namespace {
@@ -58,6 +60,10 @@
 void ChromeBrowserProvider::ShowTranslateSettings() {
 }
 
+bool ChromeBrowserProvider::IsBookmarkCollectionEnabled() {
+  return false;
+}
+
 const char* ChromeBrowserProvider::GetChromeUIScheme() {
   return nullptr;
 }
@@ -76,6 +82,12 @@
   return std::string();
 }
 
+std::string ChromeBrowserProvider::GetProductVersionWithPrefix(
+    const std::string& prefix) {
+  NOTREACHED();
+  return std::string();
+}
+
 KeyedServiceProvider* ChromeBrowserProvider::GetKeyedServiceProvider() {
   return nullptr;
 }
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.h b/ios/public/provider/chrome/browser/chrome_browser_provider.h
index e67d455..4f1e12a 100644
--- a/ios/public/provider/chrome/browser/chrome_browser_provider.h
+++ b/ios/public/provider/chrome/browser/chrome_browser_provider.h
@@ -73,6 +73,8 @@
   virtual GeolocationUpdaterProvider* GetGeolocationUpdaterProvider();
   // Displays the Translate settings screen.
   virtual void ShowTranslateSettings();
+  // Returns whether the new bookmark collection experience is enabled.
+  virtual bool IsBookmarkCollectionEnabled();
   // Returns the chrome UI scheme.
   // TODO(droger): Remove this method once chrome no longer needs to match
   // content.
@@ -86,6 +88,8 @@
           autofill::CardUnmaskPromptController* controller);
   // Returns risk data used in Wallet requests.
   virtual std::string GetRiskData();
+  // Returns product version with prefix.
+  virtual std::string GetProductVersionWithPrefix(const std::string& prefix);
   // Returns an instance of KeyedServiceProvider.
   virtual KeyedServiceProvider* GetKeyedServiceProvider();
 };
diff --git a/ios/public/provider/chrome/browser/keyed_service_provider.cc b/ios/public/provider/chrome/browser/keyed_service_provider.cc
index e5782af5..098beee 100644
--- a/ios/public/provider/chrome/browser/keyed_service_provider.cc
+++ b/ios/public/provider/chrome/browser/keyed_service_provider.cc
@@ -14,6 +14,15 @@
 KeyedServiceProvider::~KeyedServiceProvider() {
 }
 
+KeyedServiceBaseFactory* KeyedServiceProvider::GetBookmarkModelFactory() {
+  return nullptr;
+}
+
+bookmarks::BookmarkModel* KeyedServiceProvider::GetBookmarkModelForBrowserState(
+    ios::ChromeBrowserState* browser_state) {
+  return nullptr;
+}
+
 KeyedServiceBaseFactory*
 KeyedServiceProvider::GetProfileOAuth2TokenServiceFactory() {
   return nullptr;
@@ -25,6 +34,17 @@
   return nullptr;
 }
 
+KeyedServiceBaseFactory*
+KeyedServiceProvider::GetProfileOAuth2TokenServiceIOSFactory() {
+  return nullptr;
+}
+
+ProfileOAuth2TokenServiceIOS*
+KeyedServiceProvider::GetProfileOAuth2TokenServiceIOSForBrowserState(
+    ChromeBrowserState* browser_state) {
+  return nullptr;
+}
+
 KeyedServiceBaseFactory* KeyedServiceProvider::GetSigninManagerFactory() {
   return nullptr;
 }
@@ -55,17 +75,6 @@
   return nullptr;
 }
 
-KeyedServiceBaseFactory*
-KeyedServiceProvider::GetEnhancedBookmarkModelFactory() {
-  return nullptr;
-}
-
-enhanced_bookmarks::EnhancedBookmarkModel*
-KeyedServiceProvider::GetEnhancedBookmarkModelForBrowserState(
-    ChromeBrowserState* browser_state) {
-  return nullptr;
-}
-
 KeyedServiceBaseFactory* KeyedServiceProvider::GetSyncServiceFactory() {
   return nullptr;
 }
diff --git a/ios/public/provider/chrome/browser/keyed_service_provider.h b/ios/public/provider/chrome/browser/keyed_service_provider.h
index ab5bcf1b..04ce4c4 100644
--- a/ios/public/provider/chrome/browser/keyed_service_provider.h
+++ b/ios/public/provider/chrome/browser/keyed_service_provider.h
@@ -12,6 +12,7 @@
 
 class KeyedServiceBaseFactory;
 class ProfileOAuth2TokenService;
+class ProfileOAuth2TokenServiceIOS;
 class SigninManager;
 
 namespace autofill {
@@ -19,8 +20,8 @@
 class PersonalDataManager;
 }
 
-namespace enhanced_bookmarks {
-class EnhancedBookmarkModel;
+namespace bookmarks {
+class BookmarkModel;
 }
 
 namespace sync_driver {
@@ -38,6 +39,13 @@
   KeyedServiceProvider();
   virtual ~KeyedServiceProvider();
 
+  // Returns the bookmarks::BookmarkModel factory for dependencies.
+  virtual KeyedServiceBaseFactory* GetBookmarkModelFactory();
+
+  // Returns an instance of bookmarks::BookmarkModel tied to |browser_state|.
+  virtual bookmarks::BookmarkModel* GetBookmarkModelForBrowserState(
+      ios::ChromeBrowserState* browser_state);
+
   // Returns the ProfileOAuth2TokenService factory for dependencies.
   virtual KeyedServiceBaseFactory* GetProfileOAuth2TokenServiceFactory();
 
@@ -46,6 +54,15 @@
   GetProfileOAuth2TokenServiceForBrowserState(
       ChromeBrowserState* browser_state);
 
+  // Returns the ProfileOAuth2TokenServiceIOS factory for dependencies.
+  virtual KeyedServiceBaseFactory* GetProfileOAuth2TokenServiceIOSFactory();
+
+  // Returns an instance of ProfileOAuth2TokenServiceIOS tied to
+  // |browser_state|.
+  virtual ProfileOAuth2TokenServiceIOS*
+  GetProfileOAuth2TokenServiceIOSForBrowserState(
+      ChromeBrowserState* browser_state);
+
   // Returns the SigninManager factory for dependencies.
   virtual KeyedServiceBaseFactory* GetSigninManagerFactory();
 
@@ -70,15 +87,6 @@
   virtual autofill::PersonalDataManager* GetPersonalDataManagerForBrowserState(
       ChromeBrowserState* browser_state);
 
-  // Returns the enhanced_bookmarks::EnhancedBookmarkModel factory for
-  // dependencies.
-  virtual KeyedServiceBaseFactory* GetEnhancedBookmarkModelFactory();
-
-  // Returns an instance of enhanced_bookmarks::EnhancedBookmarkModel tied to
-  // |browser_state|.
-  virtual enhanced_bookmarks::EnhancedBookmarkModel*
-  GetEnhancedBookmarkModelForBrowserState(ChromeBrowserState* browser_state);
-
   // Returns the sync_driver::SyncService factory for dependencies.
   virtual KeyedServiceBaseFactory* GetSyncServiceFactory();
 
diff --git a/ios/public/provider/components/signin/browser/profile_oauth2_token_service_ios_provider.h b/ios/public/provider/components/signin/browser/profile_oauth2_token_service_ios_provider.h
index d52808ddf..4833cd6e 100644
--- a/ios/public/provider/components/signin/browser/profile_oauth2_token_service_ios_provider.h
+++ b/ios/public/provider/components/signin/browser/profile_oauth2_token_service_ios_provider.h
@@ -54,8 +54,8 @@
                               NSDate* expiration,
                               NSError* error)> AccessTokenCallback;
 
-  ProfileOAuth2TokenServiceIOSProvider() {};
-  virtual ~ProfileOAuth2TokenServiceIOSProvider() {};
+  ProfileOAuth2TokenServiceIOSProvider() {}
+  virtual ~ProfileOAuth2TokenServiceIOSProvider() {}
 
   // Initializes the shared authentication library. This method should be called
   // when loading credentials if the user is signed in to Chrome via the shared
diff --git a/ios/web/browsing_data_partition_impl.mm b/ios/web/browsing_data_partition_impl.mm
index d621edb65..f15ac55 100644
--- a/ios/web/browsing_data_partition_impl.mm
+++ b/ios/web/browsing_data_partition_impl.mm
@@ -23,12 +23,12 @@
 // being observed for KVO changes in the |mode| value. |browserState| cannot be
 // null and the |browserState|'s associated CRWBrowsingDataStore must be
 // |browsingDataStore|.
-// The |browsingDataStore|'s mode must not already be SYNCHRONIZING.
+// The |browsingDataStore|'s mode must not already be |CHANGING|.
 - (void)startObservingBrowsingDataStore:(CRWBrowsingDataStore*)browsingDataStore
                            browserState:(web::BrowserState*)browserState;
 
 // Stops observing |browsingDataStore| for its |mode| change.
-// The |browsingDataStore|'s mode must not be SYNCHRONIZING.
+// The |browsingDataStore|'s mode must not be |CHANGING|.
 - (void)stopObservingBrowsingDataStore:(CRWBrowsingDataStore*)browsingDataStore;
 @end
 
@@ -42,7 +42,7 @@
       web::BrowserState::GetBrowsingDataPartition(browserState);
   DCHECK(browsing_data_partition);
   DCHECK_EQ(browsing_data_partition->GetBrowsingDataStore(), browsingDataStore);
-  DCHECK_NE(SYNCHRONIZING, browsingDataStore.mode);
+  DCHECK_NE(web::CHANGING, browsingDataStore.mode);
 
   [browsingDataStore addObserver:self
                       forKeyPath:@"mode"
@@ -52,7 +52,7 @@
 
 - (void)stopObservingBrowsingDataStore:
         (CRWBrowsingDataStore*)browsingDataStore {
-  DCHECK_NE(SYNCHRONIZING, browsingDataStore.mode);
+  DCHECK_NE(web::CHANGING, browsingDataStore.mode);
 
   [browsingDataStore removeObserver:self forKeyPath:@"mode"];
 }
@@ -65,7 +65,7 @@
   DCHECK([browsingDataStore isKindOfClass:[CRWBrowsingDataStore class]]);
   DCHECK(context);
 
-  if (browsingDataStore.mode == SYNCHRONIZING) {
+  if (browsingDataStore.mode == web::CHANGING) {
     ++self.outOfSyncStoreCount;
     return;
   }
@@ -76,9 +76,9 @@
   bool activeState = activeStateManager->IsActive();
   // Check if the |browsingDataStore|'s associated ActiveStateManager's active
   // state is still out of sync.
-  if (activeState && browsingDataStore.mode == INACTIVE) {
+  if (activeState && browsingDataStore.mode == web::INACTIVE) {
     [browsingDataStore makeActiveWithCompletionHandler:nil];
-  } else if (!activeState && browsingDataStore.mode == ACTIVE) {
+  } else if (!activeState && browsingDataStore.mode == web::ACTIVE) {
     [browsingDataStore makeInactiveWithCompletionHandler:nil];
   }
 
@@ -115,7 +115,7 @@
   if (active_state_manager_) {
     active_state_manager_->RemoveObserver(this);
   }
-  DCHECK_NE(SYNCHRONIZING, [browsing_data_store_ mode]);
+  DCHECK_NE(CHANGING, [browsing_data_store_ mode]);
   [g_browsing_data_store_mode_observer
       stopObservingBrowsingDataStore:browsing_data_store_];
 }
diff --git a/ios/web/crw_browsing_data_store.mm b/ios/web/crw_browsing_data_store.mm
index 7142777..1d9fbe0 100644
--- a/ios/web/crw_browsing_data_store.mm
+++ b/ios/web/crw_browsing_data_store.mm
@@ -61,12 +61,12 @@
 - (SEL)browsingDataManagerSelectorForRemoveOperationType;
 
 // Redefined to be read-write. Must be called from the main thread.
-@property(nonatomic, assign) CRWBrowsingDataStoreMode mode;
+@property(nonatomic, assign) web::BrowsingDataStoreMode mode;
 // Sets the mode iff there are no more stash or restore operations that are
 // still pending. |mode| can only be either |ACTIVE| or |INACTIVE|.
 // |handler| is called immediately (in the same runloop) with a BOOL indicating
 // whether the mode change was successful or not. |handler| can be nil.
-- (void)finalizeChangeToMode:(CRWBrowsingDataStoreMode)mode
+- (void)finalizeChangeToMode:(web::BrowsingDataStoreMode)mode
     andCallCompletionHandler:(void (^)(BOOL modeChangeWasSuccessful))handler;
 
 // Changes the mode of the CRWBrowsingDataStore to |mode|. This is an
@@ -75,7 +75,7 @@
 // |completionHandler| is called on the main thread. This block has no return
 // value and takes a single BOOL argument that indicates whether or not the
 // mode change was successfully changed to |mode|.
-- (void)changeMode:(CRWBrowsingDataStoreMode)mode
+- (void)changeMode:(web::BrowsingDataStoreMode)mode
     completionHandler:(void (^)(BOOL modeChangeWasSuccessful))completionHandler;
 
 // The number of stash or restore operations that are still pending.
@@ -107,7 +107,7 @@
   // The delegate.
   base::WeakNSProtocol<id<CRWBrowsingDataStoreDelegate>> _delegate;
   // The mode of the CRWBrowsingDataStore.
-  CRWBrowsingDataStoreMode _mode;
+  web::BrowsingDataStoreMode _mode;
   // The dictionary that maps a browsing data type to its
   // CRWBrowsingDataManager.
   base::scoped_nsobject<NSDictionary> _browsingDataTypeMap;
@@ -117,7 +117,7 @@
   // The last dispatched stash or restore operation that was enqueued to be run.
   base::scoped_nsobject<NSOperation> _lastDispatchedStashOrRestoreOperation;
   // The number of stash or restore operations that are still pending. If this
-  // value > 0 the mode of the CRWBrowsingDataStore is SYNCHRONIZING. The mode
+  // value > 0 the mode of the CRWBrowsingDataStore is |CHANGING|. The mode
   // can be made ACTIVE or INACTIVE only be set when this value is 0.
   NSUInteger _numberOfPendingStashOrRestoreOperations;
 }
@@ -163,7 +163,7 @@
     web::ActiveStateManager* activeStateManager =
         web::BrowserState::GetActiveStateManager(browserState);
     DCHECK(activeStateManager);
-    _mode = activeStateManager->IsActive() ? ACTIVE : INACTIVE;
+    _mode = activeStateManager->IsActive() ? web::ACTIVE : web::INACTIVE;
     // TODO(shreyasv): If the creation of CRWBrowsingDataManagers turns out to
     // be an expensive operations re-visit this with a lazy-evaluation approach.
     base::scoped_nsobject<CRWCookieBrowsingDataManager>
@@ -232,10 +232,10 @@
 }
 
 - (SEL)browsingDataManagerSelectorForRemoveOperationType {
-  if (self.mode == ACTIVE) {
+  if (self.mode == web::ACTIVE) {
     return @selector(removeDataAtCanonicalPath);
   }
-  if (self.mode == INACTIVE) {
+  if (self.mode == web::INACTIVE) {
     return @selector(removeDataAtStashPath);
   }
   DCHECK(_lastDispatchedStashOrRestoreOperation);
@@ -264,17 +264,17 @@
   return [super automaticallyNotifiesObserversForKey:(NSString*)key];
 }
 
-- (CRWBrowsingDataStoreMode)mode {
+- (web::BrowsingDataStoreMode)mode {
   DCHECK([NSThread isMainThread]);
   return _mode;
 }
 
-- (void)setMode:(CRWBrowsingDataStoreMode)mode {
+- (void)setMode:(web::BrowsingDataStoreMode)mode {
   DCHECK([NSThread isMainThread]);
   if (_mode == mode) {
     return;
   }
-  if (mode == ACTIVE || mode == INACTIVE) {
+  if (mode == web::ACTIVE || mode == web::INACTIVE) {
     DCHECK(!self.numberOfPendingStashOrRestoreOperations);
   }
   [self willChangeValueForKey:@"mode"];
@@ -282,10 +282,10 @@
   [self didChangeValueForKey:@"mode"];
 }
 
-- (void)finalizeChangeToMode:(CRWBrowsingDataStoreMode)mode
+- (void)finalizeChangeToMode:(web::BrowsingDataStoreMode)mode
     andCallCompletionHandler:(void (^)(BOOL modeChangeWasSuccessful))handler {
   DCHECK([NSThread isMainThread]);
-  DCHECK_NE(SYNCHRONIZING, mode);
+  DCHECK_NE(web::CHANGING, mode);
 
   BOOL modeChangeWasSuccessful = NO;
   if (!self.numberOfPendingStashOrRestoreOperations) {
@@ -313,17 +313,17 @@
         (void (^)(BOOL success))completionHandler {
   DCHECK([NSThread isMainThread]);
 
-  [self changeMode:ACTIVE completionHandler:completionHandler];
+  [self changeMode:web::ACTIVE completionHandler:completionHandler];
 }
 
 - (void)makeInactiveWithCompletionHandler:
         (void (^)(BOOL success))completionHandler {
   DCHECK([NSThread isMainThread]);
 
-  [self changeMode:INACTIVE completionHandler:completionHandler];
+  [self changeMode:web::INACTIVE completionHandler:completionHandler];
 }
 
-- (void)changeMode:(CRWBrowsingDataStoreMode)mode
+- (void)changeMode:(web::BrowsingDataStoreMode)mode
     completionHandler:
         (void (^)(BOOL modeChangeWasSuccessful))completionHandler {
   DCHECK([NSThread isMainThread]);
@@ -343,7 +343,7 @@
   }
 
   OperationType operationType = NONE;
-  if (mode == ACTIVE) {
+  if (mode == web::ACTIVE) {
     // By default a |RESTORE| operation is performed when the mode is changed
     // to |ACTIVE|.
     operationType = RESTORE;
@@ -398,7 +398,7 @@
   DCHECK(selector);
 
   if (operationType == RESTORE || operationType == STASH) {
-    [self setMode:SYNCHRONIZING];
+    [self setMode:web::CHANGING];
     ++self.numberOfPendingStashOrRestoreOperations;
     completionHandler = ^{
       --self.numberOfPendingStashOrRestoreOperations;
diff --git a/ios/web/crw_browsing_data_store_unittest.mm b/ios/web/crw_browsing_data_store_unittest.mm
index 60563d8e..a35c7f9 100644
--- a/ios/web/crw_browsing_data_store_unittest.mm
+++ b/ios/web/crw_browsing_data_store_unittest.mm
@@ -158,29 +158,29 @@
 
   id unsucessfullCallback = ^(BOOL success) {
     ASSERT_TRUE([NSThread isMainThread]);
-    CRWBrowsingDataStoreMode mode = [browsing_data_store_ mode];
+    BrowsingDataStoreMode mode = [browsing_data_store_ mode];
     EXPECT_FALSE(success);
-    EXPECT_EQ(SYNCHRONIZING, mode);
+    EXPECT_EQ(CHANGING, mode);
   };
   [browsing_data_store_ makeActiveWithCompletionHandler:unsucessfullCallback];
-  EXPECT_EQ(SYNCHRONIZING, [browsing_data_store_ mode]);
+  EXPECT_EQ(CHANGING, [browsing_data_store_ mode]);
   EXPECT_EQ(1U, [observer modeChangeCount]);
 
   [browsing_data_store_ makeInactiveWithCompletionHandler:unsucessfullCallback];
-  EXPECT_EQ(SYNCHRONIZING, [browsing_data_store_ mode]);
+  EXPECT_EQ(CHANGING, [browsing_data_store_ mode]);
 
   [browsing_data_store_ makeActiveWithCompletionHandler:unsucessfullCallback];
-  EXPECT_EQ(SYNCHRONIZING, [browsing_data_store_ mode]);
+  EXPECT_EQ(CHANGING, [browsing_data_store_ mode]);
 
   __block BOOL block_was_called = NO;
   [browsing_data_store_ makeInactiveWithCompletionHandler:^(BOOL success) {
     ASSERT_TRUE([NSThread isMainThread]);
-    CRWBrowsingDataStoreMode mode = [browsing_data_store_ mode];
+    BrowsingDataStoreMode mode = [browsing_data_store_ mode];
     EXPECT_TRUE(success);
     EXPECT_EQ(INACTIVE, mode);
     block_was_called = YES;
   }];
-  EXPECT_EQ(SYNCHRONIZING, [browsing_data_store_ mode]);
+  EXPECT_EQ(CHANGING, [browsing_data_store_ mode]);
 
   base::test::ios::WaitUntilCondition(^bool{
     return block_was_called;
diff --git a/ios/web/public/crw_browsing_data_store.h b/ios/web/public/crw_browsing_data_store.h
index 20eae81..adfccef 100644
--- a/ios/web/public/crw_browsing_data_store.h
+++ b/ios/web/public/crw_browsing_data_store.h
@@ -22,21 +22,21 @@
   BROWSING_DATA_TYPE_ALL = BROWSING_DATA_TYPE_COOKIES,
 };
 
-}  // namespace web
-
-// Represents the modes that a CRWBrowsingDataStore is currently at.
-enum CRWBrowsingDataStoreMode {
+// Represents the modes that a CRWBrowsingDataStore can be in.
+typedef NS_ENUM(NSUInteger, BrowsingDataStoreMode) {
   // Web views (associated transitively through the BrowseState) are
   // flushing/reading their data from disk.
-  ACTIVE,
+  ACTIVE = 1,
   // The CRWBrowsingDataStore's mode is in the process of becoming either ACTIVE
   // or INACTIVE.
-  SYNCHRONIZING,
+  CHANGING,
   // Browsing data is stored in a path unique to the BrowserState and is
   // currently not being read or written to by web views.
-  INACTIVE
+  INACTIVE,
 };
 
+}  // namespace web
+
 // A CRWBrowsingDataStore represents various types of data that a web view
 // (UIWebView and WKWebView) uses.
 // All methods must be called on the UI thread.
@@ -52,7 +52,7 @@
 @property(nonatomic, weak) id<CRWBrowsingDataStoreDelegate> delegate;
 
 // The mode that the CRWBrowsingDataStore is in. KVO compliant.
-@property(nonatomic, assign, readonly) CRWBrowsingDataStoreMode mode;
+@property(nonatomic, assign, readonly) web::BrowsingDataStoreMode mode;
 
 // TODO(shreyasv): Verify the preconditions for the following 3 methods when
 // web::WebViewCounter class is implemented. crbug.com/480507
diff --git a/ios/web/public/crw_browsing_data_store_delegate.h b/ios/web/public/crw_browsing_data_store_delegate.h
index 7af1aa1..63fa9649 100644
--- a/ios/web/public/crw_browsing_data_store_delegate.h
+++ b/ios/web/public/crw_browsing_data_store_delegate.h
@@ -35,7 +35,7 @@
 }  // namespace web
 
 // The CRWBrowsingDataStoreDelegate has methods that can override the default
-// behavior of a CRWBrowsingDataStoreMode when a mode change occurs.
+// behavior of a CRWBrowsingDataStore when a mode change occurs.
 @protocol CRWBrowsingDataStoreDelegate<NSObject>
 
 // Called when a CRWBrowsingDataStore wants to change its mode to |ACTIVE|.
diff --git a/ios/web/public/web_thread.h b/ios/web/public/web_thread.h
index 1f44d63..99f41c3 100644
--- a/ios/web/public/web_thread.h
+++ b/ios/web/public/web_thread.h
@@ -11,7 +11,6 @@
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/task_runner_util.h"
 
 namespace base {
@@ -84,8 +83,8 @@
 
     // NOTE: do not add new threads here that are only used by a small number of
     // files. Instead you should just use a Thread class and pass its
-    // MessageLoopProxy around. Named threads there are only for threads that
-    // are used in many places.
+    // SingleThreadTaskRunner around. Named threads there are only for threads
+    // that are used in many places.
 
     // This identifier does not represent a thread.  Instead it counts the
     // number of well-known threads.  Insert new well-known threads before this
@@ -124,18 +123,17 @@
       const tracked_objects::Location& from_here,
       const base::Callback<ReturnType(void)>& task,
       const base::Callback<void(ReplyArgType)>& reply) {
-    scoped_refptr<base::MessageLoopProxy> message_loop_proxy =
-        GetMessageLoopProxyForThread(identifier);
-    return base::PostTaskAndReplyWithResult(message_loop_proxy.get(), from_here,
-                                            task, reply);
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+        GetTaskRunnerForThread(identifier);
+    return base::PostTaskAndReplyWithResult(task_runner.get(), from_here, task,
+                                            reply);
   }
 
   template <class T>
   static bool DeleteSoon(ID identifier,
                          const tracked_objects::Location& from_here,
                          const T* object) {
-    return GetMessageLoopProxyForThread(identifier)
-        ->DeleteSoon(from_here, object);
+    return GetTaskRunnerForThread(identifier)->DeleteSoon(from_here, object);
   }
 
   // Simplified wrappers for posting to the blocking thread pool. Use this
@@ -202,9 +200,9 @@
   // sets identifier to its ID.
   static bool GetCurrentThreadIdentifier(ID* identifier) WARN_UNUSED_RESULT;
 
-  // Callers can hold on to a refcounted MessageLoopProxy beyond the lifetime
-  // of the thread.
-  static scoped_refptr<base::MessageLoopProxy> GetMessageLoopProxyForThread(
+  // Callers can hold on to a refcounted SingleThreadTaskRunner beyond the
+  // lifetime of the thread.
+  static scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunnerForThread(
       ID identifier);
 
   // Returns an appropriate error message for when
diff --git a/ios/web/shell/shell_browser_state.mm b/ios/web/shell/shell_browser_state.mm
index 4702b1b..08f5a25 100644
--- a/ios/web/shell/shell_browser_state.mm
+++ b/ios/web/shell/shell_browser_state.mm
@@ -20,9 +20,9 @@
 
   request_context_getter_ = new ShellURLRequestContextGetter(
       GetStatePath(),
-      web::WebThread::GetMessageLoopProxyForThread(web::WebThread::IO),
-      web::WebThread::GetMessageLoopProxyForThread(web::WebThread::FILE),
-      web::WebThread::GetMessageLoopProxyForThread(web::WebThread::CACHE));
+      web::WebThread::GetTaskRunnerForThread(web::WebThread::IO),
+      web::WebThread::GetTaskRunnerForThread(web::WebThread::FILE),
+      web::WebThread::GetTaskRunnerForThread(web::WebThread::CACHE));
 }
 
 ShellBrowserState::~ShellBrowserState() {
diff --git a/ios/web/shell/shell_url_request_context_getter.cc b/ios/web/shell/shell_url_request_context_getter.cc
index b091466..8cffb68 100644
--- a/ios/web/shell/shell_url_request_context_getter.cc
+++ b/ios/web/shell/shell_url_request_context_getter.cc
@@ -40,7 +40,7 @@
     const base::FilePath& base_path,
     const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner,
     const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner,
-    const scoped_refptr<base::MessageLoopProxy>& cache_task_runner)
+    const scoped_refptr<base::SingleThreadTaskRunner>& cache_task_runner)
     : base_path_(base_path),
       file_task_runner_(file_task_runner),
       network_task_runner_(network_task_runner),
diff --git a/ios/web/shell/shell_url_request_context_getter.h b/ios/web/shell/shell_url_request_context_getter.h
index 2fdb971..b4144263 100644
--- a/ios/web/shell/shell_url_request_context_getter.h
+++ b/ios/web/shell/shell_url_request_context_getter.h
@@ -9,7 +9,6 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop_proxy.h"
 #include "base/single_thread_task_runner.h"
 #include "net/url_request/url_request_context_getter.h"
 
@@ -32,7 +31,7 @@
       const base::FilePath& base_path,
       const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner,
       const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner,
-      const scoped_refptr<base::MessageLoopProxy>& cache_task_runner);
+      const scoped_refptr<base::SingleThreadTaskRunner>& cache_task_runner);
 
   // net::URLRequestContextGetter implementation.
   net::URLRequestContext* GetURLRequestContext() override;
@@ -46,7 +45,7 @@
   base::FilePath base_path_;
   scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
-  scoped_refptr<base::MessageLoopProxy> cache_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> cache_task_runner_;
   scoped_ptr<net::ProxyConfigService> proxy_config_service_;
   scoped_ptr<net::NetworkDelegate> network_delegate_;
   scoped_ptr<net::URLRequestContextStorage> storage_;
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 2cc2e79..c566bf0 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -2741,7 +2741,8 @@
       // Record the URL so that errors reported following the 'NO' reply can be
       // safely ignored.
       [_openedApplicationURL addObject:request.URL];
-      return NO;
+      if ([self cancellable])
+        [_delegate webPageOrderedClose];
     }
     return NO;
   }
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 9f4e3a9..3ee70f3 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
@@ -653,8 +653,9 @@
     return;
 
   // WKWebView will not load unauthenticated content.
-  item->GetSSL().security_style = item->GetURL().SchemeIs(url::kHttpsScheme) ?
-      web::SECURITY_STYLE_AUTHENTICATED : web::SECURITY_STYLE_UNAUTHENTICATED;
+  item->GetSSL().security_style = item->GetURL().SchemeIsCryptographic()
+                                      ? web::SECURITY_STYLE_AUTHENTICATED
+                                      : web::SECURITY_STYLE_UNAUTHENTICATED;
   int contentStatus = [_wkWebView hasOnlySecureContent] ?
       web::SSLStatus::NORMAL_CONTENT :
       web::SSLStatus::DISPLAYED_INSECURE_CONTENT;
diff --git a/ios/web/web_thread_adapter.cc b/ios/web/web_thread_adapter.cc
index 016d23d..c0be57c6 100644
--- a/ios/web/web_thread_adapter.cc
+++ b/ios/web/web_thread_adapter.cc
@@ -164,7 +164,7 @@
 }
 
 // static
-scoped_refptr<base::MessageLoopProxy> WebThread::GetMessageLoopProxyForThread(
+scoped_refptr<base::SingleThreadTaskRunner> WebThread::GetTaskRunnerForThread(
     ID identifier) {
   return content::BrowserThread::GetMessageLoopProxyForThread(
       BrowserThreadIDFromWebThreadID(identifier));
diff --git a/ios/web/web_thread_impl.cc b/ios/web/web_thread_impl.cc
index e329bb0..a4cacdd 100644
--- a/ios/web/web_thread_impl.cc
+++ b/ios/web/web_thread_impl.cc
@@ -11,7 +11,7 @@
 #include "base/compiler_specific.h"
 #include "base/lazy_instance.h"
 #include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_restrictions.h"
 #include "ios/web/public/web_thread_delegate.h"
@@ -32,14 +32,13 @@
     "Web_IOThread",                // IO
 };
 
-// An implementation of MessageLoopProxy to be used in conjunction
+// An implementation of SingleThreadTaskRunner to be used in conjunction
 // with WebThread.
-class WebThreadMessageLoopProxy : public base::MessageLoopProxy {
+class WebThreadTaskRunner : public base::SingleThreadTaskRunner {
  public:
-  explicit WebThreadMessageLoopProxy(WebThread::ID identifier)
-      : id_(identifier) {}
+  explicit WebThreadTaskRunner(WebThread::ID identifier) : id_(identifier) {}
 
-  // MessageLoopProxy implementation.
+  // SingleThreadTaskRunner implementation.
   bool PostDelayedTask(const tracked_objects::Location& from_here,
                        const base::Closure& task,
                        base::TimeDelta delay) override {
@@ -57,26 +56,26 @@
   }
 
  protected:
-  ~WebThreadMessageLoopProxy() override {}
+  ~WebThreadTaskRunner() override {}
 
  private:
   WebThread::ID id_;
-  DISALLOW_COPY_AND_ASSIGN(WebThreadMessageLoopProxy);
+  DISALLOW_COPY_AND_ASSIGN(WebThreadTaskRunner);
 };
 
-// A separate helper is used just for the proxies, in order to avoid needing
-// to initialize the globals to create a proxy.
-struct WebThreadProxies {
-  WebThreadProxies() {
+// A separate helper is used just for the task runners, in order to avoid
+// needing to initialize the globals to create a task runner.
+struct WebThreadTaskRunners {
+  WebThreadTaskRunners() {
     for (int i = 0; i < WebThread::ID_COUNT; ++i) {
-      proxies[i] = new WebThreadMessageLoopProxy(static_cast<WebThread::ID>(i));
+      task_runners[i] = new WebThreadTaskRunner(static_cast<WebThread::ID>(i));
     }
   }
 
-  scoped_refptr<base::MessageLoopProxy> proxies[WebThread::ID_COUNT];
+  scoped_refptr<base::SingleThreadTaskRunner> task_runners[WebThread::ID_COUNT];
 };
 
-base::LazyInstance<WebThreadProxies>::Leaky g_proxies =
+base::LazyInstance<WebThreadTaskRunners>::Leaky g_task_runners =
     LAZY_INSTANCE_INITIALIZER;
 
 struct WebThreadGlobals {
@@ -451,7 +450,7 @@
                                  const tracked_objects::Location& from_here,
                                  const base::Closure& task,
                                  const base::Closure& reply) {
-  return GetMessageLoopProxyForThread(identifier)
+  return GetTaskRunnerForThread(identifier)
       ->PostTaskAndReply(from_here, task, reply);
 }
 
@@ -479,9 +478,9 @@
 }
 
 // static
-scoped_refptr<base::MessageLoopProxy> WebThread::GetMessageLoopProxyForThread(
+scoped_refptr<base::SingleThreadTaskRunner> WebThread::GetTaskRunnerForThread(
     ID identifier) {
-  return g_proxies.Get().proxies[identifier];
+  return g_task_runners.Get().task_runners[identifier];
 }
 
 // static
diff --git a/mandoline/BUILD.gn b/mandoline/BUILD.gn
index 1749e490..4395ece8f 100644
--- a/mandoline/BUILD.gn
+++ b/mandoline/BUILD.gn
@@ -31,6 +31,7 @@
       "//components/resource_provider:apptests",
       "//components/resource_provider:tests",
       "//components/view_manager:tests",
+      "//mandoline/tab:mandoline_frame_apptests",
     ]
   }
 }
diff --git a/mandoline/app/android/BUILD.gn b/mandoline/app/android/BUILD.gn
index 7c3c34b..e9a35b8 100644
--- a/mandoline/app/android/BUILD.gn
+++ b/mandoline/app/android/BUILD.gn
@@ -60,12 +60,15 @@
   ]
   sources = [
     "$root_out_dir/core_services.mojo",
-    "$root_out_dir/html_viewer",
     "$root_out_dir/lib.stripped/libbootstrap.so",
     "$root_out_dir/network_service.mojo",
     "$root_out_dir/obj/mojo/runner/bootstrap_java.dex.jar",
     "$root_out_dir/surfaces_service.mojo",
   ]
+
+  # Directories can't be specified as sources so pass manually to the script.
+  args =
+      [ "--files=" + rebase_path("$root_out_dir/html_viewer", root_build_dir) ]
 }
 
 generate_mojo_shell_assets_list("build_mandoline_assets") {
diff --git a/mandoline/app/android/apk/AndroidManifest.xml b/mandoline/app/android/apk/AndroidManifest.xml
index b59b8c9..a4158f1f 100644
--- a/mandoline/app/android/apk/AndroidManifest.xml
+++ b/mandoline/app/android/apk/AndroidManifest.xml
@@ -14,7 +14,7 @@
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
 
     <application android:name="org.chromium.mojo.shell.MojoShellApplication"
-            android:label="Mandoline">
+                 android:label="Mandoline">
         <meta-data android:name="com.google.android.gms.version"
                    android:value="@integer/google_play_services_version" />
         <meta-data android:name="mojo_lib"
@@ -27,6 +27,7 @@
             <intent-filter>
                 <action android:name="android.intent.action.VIEW"/>
                 <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.BROWSABLE"/>
                 <data android:scheme="http"/>
                 <data android:scheme="https"/>
             </intent-filter>
diff --git a/mandoline/services/core_services/core_services_application_delegate.cc b/mandoline/services/core_services/core_services_application_delegate.cc
index c1ca150..3867c55 100644
--- a/mandoline/services/core_services/core_services_application_delegate.cc
+++ b/mandoline/services/core_services/core_services_application_delegate.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/single_thread_task_runner.h"
+#include "base/threading/simple_thread.h"
 #include "components/clipboard/clipboard_application_delegate.h"
 #include "components/filesystem/file_system_app.h"
 #include "components/resource_provider/resource_provider_app.h"
@@ -14,6 +15,7 @@
 #include "mandoline/ui/browser/browser.h"
 #include "mojo/application/public/cpp/application_connection.h"
 #include "mojo/application/public/cpp/application_impl.h"
+#include "mojo/application/public/cpp/application_runner.h"
 #include "mojo/common/message_pump_mojo.h"
 #include "mojo/services/network/network_service_delegate.h"
 #include "mojo/services/tracing/tracing_app.h"
@@ -25,85 +27,51 @@
 
 namespace core_services {
 
-class ApplicationThread;
-
-// A base::Thread which hosts a mojo::ApplicationImpl on its own thread.
-//
-// Why not base::SimpleThread? The comments in SimpleThread discourage its use,
-// and we want most of what base::Thread provides. The hack where we call
-// SetThreadWasQuitProperly() in Run() is already used in the chrome codebase.
-// (By the time we building a base::Thread here, we already have a MessageLoop
-// on our thread, along with a lot of other bookkeeping objects, too. This is
-// why we don't call into ApplicationRunner; we already have an AtExitManager et
-// all at this point.)
-class ApplicationThread : public base::Thread {
+// A helper class for hosting a mojo::ApplicationImpl on its own thread.
+class ApplicationThread : public base::SimpleThread {
  public:
   ApplicationThread(
       const base::WeakPtr<CoreServicesApplicationDelegate>
           core_services_application,
-      const std::string& name,
+      const std::string& url,
       scoped_ptr<mojo::ApplicationDelegate> delegate,
       mojo::InterfaceRequest<mojo::Application> request)
-      : base::Thread(name),
+      : base::SimpleThread(url),
         core_services_application_(core_services_application),
         core_services_application_task_runner_(
             base::MessageLoop::current()->task_runner()),
+        url_(url),
         delegate_(delegate.Pass()),
         request_(request.Pass()) {
   }
 
   ~ApplicationThread() override {
-    Stop();
+    Join();
   }
 
-  // Overridden from base::Thread:
-  void Run(base::MessageLoop* message_loop) override {
-    {
-      application_impl_.reset(new mojo::ApplicationImpl(
-          delegate_.get(), request_.Pass()));
-      base::Thread::Run(message_loop);
-      application_impl_.reset();
+  // Overridden from base::SimpleThread:
+  void Run() override {
+    scoped_ptr<mojo::ApplicationRunner> runner(
+        new mojo::ApplicationRunner(delegate_.release()));
+    if (url_ == "mojo://network_service/") {
+      runner->set_message_loop_type(base::MessageLoop::TYPE_IO);
+    } else if (url_ == "mojo://view_manager/") {
+      runner->set_message_loop_type(base::MessageLoop::TYPE_UI);
     }
-    delegate_.reset();
+    runner->Run(request_.PassMessagePipe().release().value(), false);
 
     core_services_application_task_runner_->PostTask(
         FROM_HERE,
         base::Bind(&CoreServicesApplicationDelegate::ApplicationThreadDestroyed,
                    core_services_application_,
                    this));
-
-    // TODO(erg): This is a hack.
-    //
-    // Right now, most of our services do not receive
-    // Application::RequestQuit() calls. jam@ is currently working on shutting
-    // down everything cleanly. In the long run, we don't wan this here (we
-    // want this set in ShutdownCleanly()), but until we can rely on
-    // RequestQuit() getting delivered we have to manually do this here.
-    //
-    // Remove this ASAP.
-    Thread::SetThreadWasQuitProperly(true);
-  }
-
-  void RequestQuit() {
-    if (!IsRunning())
-      return;
-    task_runner()->PostTask(
-        FROM_HERE,
-        base::Bind(&ApplicationThread::ShutdownCleanly,
-                   base::Unretained(this)));
-
-  }
-
-  void ShutdownCleanly() {
-    application_impl_->QuitNow();
-    Thread::SetThreadWasQuitProperly(true);
   }
 
  private:
   base::WeakPtr<CoreServicesApplicationDelegate> core_services_application_;
   scoped_refptr<base::SingleThreadTaskRunner>
       core_services_application_task_runner_;
-  scoped_ptr<mojo::ApplicationImpl> application_impl_;
+  std::string url_;
   scoped_ptr<mojo::ApplicationDelegate> delegate_;
   mojo::InterfaceRequest<mojo::Application> request_;
 
@@ -135,11 +103,6 @@
 }
 
 void CoreServicesApplicationDelegate::Quit() {
-  // Fire off RequestQuit() messages to all the threads before we try to join
-  // on them.
-  for (ApplicationThread* thread : application_threads_)
-    thread->RequestQuit();
-
   // This will delete all threads. This also performs a blocking join, waiting
   // for the threads to end.
   application_threads_.clear();
@@ -181,24 +144,10 @@
   else
     NOTREACHED() << "This application package does not support " << url;
 
-  base::Thread::Options thread_options;
-
-  // In the case of mojo:network_service, we must use an IO message loop.
-  if (url == "mojo://network_service/") {
-    thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
-  } else if (url == "mojo://view_manager/") {
-    thread_options.message_loop_type = base::MessageLoop::TYPE_UI;
-  } else {
-    // We must use a MessagePumpMojo to awake on mojo messages.
-    thread_options.message_pump_factory =
-        base::Bind(&mojo::common::MessagePumpMojo::Create);
-  }
-
   scoped_ptr<ApplicationThread> thread(
       new ApplicationThread(weak_factory_.GetWeakPtr(), url, delegate.Pass(),
-      request.Pass()));
-  thread->StartWithOptions(thread_options);
-
+                            request.Pass()));
+  thread->Start();
   application_threads_.push_back(thread.Pass());
 }
 
diff --git a/mandoline/services/core_services/core_services_application_delegate.h b/mandoline/services/core_services/core_services_application_delegate.h
index 21e3cb5..5a25cf0 100644
--- a/mandoline/services/core_services/core_services_application_delegate.h
+++ b/mandoline/services/core_services/core_services_application_delegate.h
@@ -8,7 +8,6 @@
 #include "base/macros.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
-#include "base/threading/thread.h"
 #include "components/clipboard/public/interfaces/clipboard.mojom.h"
 #include "mojo/application/public/cpp/application_delegate.h"
 #include "mojo/application/public/cpp/interface_factory_impl.h"
diff --git a/mandoline/tab/BUILD.gn b/mandoline/tab/BUILD.gn
index 664654f..c52d60b 100644
--- a/mandoline/tab/BUILD.gn
+++ b/mandoline/tab/BUILD.gn
@@ -2,18 +2,50 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//testing/test.gni")
+import("//third_party/mojo/src/mojo/public/mojo_application.gni")
+import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
+
 source_set("tab") {
   sources = [
     "frame.cc",
     "frame.h",
+    "frame_services.cc",
+    "frame_services.h",
     "frame_tree.cc",
     "frame_tree.h",
+    "frame_tree_delegate.h",
+    "frame_user_data.h",
   ]
 
   deps = [
     "//base",
     "//components/view_manager/public/cpp",
+    "//mandoline/tab/public/interfaces",
+    "//mojo/application/public/cpp",
     "//mojo/application/public/interfaces",
     "//third_party/mojo/src/mojo/public/cpp/bindings",
   ]
 }
+
+mojo_native_application("mandoline_frame_apptests") {
+  testonly = true
+
+  sources = [
+    "frame_apptest.cc",
+  ]
+
+  deps = [
+    ":tab",
+    "//base",
+    "//base/test:test_config",
+    "//components/view_manager/public/cpp",
+    "//components/view_manager/public/interfaces",
+    "//mandoline/tab/public/interfaces",
+    "//mojo/application/public/cpp:test_support",
+    "//ui/mojo/geometry:interfaces",
+    "//ui/mojo/geometry:util",
+  ]
+
+  data_deps = [ "//components/view_manager" ]
+}
diff --git a/mandoline/tab/DEPS b/mandoline/tab/DEPS
index 48470e7..b13593c5 100644
--- a/mandoline/tab/DEPS
+++ b/mandoline/tab/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+components/view_manager/public",
   "+mojo/application/public",
+  "+third_party/mojo/src/mojo/public",
 ]
diff --git a/mandoline/tab/frame.cc b/mandoline/tab/frame.cc
index 8928e0d..e987697 100644
--- a/mandoline/tab/frame.cc
+++ b/mandoline/tab/frame.cc
@@ -10,6 +10,8 @@
 #include "components/view_manager/public/cpp/view.h"
 #include "components/view_manager/public/cpp/view_property.h"
 #include "mandoline/tab/frame_tree.h"
+#include "mandoline/tab/frame_tree_delegate.h"
+#include "mandoline/tab/frame_user_data.h"
 
 using mojo::View;
 
@@ -20,38 +22,66 @@
 // Used to find the Frame associated with a View.
 DEFINE_LOCAL_VIEW_PROPERTY_KEY(Frame*, kFrame, nullptr);
 
+namespace {
+
+const uint32_t kNoParentId = 0u;
+
+FrameDataPtr FrameToFrameData(const Frame* frame) {
+  FrameDataPtr frame_data(FrameData::New());
+  frame_data->frame_id = frame->view()->id();
+  frame_data->parent_id =
+      frame->parent() ? frame->parent()->view()->id() : kNoParentId;
+  return frame_data.Pass();
+}
+
+}  // namespace
+
 Frame::Frame(FrameTree* tree,
              View* view,
              ViewOwnership view_ownership,
-             mojo::InterfaceRequest<mojo::ServiceProvider>* services,
-             mojo::ServiceProviderPtr* exposed_services)
+             FrameTreeClient* frame_tree_client,
+             scoped_ptr<FrameUserData> user_data)
     : tree_(tree),
       view_(view),
       parent_(nullptr),
-      view_ownership_(view_ownership) {
+      view_ownership_(view_ownership),
+      frame_user_data_(user_data.Pass()),
+      frame_tree_client_(frame_tree_client),
+      frame_tree_server_binding_(this) {
   view_->SetLocalProperty(kFrame, this);
   view_->AddObserver(this);
-
-  if (services)
-    *services = GetProxy(&services_).Pass();
-
-  if (exposed_services) {
-    mojo::ServiceProviderPtr exposed_services_ptr;
-    exposed_services_.Bind(GetProxy(&exposed_services_ptr));
-    *exposed_services = exposed_services_ptr.Pass();
-  }
 }
 
 Frame::~Frame() {
-  view_->RemoveObserver(this);
-  STLDeleteElements(&children_);
+  if (view_)
+    view_->RemoveObserver(this);
+  while (!children_.empty())
+    delete children_[0];
   if (parent_)
     parent_->Remove(this);
-  view_->ClearLocalProperty(kFrame);
+  if (view_)
+    view_->ClearLocalProperty(kFrame);
   if (view_ownership_ == ViewOwnership::OWNS_VIEW)
     view_->Destroy();
 }
 
+void Frame::Init(Frame* parent) {
+  if (parent)
+    parent->Add(this);
+
+  std::vector<const Frame*> frames;
+  tree_->root()->BuildFrameTree(&frames);
+
+  mojo::Array<FrameDataPtr> array(frames.size());
+  for (size_t i = 0; i < frames.size(); ++i)
+    array[i] = FrameToFrameData(frames[i]).Pass();
+
+  // TODO(sky): error handling.
+  FrameTreeServerPtr frame_tree_server_ptr;
+  frame_tree_server_binding_.Bind(GetProxy(&frame_tree_server_ptr).Pass());
+  frame_tree_client_->OnConnect(frame_tree_server_ptr.Pass(), array.Pass());
+}
+
 // static
 Frame* Frame::FindFirstFrameAncestor(View* view) {
   while (view && !view->GetLocalProperty(kFrame))
@@ -59,12 +89,31 @@
   return view ? view->GetLocalProperty(kFrame) : nullptr;
 }
 
+const Frame* Frame::FindFrame(uint32_t id) const {
+  if (id == view_->id())
+    return this;
+
+  for (const Frame* child : children_) {
+    const Frame* match = child->FindFrame(id);
+    if (match)
+      return match;
+  }
+  return nullptr;
+}
+
+void Frame::BuildFrameTree(std::vector<const Frame*>* frames) const {
+  frames->push_back(this);
+  for (const Frame* frame : children_)
+    frame->BuildFrameTree(frames);
+}
+
 void Frame::Add(Frame* node) {
-  if (node->parent_)
-    node->parent_->Remove(node);
+  DCHECK(!node->parent_);
 
   node->parent_ = this;
   children_.push_back(node);
+
+  tree_->root()->NotifyAdded(this, node);
 }
 
 void Frame::Remove(Frame* node) {
@@ -73,21 +122,67 @@
   DCHECK(iter != children_.end());
   node->parent_ = nullptr;
   children_.erase(iter);
+
+  tree_->root()->NotifyRemoved(this, node);
+}
+
+void Frame::NotifyAdded(const Frame* source, const Frame* added_node) {
+  if (added_node == this)
+    return;
+
+  if (source != this)
+    frame_tree_client_->OnFrameAdded(FrameToFrameData(added_node));
+
+  for (Frame* child : children_)
+    child->NotifyAdded(source, added_node);
+}
+
+void Frame::NotifyRemoved(const Frame* source, const Frame* removed_node) {
+  if (removed_node == this)
+    return;
+
+  if (source != this)
+    frame_tree_client_->OnFrameRemoved(removed_node->view_->id());
+
+  for (Frame* child : children_)
+    child->NotifyRemoved(source, removed_node);
 }
 
 void Frame::OnViewDestroying(mojo::View* view) {
   if (parent_)
     parent_->Remove(this);
-  // Assume the view associated with the root is never deleted out from under
-  // us.
-  // TODO(sky): this is likely bogus. Change browser to create a child for
-  // each FrameTree.
-  DCHECK_NE(this, tree_->root());
 
   // Reset |view_ownership_| so we don't attempt to delete |view_| in the
   // destructor.
   view_ownership_ = ViewOwnership::DOESNT_OWN_VIEW;
+
+  // Assume the view associated with the root is never deleted out from under
+  // us.
+  // TODO(sky): Change browser to create a child for each FrameTree.
+  if (tree_->root() == this) {
+    view_->RemoveObserver(this);
+    view_ = nullptr;
+    return;
+  }
+
   delete this;
 }
 
+void Frame::PostMessageEventToFrame(uint32_t frame_id, MessageEventPtr event) {
+  Frame* target = tree_->root()->FindFrame(frame_id);
+  if (!target ||
+      !tree_->delegate_->CanPostMessageEventToFrame(this, target, event.get()))
+    return;
+
+  NOTIMPLEMENTED();
+}
+
+void Frame::NavigateFrame(uint32_t frame_id) {
+  NOTIMPLEMENTED();
+}
+
+void Frame::ReloadFrame(uint32_t frame_id) {
+  NOTIMPLEMENTED();
+}
+
 }  // namespace mandoline
diff --git a/mandoline/tab/frame.h b/mandoline/tab/frame.h
index 1771f02..cd81d20 100644
--- a/mandoline/tab/frame.h
+++ b/mandoline/tab/frame.h
@@ -8,12 +8,16 @@
 #include <vector>
 
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 #include "components/view_manager/public/cpp/view_observer.h"
-#include "mojo/application/public/cpp/service_provider_impl.h"
+#include "mandoline/tab/public/interfaces/frame_tree.mojom.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
 
 namespace mandoline {
 
 class FrameTree;
+class FrameTreeClient;
+class FrameUserData;
 
 enum class ViewOwnership {
   OWNS_VIEW,
@@ -23,15 +27,17 @@
 // Frame represents an embedding in a frame. Frames own their children.
 // Frames automatically delete themself if the View the frame is associated
 // with is deleted.
-class Frame : public mojo::ViewObserver {
+class Frame : public mojo::ViewObserver, public FrameTreeServer {
  public:
   Frame(FrameTree* tree,
         mojo::View* view,
         ViewOwnership view_ownership,
-        mojo::InterfaceRequest<mojo::ServiceProvider>* services,
-        mojo::ServiceProviderPtr* exposed_services);
+        FrameTreeClient* frame_tree_client,
+        scoped_ptr<FrameUserData> user_data);
   ~Frame() override;
 
+  void Init(Frame* parent);
+
   // Walks the View tree starting at |view| going up returning the first
   // Frame that is associated with a view. For example, if |view|
   // has a Frame associated with it, then that is returned. Otherwise
@@ -41,23 +47,52 @@
   FrameTree* tree() { return tree_; }
 
   Frame* parent() { return parent_; }
+  const Frame* parent() const { return parent_; }
 
   mojo::View* view() { return view_; }
+  const mojo::View* view() const { return view_; }
+
+  // Finds the descendant with the specified id.
+  Frame* FindFrame(uint32_t id) {
+    return const_cast<Frame*>(const_cast<const Frame*>(this)->FindFrame(id));
+  }
+  const Frame* FindFrame(uint32_t id) const;
+
+  FrameUserData* user_data();
+
+ private:
+  friend class FrameTree;
+
+  // Adds this to |frames| and recurses through the children calling the
+  // same function.
+  void BuildFrameTree(std::vector<const Frame*>* frames) const;
 
   void Add(Frame* node);
   void Remove(Frame* node);
 
- private:
+  // Notifies the client and all descendants as appropriate.
+  void NotifyAdded(const Frame* source, const Frame* added_node);
+  void NotifyRemoved(const Frame* source, const Frame* removed_node);
+
   // mojo::ViewObserver:
   void OnViewDestroying(mojo::View* view) override;
 
+  // FrameTreeServer:
+  void PostMessageEventToFrame(uint32_t frame_id,
+                               MessageEventPtr event) override;
+  void NavigateFrame(uint32_t frame_id) override;
+  void ReloadFrame(uint32_t frame_id) override;
+
   FrameTree* const tree_;
-  mojo::View* const view_;
+  mojo::View* view_;
   Frame* parent_;
   ViewOwnership view_ownership_;
-  mojo::ServiceProviderImpl exposed_services_;
-  mojo::ServiceProviderPtr services_;
   std::vector<Frame*> children_;
+  scoped_ptr<FrameUserData> frame_user_data_;
+
+  FrameTreeClient* frame_tree_client_;
+
+  mojo::Binding<FrameTreeServer> frame_tree_server_binding_;
 
   DISALLOW_COPY_AND_ASSIGN(Frame);
 };
diff --git a/mandoline/tab/frame_apptest.cc b/mandoline/tab/frame_apptest.cc
new file mode 100644
index 0000000..4c1ec9d47
--- /dev/null
+++ b/mandoline/tab/frame_apptest.cc
@@ -0,0 +1,222 @@
+// 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 "mandoline/tab/frame.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/test/test_timeouts.h"
+#include "components/view_manager/public/cpp/lib/view_manager_client_impl.h"
+#include "components/view_manager/public/cpp/view_manager_client_factory.h"
+#include "components/view_manager/public/cpp/view_manager_delegate.h"
+#include "components/view_manager/public/cpp/view_manager_init.h"
+#include "components/view_manager/public/cpp/view_observer.h"
+#include "mandoline/tab/frame.h"
+#include "mandoline/tab/frame_tree.h"
+#include "mandoline/tab/frame_tree_delegate.h"
+#include "mandoline/tab/frame_user_data.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/application_test_base.h"
+#include "mojo/application/public/cpp/service_provider_impl.h"
+
+using mojo::View;
+using mojo::ViewManager;
+
+namespace mandoline {
+
+namespace {
+
+base::RunLoop* current_run_loop = nullptr;
+
+void TimeoutRunLoop(const base::Closure& timeout_task, bool* timeout) {
+  CHECK(current_run_loop);
+  *timeout = true;
+  timeout_task.Run();
+}
+
+bool DoRunLoopWithTimeout() {
+  if (current_run_loop != nullptr)
+    return false;
+
+  bool timeout = false;
+  base::RunLoop run_loop;
+  base::MessageLoop::current()->PostDelayedTask(
+      FROM_HERE, base::Bind(&TimeoutRunLoop, run_loop.QuitClosure(), &timeout),
+      TestTimeouts::action_timeout());
+
+  current_run_loop = &run_loop;
+  current_run_loop->Run();
+  current_run_loop = nullptr;
+  return !timeout;
+}
+
+void QuitRunLoop() {
+  current_run_loop->Quit();
+  current_run_loop = nullptr;
+}
+
+}  // namespace
+
+class FrameTest : public mojo::test::ApplicationTestBase,
+                  public mojo::ApplicationDelegate,
+                  public mojo::ViewManagerDelegate {
+ public:
+  FrameTest() : most_recent_view_manager_(nullptr), window_manager_(nullptr) {}
+
+  ViewManager* most_recent_view_manager() { return most_recent_view_manager_; }
+
+  // Overridden from ApplicationDelegate:
+  void Initialize(mojo::ApplicationImpl* app) override {
+    view_manager_client_factory_.reset(
+        new mojo::ViewManagerClientFactory(app->shell(), this));
+  }
+
+  // ApplicationDelegate implementation.
+  bool ConfigureIncomingConnection(
+      mojo::ApplicationConnection* connection) override {
+    connection->AddService(view_manager_client_factory_.get());
+    return true;
+  }
+
+  ViewManager* window_manager() { return window_manager_; }
+
+  // ApplicationTestBase:
+  ApplicationDelegate* GetApplicationDelegate() override { return this; }
+
+  // Overridden from ViewManagerDelegate:
+  void OnEmbed(View* root,
+               mojo::InterfaceRequest<mojo::ServiceProvider> services,
+               mojo::ServiceProviderPtr exposed_services) override {
+    most_recent_view_manager_ = root->view_manager();
+    QuitRunLoop();
+  }
+  void OnViewManagerDestroyed(ViewManager* view_manager) override {}
+
+ private:
+  // Overridden from testing::Test:
+  void SetUp() override {
+    ApplicationTestBase::SetUp();
+
+    view_manager_init_.reset(
+        new mojo::ViewManagerInit(application_impl(), this, nullptr));
+    ASSERT_TRUE(DoRunLoopWithTimeout());
+    std::swap(window_manager_, most_recent_view_manager_);
+  }
+
+  // Overridden from testing::Test:
+  void TearDown() override {
+    view_manager_init_.reset();  // Uses application_impl() from base class.
+    ApplicationTestBase::TearDown();
+  }
+
+  scoped_ptr<mojo::ViewManagerInit> view_manager_init_;
+
+  scoped_ptr<mojo::ViewManagerClientFactory> view_manager_client_factory_;
+
+  // Used to receive the most recent view manager loaded by an embed action.
+  ViewManager* most_recent_view_manager_;
+  // The View Manager connection held by the window manager (app running at the
+  // root view).
+  ViewManager* window_manager_;
+
+  MOJO_DISALLOW_COPY_AND_ASSIGN(FrameTest);
+};
+
+class TestFrameTreeDelegate : public FrameTreeDelegate {
+ public:
+  TestFrameTreeDelegate() {}
+  ~TestFrameTreeDelegate() override {}
+
+  // TestFrameTreeDelegate:
+  bool CanPostMessageEventToFrame(const Frame* source,
+                                  const Frame* target,
+                                  MessageEvent* event) override {
+    return false;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestFrameTreeDelegate);
+};
+
+class TestFrameTreeClient : public FrameTreeClient {
+ public:
+  TestFrameTreeClient() : connect_count_(0) {}
+  ~TestFrameTreeClient() override {}
+
+  int connect_count() const { return connect_count_; }
+
+  mojo::Array<FrameDataPtr> connect_frames() { return connect_frames_.Pass(); }
+
+  mojo::Array<FrameDataPtr> adds() { return adds_.Pass(); }
+
+  // TestFrameTreeClient:
+  void OnConnect(FrameTreeServerPtr server,
+                 mojo::Array<FrameDataPtr> frames) override {
+    connect_count_++;
+    connect_frames_ = frames.Pass();
+    server_ = server.Pass();
+  }
+  void OnFrameAdded(FrameDataPtr frame) override {
+    adds_.push_back(frame.Pass());
+  }
+  void OnFrameRemoved(uint32_t frame_id) override {}
+
+ private:
+  int connect_count_;
+  mojo::Array<FrameDataPtr> connect_frames_;
+  FrameTreeServerPtr server_;
+  mojo::Array<FrameDataPtr> adds_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestFrameTreeClient);
+};
+
+// Verifies the root gets a connect.
+TEST_F(FrameTest, RootGetsConnect) {
+  TestFrameTreeDelegate tree_delegate;
+  TestFrameTreeClient root_client;
+  FrameTree tree(window_manager()->GetRoot(), &tree_delegate, &root_client,
+                 nullptr);
+  ASSERT_EQ(1, root_client.connect_count());
+  mojo::Array<FrameDataPtr> frames = root_client.connect_frames();
+  ASSERT_EQ(1u, frames.size());
+  EXPECT_EQ(tree.root()->view()->id(), frames[0]->frame_id);
+  EXPECT_EQ(0u, frames[0]->parent_id);
+}
+
+// Verifies adding a child to the root.
+TEST_F(FrameTest, SingleChild) {
+  TestFrameTreeDelegate tree_delegate;
+  TestFrameTreeClient root_client;
+  FrameTree tree(window_manager()->GetRoot(), &tree_delegate, &root_client,
+                 nullptr);
+
+  View* child = window_manager()->CreateView();
+  EXPECT_EQ(nullptr, Frame::FindFirstFrameAncestor(child));
+  window_manager()->GetRoot()->AddChild(child);
+  EXPECT_EQ(tree.root(), Frame::FindFirstFrameAncestor(child));
+
+  TestFrameTreeClient child_client;
+  Frame* child_frame =
+      tree.CreateAndAddFrame(child, tree.root(), &child_client, nullptr);
+  EXPECT_EQ(tree.root(), child_frame->parent());
+
+  ASSERT_EQ(1, child_client.connect_count());
+  mojo::Array<FrameDataPtr> frames_in_child = child_client.connect_frames();
+  // We expect 2 frames. One for the root, one for the child.
+  ASSERT_EQ(2u, frames_in_child.size());
+  EXPECT_EQ(tree.root()->view()->id(), frames_in_child[0]->frame_id);
+  EXPECT_EQ(0u, frames_in_child[0]->parent_id);
+  EXPECT_EQ(child_frame->view()->id(), frames_in_child[1]->frame_id);
+  EXPECT_EQ(tree.root()->view()->id(), frames_in_child[1]->parent_id);
+
+  // The root did the add, so it shouldn't get an add.
+  EXPECT_EQ(0u, root_client.adds().size());
+}
+
+}  // namespace mandoline
diff --git a/mandoline/tab/frame_services.cc b/mandoline/tab/frame_services.cc
new file mode 100644
index 0000000..ea64a41
--- /dev/null
+++ b/mandoline/tab/frame_services.cc
@@ -0,0 +1,31 @@
+// 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 "mandoline/tab/frame_services.h"
+
+#include "mojo/application/public/cpp/connect.h"
+
+namespace mandoline {
+
+FrameServices::FrameServices() {
+}
+
+FrameServices::~FrameServices() {
+}
+
+void FrameServices::Init(
+    mojo::InterfaceRequest<mojo::ServiceProvider>* services,
+    mojo::ServiceProviderPtr* exposed_services) {
+  *services = GetProxy(&services_).Pass();
+
+  if (exposed_services) {
+    mojo::ServiceProviderPtr exposed_services_ptr;
+    exposed_services_.Bind(GetProxy(&exposed_services_ptr));
+    *exposed_services = exposed_services_ptr.Pass();
+  }
+
+  mojo::ConnectToService(services_.get(), &frame_tree_client_);
+}
+
+}  // namespace mandoline
diff --git a/mandoline/tab/frame_services.h b/mandoline/tab/frame_services.h
new file mode 100644
index 0000000..fc7ea654
--- /dev/null
+++ b/mandoline/tab/frame_services.h
@@ -0,0 +1,38 @@
+// 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 MANDOLINE_TAB_FRAME_SERVICES_H_
+#define MANDOLINE_TAB_FRAME_SERVICES_H_
+
+#include "base/basictypes.h"
+#include "mandoline/tab/frame_user_data.h"
+#include "mandoline/tab/public/interfaces/frame_tree.mojom.h"
+#include "mojo/application/public/cpp/service_provider_impl.h"
+
+namespace mandoline {
+
+// FrameServices is a FrameUserData that manages the ServiceProviders exposed
+// to each client. It is also responsible for obtaining the FrameTreeClient
+// from the remote side.
+class FrameServices : public FrameUserData {
+ public:
+  FrameServices();
+  ~FrameServices() override;
+
+  void Init(mojo::InterfaceRequest<mojo::ServiceProvider>* services,
+            mojo::ServiceProviderPtr* exposed_services);
+
+  FrameTreeClient* frame_tree_client() { return frame_tree_client_.get(); }
+
+ private:
+  mojo::ServiceProviderImpl exposed_services_;
+  mojo::ServiceProviderPtr services_;
+  FrameTreeClientPtr frame_tree_client_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameServices);
+};
+
+}  // namespace mandoline
+
+#endif  // MANDOLINE_TAB_FRAME_SERVICES_H_
diff --git a/mandoline/tab/frame_tree.cc b/mandoline/tab/frame_tree.cc
index 88c62697..b833a590 100644
--- a/mandoline/tab/frame_tree.cc
+++ b/mandoline/tab/frame_tree.cc
@@ -4,14 +4,35 @@
 
 #include "mandoline/tab/frame_tree.h"
 
+#include "mandoline/tab/frame_user_data.h"
+
 namespace mandoline {
 
-FrameTree::FrameTree(mojo::View* view)
+FrameTree::FrameTree(mojo::View* view,
+                     FrameTreeDelegate* delegate,
+                     FrameTreeClient* root_client,
+                     scoped_ptr<FrameUserData> user_data)
     : view_(view),
-      root_(this, view, ViewOwnership::DOESNT_OWN_VIEW, nullptr, nullptr) {
+      delegate_(delegate),
+      root_(this,
+            view,
+            ViewOwnership::DOESNT_OWN_VIEW,
+            root_client,
+            user_data.Pass()) {
+  root_.Init(nullptr);
 }
 
 FrameTree::~FrameTree() {
 }
 
+Frame* FrameTree::CreateAndAddFrame(mojo::View* view,
+                                    Frame* parent,
+                                    FrameTreeClient* client,
+                                    scoped_ptr<FrameUserData> user_data) {
+  Frame* frame =
+      new Frame(this, view, ViewOwnership::OWNS_VIEW, client, user_data.Pass());
+  frame->Init(parent);
+  return frame;
+}
+
 }  // namespace mandoline
diff --git a/mandoline/tab/frame_tree.h b/mandoline/tab/frame_tree.h
index 16d3591..6d216985 100644
--- a/mandoline/tab/frame_tree.h
+++ b/mandoline/tab/frame_tree.h
@@ -9,6 +9,10 @@
 
 namespace mandoline {
 
+class FrameTreeClient;
+class FrameTreeDelegate;
+class FrameUserData;
+
 // FrameTree manages the set of Frames that comprise a single url. FrameTree
 // owns the root Frame and each Frames owns its children. Frames are
 // automatically deleted and removed from the tree if the corresponding view is
@@ -18,14 +22,26 @@
  public:
   // |view| is the view to do the initial embedding in. It is assumed |view|
   // outlives FrameTree.
-  explicit FrameTree(mojo::View* view);
+  FrameTree(mojo::View* view,
+            FrameTreeDelegate* delegate,
+            FrameTreeClient* root_client,
+            scoped_ptr<FrameUserData> user_data);
   ~FrameTree();
 
   Frame* root() { return &root_; }
 
+  Frame* CreateAndAddFrame(mojo::View* view,
+                           Frame* parent,
+                           FrameTreeClient* client,
+                           scoped_ptr<FrameUserData> user_data);
+
  private:
+  friend class Frame;
+
   mojo::View* view_;
 
+  FrameTreeDelegate* delegate_;
+
   Frame root_;
 
   DISALLOW_COPY_AND_ASSIGN(FrameTree);
diff --git a/mandoline/tab/frame_tree_delegate.h b/mandoline/tab/frame_tree_delegate.h
new file mode 100644
index 0000000..f35a89e
--- /dev/null
+++ b/mandoline/tab/frame_tree_delegate.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 MANDOLINE_TAB_FRAME_TREE_DELEGATE_H_
+#define MANDOLINE_TAB_FRAME_TREE_DELEGATE_H_
+
+namespace mandoline {
+
+class MessageEvent;
+
+class FrameTreeDelegate {
+ public:
+  virtual bool CanPostMessageEventToFrame(const Frame* source,
+                                          const Frame* target,
+                                          MessageEvent* event) = 0;
+
+ protected:
+  virtual ~FrameTreeDelegate() {}
+};
+
+}  // namespace mandoline
+
+#endif  // MANDOLINE_TAB_FRAME_TREE_DELEGATE_H_
diff --git a/mandoline/tab/frame_user_data.h b/mandoline/tab/frame_user_data.h
new file mode 100644
index 0000000..9afe216
--- /dev/null
+++ b/mandoline/tab/frame_user_data.h
@@ -0,0 +1,18 @@
+// 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 MANDOLINE_TAB_FRAME_USER_DATA_H_
+#define MANDOLINE_TAB_FRAME_USER_DATA_H_
+
+namespace mandoline {
+
+// Arbitrary data that may be associated with each frame.
+class FrameUserData {
+ public:
+  virtual ~FrameUserData() {}
+};
+
+}  // namespace mandoline
+
+#endif  // MANDOLINE_TAB_FRAME_USER_DATA_H_
diff --git a/mandoline/tab/public/interfaces/BUILD.gn b/mandoline/tab/public/interfaces/BUILD.gn
new file mode 100644
index 0000000..d106440a
--- /dev/null
+++ b/mandoline/tab/public/interfaces/BUILD.gn
@@ -0,0 +1,11 @@
+# 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("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+  sources = [
+    "frame_tree.mojom",
+  ]
+}
diff --git a/mandoline/tab/public/interfaces/frame_tree.mojom b/mandoline/tab/public/interfaces/frame_tree.mojom
new file mode 100644
index 0000000..8a2fd6f
--- /dev/null
+++ b/mandoline/tab/public/interfaces/frame_tree.mojom
@@ -0,0 +1,50 @@
+// 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 mandoline;
+
+// This files defines the interfaces and structures used for frames.
+//
+// When a client in the frame tree is connected to by way of the ViewManager a
+// FrameTreeClient is obtained (from the ServiceProvider interface request
+// passed in ViewManager::OnEmbed()). The FrameTreeClient is told the frame
+// tree (by way of OnConnection()), which allows the client to use other
+// frames in the tree (assuming the client has the appropriate permissions).
+//
+// frame_ids are the same as views ids. This means that when a client creates
+// a new view to be part of the frame tree it immediately knows the id to use
+// for FrameTreeServer calls.
+// TODO(sky): there are likely timing issues here, figure out how to resolve
+// that.
+
+// Provides information about a frame.
+struct FrameData {
+  // 0 if the frame has no parent (its the root).
+  uint32 parent_id;
+  uint32 frame_id;
+};
+
+struct MessageEvent {
+  // TODO(sky): add details.
+};
+
+interface FrameTreeServer {
+  // TODO(sky): make these real.
+  PostMessageEventToFrame(uint32 frame_id, MessageEvent event);
+  NavigateFrame(uint32 frame_id);
+  ReloadFrame(uint32 frame_id);
+};
+
+interface FrameTreeClient {
+  // Called once per client. |frames| gives the contents of the tree.
+  OnConnect(FrameTreeServer server, array<FrameData> frames);
+
+  // Called when a new frame is added to the tree. This is not called on the
+  // originator of the change.
+  OnFrameAdded(FrameData frame);
+
+  // Called when a frame is removed from the tree. This is not called on the
+  // originator of the change.
+  OnFrameRemoved(uint32 frame_id);
+};
diff --git a/mandoline/tools/android_run_mandoline.py b/mandoline/tools/android_run_mandoline.py
index d5540a4..71ac9ad3 100755
--- a/mandoline/tools/android_run_mandoline.py
+++ b/mandoline/tools/android_run_mandoline.py
@@ -9,7 +9,7 @@
 import sys
 
 sys.path.insert(0, os.path.join(os.path.abspath(os.path.dirname(__file__)),
-                                '../../mojo/tools'))
+                                os.pardir, os.pardir, 'mojo', 'tools'))
 
 from mopy.android import AndroidShell
 from mopy.config import Config
@@ -38,9 +38,7 @@
                   is_debug=runner_args.debug,
                   apk_name="Mandoline.apk")
   shell = AndroidShell(config)
-  args.extend(shell.PrepareShellRun(None, runner_args.device, runner_args.gdb))
-
-  shell.CleanLogs()
+  shell.InitShell(None, runner_args.device)
   p = shell.ShowLogs()
   shell.StartShell(args, sys.stdout, p.terminate, runner_args.gdb)
   return 0
diff --git a/mandoline/ui/browser/browser.cc b/mandoline/ui/browser/browser.cc
index fb525ce..50c774c4 100644
--- a/mandoline/ui/browser/browser.cc
+++ b/mandoline/ui/browser/browser.cc
@@ -9,6 +9,7 @@
 #include "components/view_manager/public/cpp/view.h"
 #include "components/view_manager/public/cpp/view_manager_init.h"
 #include "mandoline/tab/frame.h"
+#include "mandoline/tab/frame_services.h"
 #include "mandoline/tab/frame_tree.h"
 #include "mandoline/ui/browser/browser_ui.h"
 #include "mandoline/ui/browser/merged_service_provider.h"
@@ -140,9 +141,11 @@
     frame = nullptr;
   }
 
-  Frame* child_frame = new Frame(frame->tree(), view, ViewOwnership::OWNS_VIEW,
-                                 services, exposed_services);
-  parent->Add(child_frame);
+  scoped_ptr<FrameServices> frame_services(new FrameServices);
+  frame_services->Init(services, exposed_services);
+  FrameTreeClient* frame_tree_client = frame_services->frame_tree_client();
+  frame_tree_->CreateAndAddFrame(view, parent, frame_tree_client,
+                                 frame_services.Pass());
   return true;
 }
 
@@ -188,10 +191,15 @@
   if (changed)
     ui_->OnURLChanged();
 
-  // TODO(sky): move serviceproviders to frame tree.
-  frame_tree_.reset(new FrameTree(content_));
   merged_service_provider_.reset(
       new MergedServiceProvider(exposed_services.Pass(), this));
+  scoped_ptr<FrameServices> frame_services(new FrameServices);
+  // TODO(sky): FrameServices and MergedServiceProvider need to be combined.
+  // TODO(sky): FrameServices needs to man in the middle services.
+  frame_services->Init(&services, nullptr);
+  FrameTreeClient* frame_tree_client = frame_services->frame_tree_client();
+  frame_tree_.reset(new FrameTree(content_, nullptr, frame_tree_client,
+                                  frame_services.Pass()));
   content_->Embed(request.Pass(), services.Pass(),
                   merged_service_provider_->GetServiceProviderPtr().Pass());
 
diff --git a/media/audio/pulse/pulse.sigs b/media/audio/pulse/pulse.sigs
index b9c8088..522efcb5 100644
--- a/media/audio/pulse/pulse.sigs
+++ b/media/audio/pulse/pulse.sigs
@@ -16,6 +16,7 @@
 void pa_threaded_mainloop_unlock(pa_threaded_mainloop* m);
 void pa_threaded_mainloop_wait(pa_threaded_mainloop* m);
 pa_channel_map* pa_channel_map_init(pa_channel_map* m);
+pa_channel_map* pa_channel_map_init_mono(pa_channel_map* m);
 int pa_context_connect(pa_context* c, const char* server, pa_context_flags_t flags, const pa_spawn_api* api);
 void pa_context_disconnect(pa_context* c);
 pa_operation* pa_context_get_server_info(pa_context* c, pa_server_info_cb_t cb, void* userdata);
diff --git a/media/audio/pulse/pulse_util.cc b/media/audio/pulse/pulse_util.cc
index 7e579d5..ee37c03 100644
--- a/media/audio/pulse/pulse_util.cc
+++ b/media/audio/pulse/pulse_util.cc
@@ -99,16 +99,22 @@
 
 pa_channel_map ChannelLayoutToPAChannelMap(ChannelLayout channel_layout) {
   pa_channel_map channel_map;
-  pa_channel_map_init(&channel_map);
+  if (channel_layout == CHANNEL_LAYOUT_MONO) {
+    // CHANNEL_LAYOUT_MONO only specifies audio on the C channel, but we
+    // want PulseAudio to play single-channel audio on more than just that.
+    pa_channel_map_init_mono(&channel_map);
+  } else {
+    pa_channel_map_init(&channel_map);
 
-  channel_map.channels = ChannelLayoutToChannelCount(channel_layout);
-  for (Channels ch = LEFT; ch <= CHANNELS_MAX;
-       ch = static_cast<Channels>(ch + 1)) {
-    int channel_index = ChannelOrder(channel_layout, ch);
-    if (channel_index < 0)
-      continue;
+    channel_map.channels = ChannelLayoutToChannelCount(channel_layout);
+    for (Channels ch = LEFT; ch <= CHANNELS_MAX;
+         ch = static_cast<Channels>(ch + 1)) {
+      int channel_index = ChannelOrder(channel_layout, ch);
+      if (channel_index < 0)
+        continue;
 
-    channel_map.map[channel_index] = ChromiumToPAChannelPosition(ch);
+      channel_map.map[channel_index] = ChromiumToPAChannelPosition(ch);
+    }
   }
 
   return channel_map;
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index d81171e..29547f3d 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -272,11 +272,13 @@
   }
 
   if (current_cpu == "x86" || current_cpu == "x64") {
-    sources += [ "simd/convert_yuv_to_rgb_x86.cc" ]
-    deps += [
-      ":media_yasm",
-      ":media_sse2",
+    sources += [
+      "simd/convert_rgb_to_yuv_sse2.cc",
+      "simd/convert_rgb_to_yuv_ssse3.cc",
+      "simd/convert_yuv_to_rgb_x86.cc",
+      "simd/filter_yuv_sse2.cc",
     ]
+    deps += [ ":media_yasm" ]
   }
 
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
@@ -464,21 +466,6 @@
 }
 
 if (current_cpu == "x86" || current_cpu == "x64") {
-  source_set("media_sse2") {
-    sources = [
-      "simd/convert_rgb_to_yuv_sse2.cc",
-      "simd/convert_rgb_to_yuv_ssse3.cc",
-      "simd/filter_yuv_sse2.cc",
-    ]
-    configs += [
-      "//media:media_config",
-      "//media:media_implementation",
-    ]
-    if (!is_win) {
-      cflags = [ "-msse2" ]
-    }
-  }
-
   import("//third_party/yasm/yasm_assemble.gni")
   yasm_assemble("media_yasm") {
     sources = [
diff --git a/media/base/audio_buffer.cc b/media/base/audio_buffer.cc
index 3eff804..f07ed6dc 100644
--- a/media/base/audio_buffer.cc
+++ b/media/base/audio_buffer.cc
@@ -4,6 +4,8 @@
 
 #include "media/base/audio_buffer.h"
 
+#include <cmath>
+
 #include "base/logging.h"
 #include "media/base/audio_bus.h"
 #include "media/base/buffers.h"
@@ -162,12 +164,52 @@
                                             kNoTimestamp()));
 }
 
+template <typename Target, typename Dest>
+static inline Dest ConvertSample(Target value);
+
 // Convert int16 values in the range [INT16_MIN, INT16_MAX] to [-1.0, 1.0].
-static inline float ConvertS16ToFloat(int16 value) {
+template <>
+inline float ConvertSample<int16, float>(int16 value) {
   return value * (value < 0 ? -1.0f / std::numeric_limits<int16>::min()
                             : 1.0f / std::numeric_limits<int16>::max());
 }
 
+// Specializations for int32
+template <>
+inline int32 ConvertSample<int16, int32>(int16 value) {
+  return static_cast<int32>(value) << 16;
+}
+
+template <>
+inline int32 ConvertSample<int32, int32>(int32 value) {
+  return value;
+}
+
+template <>
+inline int32 ConvertSample<float, int32>(float value) {
+  return static_cast<int32>(value < 0
+                                ? (-value) * std::numeric_limits<int32>::min()
+                                : value * std::numeric_limits<int32>::max());
+}
+
+// Specializations for int16
+template <>
+inline int16 ConvertSample<int16, int16>(int16 sample) {
+  return sample;
+}
+
+template <>
+inline int16 ConvertSample<int32, int16>(int32 sample) {
+  return sample >> 16;
+}
+
+template <>
+inline int16 ConvertSample<float, int16>(float sample) {
+  return static_cast<int16>(
+      nearbyint(sample < 0 ? (-sample) * std::numeric_limits<int16>::min()
+                           : sample * std::numeric_limits<int16>::max()));
+}
+
 void AudioBuffer::ReadFrames(int frames_to_copy,
                              int source_frame_offset,
                              int dest_frame_offset,
@@ -213,7 +255,7 @@
           source_frame_offset;
       float* dest_data = dest->channel(ch) + dest_frame_offset;
       for (int i = 0; i < frames_to_copy; ++i) {
-        dest_data[i] = ConvertS16ToFloat(source_data[i]);
+        dest_data[i] = ConvertSample<int16, float>(source_data[i]);
       }
     }
     return;
@@ -245,103 +287,74 @@
       source_data, dest_frame_offset, frames_to_copy, bytes_per_channel);
 }
 
-static inline int32 ConvertS16ToS32(int16 value) {
-  return static_cast<int32>(value) << 16;
-}
-
-static inline int32 ConvertF32ToS32(float value) {
-  return static_cast<int32>(value < 0
-                                ? (-value) * std::numeric_limits<int32>::min()
-                                : value * std::numeric_limits<int32>::max());
-}
-
-// No need for conversion. Return value as is. Keeping function to align with
-// code structure.
-static inline int32 ConvertS32ToS32(int32 value) {
-  return value;
-}
-
-template <class Target, typename Converter>
-void InterleaveToS32(const std::vector<uint8*>& channel_data,
-                     size_t frames_to_copy,
-                     int trim_start,
-                     int32* dest_data,
-                     Converter convert_func) {
+template <class Target, typename Dest>
+void InterleaveAndConvert(const std::vector<uint8*>& channel_data,
+                          size_t frames_to_copy,
+                          int trim_start,
+                          Dest* dest_data) {
   for (size_t ch = 0; ch < channel_data.size(); ++ch) {
     const Target* source_data =
         reinterpret_cast<const Target*>(channel_data[ch]) + trim_start;
     for (size_t i = 0, offset = ch; i < frames_to_copy;
          ++i, offset += channel_data.size()) {
-      dest_data[offset] = convert_func(source_data[i]);
+      dest_data[offset] = ConvertSample<Target, Dest>(source_data[i]);
     }
   }
 }
 
+template <typename Dest>
+void ReadFramesInterleaved(const std::vector<uint8*>& channel_data,
+                           int channel_count,
+                           SampleFormat sample_format,
+                           int frames_to_copy,
+                           int trim_start,
+                           Dest* dest_data) {
+  switch (sample_format) {
+    case kSampleFormatU8:
+      NOTREACHED();
+      break;
+    case kSampleFormatS16:
+      InterleaveAndConvert<int16, Dest>(
+          channel_data, frames_to_copy * channel_count, trim_start, dest_data);
+      break;
+    case kSampleFormatS32:
+      InterleaveAndConvert<int32, Dest>(
+          channel_data, frames_to_copy * channel_count, trim_start, dest_data);
+      break;
+    case kSampleFormatF32:
+      InterleaveAndConvert<float, Dest>(
+          channel_data, frames_to_copy * channel_count, trim_start, dest_data);
+      break;
+    case kSampleFormatPlanarS16:
+      InterleaveAndConvert<int16, Dest>(channel_data, frames_to_copy,
+                                        trim_start, dest_data);
+      break;
+    case kSampleFormatPlanarF32:
+      InterleaveAndConvert<float, Dest>(channel_data, frames_to_copy,
+                                        trim_start, dest_data);
+      break;
+    case kSampleFormatPlanarS32:
+      InterleaveAndConvert<int32, Dest>(channel_data, frames_to_copy,
+                                        trim_start, dest_data);
+      break;
+    case kUnknownSampleFormat:
+      NOTREACHED();
+      break;
+  }
+}
+
 void AudioBuffer::ReadFramesInterleavedS32(int frames_to_copy,
                                            int32* dest_data) {
   DCHECK_LE(frames_to_copy, adjusted_frame_count_);
+  ReadFramesInterleaved<int32>(channel_data_, channel_count_, sample_format_,
+                               frames_to_copy, trim_start_, dest_data);
+}
 
-  switch (sample_format_) {
-    case kSampleFormatU8:
-      NOTIMPLEMENTED();
-      break;
-    case kSampleFormatS16:
-      // Format is interleaved signed16. Convert each value into int32 and
-      // insert into output channel data.
-      InterleaveToS32<int16>(channel_data_,
-                             frames_to_copy * channel_count_,
-                             trim_start_,
-                             dest_data,
-                             ConvertS16ToS32);
-      break;
-    case kSampleFormatS32: {
-      // Format is interleaved signed32; just copy the data.
-      const int32* source_data =
-          reinterpret_cast<const int32*>(channel_data_[0]) + trim_start_;
-      memcpy(dest_data,
-             source_data,
-             frames_to_copy * channel_count_ * sizeof(int32));
-    } break;
-    case kSampleFormatF32:
-      // Format is interleaved float. Convert each value into int32 and insert
-      // into output channel data.
-      InterleaveToS32<float>(channel_data_,
-                             frames_to_copy * channel_count_,
-                             trim_start_,
-                             dest_data,
-                             ConvertF32ToS32);
-      break;
-    case kSampleFormatPlanarS16:
-      // Format is planar signed 16 bit. Convert each value into int32 and
-      // insert into output channel data.
-      InterleaveToS32<int16>(channel_data_,
-                             frames_to_copy,
-                             trim_start_,
-                             dest_data,
-                             ConvertS16ToS32);
-      break;
-    case kSampleFormatPlanarF32:
-      // Format is planar float. Convert each value into int32 and insert into
-      // output channel data.
-      InterleaveToS32<float>(channel_data_,
-                             frames_to_copy,
-                             trim_start_,
-                             dest_data,
-                             ConvertF32ToS32);
-      break;
-    case kSampleFormatPlanarS32:
-      // Format is planar signed 32 bit. Convert each value into int32 and
-      // insert into output channel data.
-      InterleaveToS32<int32>(channel_data_,
-                             frames_to_copy,
-                             trim_start_,
-                             dest_data,
-                             ConvertS32ToS32);
-      break;
-    case kUnknownSampleFormat:
-      NOTREACHED();
-      break;
-  }
+void AudioBuffer::ReadFramesInterleavedS16(int frames_to_copy,
+                                           int16* dest_data) {
+  DCHECK_LE(frames_to_copy, adjusted_frame_count_);
+  ReadFramesInterleaved<int16>(channel_data_, channel_count_, sample_format_,
+                               frames_to_copy, trim_start_, dest_data);
 }
 
 void AudioBuffer::TrimStart(int frames_to_trim) {
diff --git a/media/base/audio_buffer.h b/media/base/audio_buffer.h
index f81c2f63..63390d47 100644
--- a/media/base/audio_buffer.h
+++ b/media/base/audio_buffer.h
@@ -78,6 +78,11 @@
   // interleaved int32.
   void ReadFramesInterleavedS32(int frames_to_copy, int32* dest);
 
+  // Copy |frames_to_copy| frames into |dest|, |frames_to_copy| is the number of
+  // frames to copy. The frames are converted from their source format into
+  // interleaved int16.
+  void ReadFramesInterleavedS16(int frames_to_copy, int16* dest);
+
   // Trim an AudioBuffer by removing |frames_to_trim| frames from the start.
   // Timestamp and duration are adjusted to reflect the fewer frames.
   // Note that repeated calls to TrimStart() may result in timestamp() and
diff --git a/media/base/audio_buffer_unittest.cc b/media/base/audio_buffer_unittest.cc
index 168445a..43c763e 100644
--- a/media/base/audio_buffer_unittest.cc
+++ b/media/base/audio_buffer_unittest.cc
@@ -548,4 +548,46 @@
   ReadFramesInterleavedS32Test(kSampleFormatPlanarF32);
 }
 
+static void ReadFramesInterleavedS16Test(SampleFormat sample_format) {
+  const ChannelLayout channel_layout = CHANNEL_LAYOUT_4_0;
+  const int channels = ChannelLayoutToChannelCount(channel_layout);
+  const int frames = kSampleRate / 100;
+  const base::TimeDelta duration = base::TimeDelta::FromMilliseconds(10);
+  scoped_refptr<AudioBuffer> buffer = MakeReadFramesInterleavedTestBuffer(
+      sample_format, kSampleRate, channel_layout, channels, frames);
+  EXPECT_EQ(frames, buffer->frame_count());
+  EXPECT_EQ(duration, buffer->duration());
+
+  int16* dest = new int16[frames * channels];
+  buffer->ReadFramesInterleavedS16(frames, dest);
+
+  int count = 0;
+  for (int i = 0; i < frames; ++i) {
+    for (int ch = 0; ch < channels; ++ch) {
+      EXPECT_EQ(dest[count++], (frames * ch + i));
+    }
+  }
+  delete[] dest;
+}
+
+TEST(AudioBufferTest, ReadFramesInterleavedS16FromS16) {
+  ReadFramesInterleavedS16Test(kSampleFormatS16);
+}
+
+TEST(AudioBufferTest, ReadFramesInterleavedS16FromS32) {
+  ReadFramesInterleavedS16Test(kSampleFormatS32);
+}
+
+TEST(AudioBufferTest, ReadFramesInterleavedS16FromF32) {
+  ReadFramesInterleavedS16Test(kSampleFormatF32);
+}
+
+TEST(AudioBufferTest, ReadFramesInterleavedS16FromPlanarS16) {
+  ReadFramesInterleavedS16Test(kSampleFormatPlanarS16);
+}
+
+TEST(AudioBufferTest, ReadFramesInterleavedS16FromPlanarF32) {
+  ReadFramesInterleavedS16Test(kSampleFormatPlanarF32);
+}
+
 }  // namespace media
diff --git a/media/base/audio_decoder.h b/media/base/audio_decoder.h
index cee0bbc..3da8547c 100644
--- a/media/base/audio_decoder.h
+++ b/media/base/audio_decoder.h
@@ -26,11 +26,14 @@
   // TODO(rileya): Now that both AudioDecoder and VideoDecoder Status enums
   // match, break them into a decoder_status.h.
   enum Status {
-    kOk,  // We're all good.
-    kAborted,  // We aborted as a result of Reset() or destruction.
+    kOk,          // We're all good.
+    kAborted,     // We aborted as a result of Reset() or destruction.
     kDecodeError  // A decoding error occurred.
   };
 
+  // Callback for VideoDecoder initialization.
+  typedef base::Callback<void(bool success)> InitCB;
+
   // Callback for AudioDecoder to return a decoded frame whenever it becomes
   // available. Only non-EOS frames should be returned via this callback.
   typedef base::Callback<void(const scoped_refptr<AudioBuffer>&)> OutputCB;
@@ -53,10 +56,10 @@
 
   // Initializes an AudioDecoder with the given DemuxerStream, executing the
   // callback upon completion.
-  //  |statistics_cb| is used to update global pipeline statistics.
+  //  |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 PipelineStatusCB& status_cb,
+                          const InitCB& init_cb,
                           const OutputCB& output_cb) = 0;
 
   // Requests samples to be decoded. Only one decode may be in flight at any
diff --git a/media/base/media_log.cc b/media/base/media_log.cc
index d7028e79..7795235 100644
--- a/media/base/media_log.cc
+++ b/media/base/media_log.cc
@@ -47,10 +47,6 @@
       return "WEBMEDIAPLAYER_CREATED";
     case MediaLogEvent::WEBMEDIAPLAYER_DESTROYED:
       return "WEBMEDIAPLAYER_DESTROYED";
-    case MediaLogEvent::PIPELINE_CREATED:
-      return "PIPELINE_CREATED";
-    case MediaLogEvent::PIPELINE_DESTROYED:
-      return "PIPELINE_DESTROYED";
     case MediaLogEvent::LOAD:
       return "LOAD";
     case MediaLogEvent::SEEK:
diff --git a/media/base/media_log_event.h b/media/base/media_log_event.h
index db687fb..fe8bb75 100644
--- a/media/base/media_log_event.h
+++ b/media/base/media_log_event.h
@@ -32,11 +32,6 @@
     WEBMEDIAPLAYER_CREATED,
     WEBMEDIAPLAYER_DESTROYED,
 
-    // A Pipeline is being created or destroyed.
-    // params: none.
-    PIPELINE_CREATED,
-    PIPELINE_DESTROYED,
-
     // A media player is loading a resource.
     // params: "url": <URL of the resource>.
     LOAD,
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index 3135875..0f0b7ce 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -82,10 +82,11 @@
 
   // VideoDecoder implementation.
   virtual std::string GetDisplayName() const;
-  MOCK_METHOD4(Initialize, void(const VideoDecoderConfig& config,
-                                bool low_delay,
-                                const PipelineStatusCB& status_cb,
-                                const OutputCB& output_cb));
+  MOCK_METHOD4(Initialize,
+               void(const VideoDecoderConfig& config,
+                    bool low_delay,
+                    const InitCB& init_cb,
+                    const OutputCB& output_cb));
   MOCK_METHOD2(Decode, void(const scoped_refptr<DecoderBuffer>& buffer,
                             const DecodeCB&));
   MOCK_METHOD1(Reset, void(const base::Closure&));
@@ -104,7 +105,7 @@
   virtual std::string GetDisplayName() const;
   MOCK_METHOD3(Initialize,
                void(const AudioDecoderConfig& config,
-                    const PipelineStatusCB& status_cb,
+                    const InitCB& init_cb,
                     const OutputCB& output_cb));
   MOCK_METHOD2(Decode,
                void(const scoped_refptr<DecoderBuffer>& buffer,
diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc
index 4a39704..387470a 100644
--- a/media/base/pipeline.cc
+++ b/media/base/pipeline.cc
@@ -46,8 +46,6 @@
       pending_cdm_context_(nullptr),
       weak_factory_(this) {
   media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(kCreated));
-  media_log_->AddEvent(
-      media_log_->CreateEvent(MediaLogEvent::PIPELINE_CREATED));
 }
 
 Pipeline::~Pipeline() {
@@ -56,9 +54,6 @@
   DCHECK(!running_) << "Stop() must complete before destroying object";
   DCHECK(stop_cb_.is_null());
   DCHECK(seek_cb_.is_null());
-
-  media_log_->AddEvent(
-      media_log_->CreateEvent(MediaLogEvent::PIPELINE_DESTROYED));
 }
 
 void Pipeline::Start(Demuxer* demuxer,
diff --git a/media/base/test_helpers.cc b/media/base/test_helpers.cc
index bbfbd64a..f4ba9915 100644
--- a/media/base/test_helpers.cc
+++ b/media/base/test_helpers.cc
@@ -27,6 +27,7 @@
  public:
   MockCallback();
   MOCK_METHOD0(Run, void());
+  MOCK_METHOD1(RunWithBool, void(bool));
   MOCK_METHOD1(RunWithStatus, void(PipelineStatus));
 
  protected:
@@ -46,6 +47,12 @@
   return base::Bind(&MockCallback::Run, callback);
 }
 
+base::Callback<void(bool)> NewExpectedBoolCB(bool success) {
+  StrictMock<MockCallback>* callback = new StrictMock<MockCallback>();
+  EXPECT_CALL(*callback, RunWithBool(success));
+  return base::Bind(&MockCallback::RunWithBool, callback);
+}
+
 PipelineStatusCB NewExpectedStatusCB(PipelineStatus status) {
   StrictMock<MockCallback>* callback = new StrictMock<MockCallback>();
   EXPECT_CALL(*callback, RunWithStatus(status));
diff --git a/media/base/test_helpers.h b/media/base/test_helpers.h
index 712812f..05ba898 100644
--- a/media/base/test_helpers.h
+++ b/media/base/test_helpers.h
@@ -28,6 +28,7 @@
 
 // Return a callback that expects to be run once.
 base::Closure NewExpectedClosure();
+base::Callback<void(bool)> NewExpectedBoolCB(bool success);
 PipelineStatusCB NewExpectedStatusCB(PipelineStatus status);
 
 // Helper class for running a message loop until a callback has run. Useful for
diff --git a/media/base/video_decoder.h b/media/base/video_decoder.h
index 85c08f3e..f7bae3c 100644
--- a/media/base/video_decoder.h
+++ b/media/base/video_decoder.h
@@ -25,11 +25,14 @@
   // TODO(rileya): Now that both AudioDecoder and VideoDecoder Status enums
   // match, break them into a decoder_status.h.
   enum Status {
-    kOk,  // Everything went as planned.
-    kAborted,  // Decode was aborted as a result of Reset() being called.
+    kOk,          // Everything went as planned.
+    kAborted,     // Decode was aborted as a result of Reset() being called.
     kDecodeError  // Decoding error happened.
   };
 
+  // Callback for VideoDecoder initialization.
+  typedef base::Callback<void(bool success)> InitCB;
+
   // Callback for VideoDecoder to return a decoded frame whenever it becomes
   // available. Only non-EOS frames should be returned via this callback.
   typedef base::Callback<void(const scoped_refptr<VideoFrame>&)> OutputCB;
@@ -51,7 +54,7 @@
   virtual std::string GetDisplayName() const = 0;
 
   // Initializes a VideoDecoder with the given |config|, executing the
-  // |status_cb| upon completion. |output_cb| is called for each output frame
+  // |init_cb| upon completion. |output_cb| is called for each output frame
   // decoded by Decode().
   //
   // If |low_delay| is true then the decoder is not allowed to queue frames,
@@ -64,10 +67,10 @@
   // 1) The VideoDecoder will be reinitialized if it was initialized before.
   //    Upon reinitialization, all internal buffered frames will be dropped.
   // 2) This method should not be called during pending decode or reset.
-  // 3) No VideoDecoder calls should be made before |status_cb| is executed.
+  // 3) No VideoDecoder calls should be made before |init_cb| is executed.
   virtual void Initialize(const VideoDecoderConfig& config,
                           bool low_delay,
-                          const PipelineStatusCB& status_cb,
+                          const InitCB& init_cb,
                           const OutputCB& output_cb) = 0;
 
   // Requests a |buffer| to be decoded. The status of the decoder and decoded
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
index 68bbfc2c..aac26e5 100644
--- a/media/base/video_frame.cc
+++ b/media/base/video_frame.cc
@@ -243,9 +243,9 @@
   DCHECK(IsValidConfig(format, STORAGE_OWNED_MEMORY, new_coded_size,
                        visible_rect, natural_size));
 
-  scoped_refptr<VideoFrame> frame(
-      new VideoFrame(format, STORAGE_OWNED_MEMORY, new_coded_size, visible_rect,
-                     natural_size, timestamp, false));
+  scoped_refptr<VideoFrame> frame(new VideoFrame(format, STORAGE_OWNED_MEMORY,
+                                                 new_coded_size, visible_rect,
+                                                 natural_size, timestamp));
   frame->AllocateYUV();
   return frame;
 }
@@ -265,7 +265,7 @@
   Format texture_format = has_alpha ? ARGB : XRGB;
   scoped_refptr<VideoFrame> frame(
       new VideoFrame(texture_format, STORAGE_TEXTURE, coded_size, visible_rect,
-                     natural_size, mailbox_holders, timestamp, false));
+                     natural_size, mailbox_holders, timestamp));
   frame->mailbox_holders_release_cb_ = mailbox_holder_release_cb;
   frame->allow_overlay_ = allow_overlay;
   return frame;
@@ -288,7 +288,7 @@
   mailbox_holders[kVPlane] = v_mailbox_holder;
   scoped_refptr<VideoFrame> frame(
       new VideoFrame(I420, STORAGE_TEXTURE, coded_size, visible_rect,
-                     natural_size, mailbox_holders, timestamp, false));
+                     natural_size, mailbox_holders, timestamp));
   frame->mailbox_holders_release_cb_ = mailbox_holder_release_cb;
   frame->allow_overlay_ = allow_overlay;
   return frame;
@@ -341,9 +341,9 @@
   CHECK(IsValidConfig(format, STORAGE_UNOWNED_MEMORY, new_coded_size,
                       visible_rect, natural_size));
 
-  scoped_refptr<VideoFrame> frame(
-      new VideoFrame(format, STORAGE_UNOWNED_MEMORY, new_coded_size,
-                     visible_rect, natural_size, timestamp, false));
+  scoped_refptr<VideoFrame> frame(new VideoFrame(format, STORAGE_UNOWNED_MEMORY,
+                                                 new_coded_size, visible_rect,
+                                                 natural_size, timestamp));
   frame->strides_[kYPlane] = y_stride;
   frame->strides_[kUPlane] = u_stride;
   frame->strides_[kVPlane] = v_stride;
@@ -377,9 +377,9 @@
 #if defined(OS_MACOSX) || defined(OS_CHROMEOS)
   DCHECK_EQ(format, NV12);
 #endif
-  scoped_refptr<VideoFrame> frame(
-      new VideoFrame(format, STORAGE_DMABUFS, coded_size, visible_rect,
-                     natural_size, timestamp, false));
+  scoped_refptr<VideoFrame> frame(new VideoFrame(format, STORAGE_DMABUFS,
+                                                 coded_size, visible_rect,
+                                                 natural_size, timestamp));
 
   for (size_t i = 0; i < dmabuf_fds.size(); ++i) {
     int duped_fd = HANDLE_EINTR(dup(dmabuf_fds[i]));
@@ -433,9 +433,9 @@
     return NULL;
   }
 
-  scoped_refptr<VideoFrame> frame(
-      new VideoFrame(format, STORAGE_UNOWNED_MEMORY, coded_size, visible_rect,
-                     natural_size, timestamp, false));
+  scoped_refptr<VideoFrame> frame(new VideoFrame(format, STORAGE_UNOWNED_MEMORY,
+                                                 coded_size, visible_rect,
+                                                 natural_size, timestamp));
 
   frame->cv_pixel_buffer_.reset(cv_pixel_buffer, base::scoped_policy::RETAIN);
   return frame;
@@ -452,10 +452,11 @@
   CHECK_NE(frame->storage_type(), STORAGE_TEXTURE);
 
   DCHECK(frame->visible_rect().Contains(visible_rect));
-  scoped_refptr<VideoFrame> wrapped_frame(
-      new VideoFrame(frame->format(), frame->storage_type(),
-                     frame->coded_size(), visible_rect, natural_size,
-                     frame->timestamp(), frame->end_of_stream()));
+  scoped_refptr<VideoFrame> wrapped_frame(new VideoFrame(
+      frame->format(), frame->storage_type(), frame->coded_size(), visible_rect,
+      natural_size, frame->timestamp()));
+  if (frame->IsEndOfStream())
+    frame->metadata()->SetBoolean(VideoFrameMetadata::END_OF_STREAM, true);
 
   for (size_t i = 0; i < NumPlanes(frame->format()); ++i) {
     wrapped_frame->strides_[i] = frame->stride(i);
@@ -467,8 +468,11 @@
 
 // static
 scoped_refptr<VideoFrame> VideoFrame::CreateEOSFrame() {
-  return new VideoFrame(UNKNOWN, STORAGE_UNKNOWN, gfx::Size(), gfx::Rect(),
-                        gfx::Size(), kNoTimestamp(), true);
+  scoped_refptr<VideoFrame> frame =
+      new VideoFrame(UNKNOWN, STORAGE_UNKNOWN, gfx::Size(), gfx::Rect(),
+                     gfx::Size(), kNoTimestamp());
+  frame->metadata()->SetBoolean(VideoFrameMetadata::END_OF_STREAM, true);
+  return frame;
 }
 
 // static
@@ -512,9 +516,8 @@
 scoped_refptr<VideoFrame> VideoFrame::CreateHoleFrame(
     const gfx::Size& size) {
   DCHECK(IsValidConfig(UNKNOWN, STORAGE_HOLE, size, gfx::Rect(size), size));
-  scoped_refptr<VideoFrame> frame(
-      new VideoFrame(UNKNOWN, STORAGE_HOLE, size, gfx::Rect(size), size,
-                     base::TimeDelta(), false));
+  scoped_refptr<VideoFrame> frame(new VideoFrame(
+      UNKNOWN, STORAGE_HOLE, size, gfx::Rect(size), size, base::TimeDelta()));
   return frame;
 }
 #endif  // defined(VIDEO_HOLE)
@@ -596,49 +599,12 @@
       SampleSize(format, plane).height();
 }
 
-void VideoFrame::AllocateYUV() {
-  DCHECK_EQ(storage_type_, STORAGE_OWNED_MEMORY);
-  static_assert(0 == kYPlane, "y plane data must be index 0");
-
-  size_t data_size = 0;
-  size_t offset[kMaxPlanes];
-  for (size_t plane = 0; plane < NumPlanes(format_); ++plane) {
-    // The *2 in alignment for height is because some formats (e.g. h264) allow
-    // interlaced coding, and then the size needs to be a multiple of two
-    // macroblocks (vertically). See
-    // libavcodec/utils.c:avcodec_align_dimensions2().
-    const size_t height = RoundUp(rows(plane), kFrameSizeAlignment * 2);
-    strides_[plane] = RoundUp(row_bytes(plane), kFrameSizeAlignment);
-    offset[plane] = data_size;
-    data_size += height * strides_[plane];
-  }
-
-  // The extra line of UV being allocated is because h264 chroma MC
-  // overreads by one line in some cases, see libavcodec/utils.c:
-  // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
-  // put_h264_chroma_mc4_ssse3().
-  DCHECK(IsValidPlane(kUPlane, format_));
-  data_size += strides_[kUPlane] + kFrameSizePadding;
-
-  // FFmpeg expects the initialize allocation to be zero-initialized.  Failure
-  // to do so can lead to unitialized value usage.  See http://crbug.com/390941
-  uint8* data = reinterpret_cast<uint8*>(
-      base::AlignedAlloc(data_size, kFrameAddressAlignment));
-  memset(data, 0, data_size);
-
-  for (size_t plane = 0; plane < NumPlanes(format_); ++plane)
-    data_[plane] = data + offset[plane];
-
-  AddDestructionObserver(base::Bind(&ReleaseData, data));
-}
-
 VideoFrame::VideoFrame(Format format,
                        StorageType storage_type,
                        const gfx::Size& coded_size,
                        const gfx::Rect& visible_rect,
                        const gfx::Size& natural_size,
-                       base::TimeDelta timestamp,
-                       bool end_of_stream)
+                       base::TimeDelta timestamp)
     : format_(format),
       storage_type_(storage_type),
       coded_size_(coded_size),
@@ -648,7 +614,6 @@
       shared_memory_offset_(0),
       timestamp_(timestamp),
       release_sync_point_(0),
-      end_of_stream_(end_of_stream),
       allow_overlay_(false) {
   DCHECK(IsValidConfig(format_, storage_type, coded_size_, visible_rect_,
                        natural_size_));
@@ -663,11 +628,14 @@
                        const gfx::Rect& visible_rect,
                        const gfx::Size& natural_size,
                        base::TimeDelta timestamp,
-                       bool end_of_stream,
                        base::SharedMemoryHandle handle,
                        size_t shared_memory_offset)
-    : VideoFrame(format, storage_type, coded_size, visible_rect, natural_size,
-      timestamp, end_of_stream) {
+    : VideoFrame(format,
+                 storage_type,
+                 coded_size,
+                 visible_rect,
+                 natural_size,
+                 timestamp) {
   shared_memory_handle_ = handle;
   shared_memory_offset_ = shared_memory_offset;
 }
@@ -678,10 +646,13 @@
                        const gfx::Rect& visible_rect,
                        const gfx::Size& natural_size,
                        const gpu::MailboxHolder(&mailbox_holders)[kMaxPlanes],
-                       base::TimeDelta timestamp,
-                       bool end_of_stream)
-    : VideoFrame(format, storage_type, coded_size, visible_rect, natural_size,
-      timestamp, end_of_stream) {
+                       base::TimeDelta timestamp)
+    : VideoFrame(format,
+                 storage_type,
+                 coded_size,
+                 visible_rect,
+                 natural_size,
+                 timestamp) {
   memcpy(&mailbox_holders_, mailbox_holders, sizeof(mailbox_holders_));
 }
 
@@ -728,10 +699,10 @@
   scoped_refptr<VideoFrame> frame;
   if (storage_type == STORAGE_SHMEM) {
     frame = new VideoFrame(format, storage_type, new_coded_size, visible_rect,
-                           natural_size, timestamp, false, handle, data_offset);
+                           natural_size, timestamp, handle, data_offset);
   } else {
     frame = new VideoFrame(format, storage_type, new_coded_size, visible_rect,
-                           natural_size, timestamp, false);
+                           natural_size, timestamp);
   }
   frame->strides_[kYPlane] = new_coded_size.width();
   frame->strides_[kUPlane] = new_coded_size.width() / 2;
@@ -742,6 +713,42 @@
   return frame;
 }
 
+void VideoFrame::AllocateYUV() {
+  DCHECK_EQ(storage_type_, STORAGE_OWNED_MEMORY);
+  static_assert(0 == kYPlane, "y plane data must be index 0");
+
+  size_t data_size = 0;
+  size_t offset[kMaxPlanes];
+  for (size_t plane = 0; plane < NumPlanes(format_); ++plane) {
+    // The *2 in alignment for height is because some formats (e.g. h264) allow
+    // interlaced coding, and then the size needs to be a multiple of two
+    // macroblocks (vertically). See
+    // libavcodec/utils.c:avcodec_align_dimensions2().
+    const size_t height = RoundUp(rows(plane), kFrameSizeAlignment * 2);
+    strides_[plane] = RoundUp(row_bytes(plane), kFrameSizeAlignment);
+    offset[plane] = data_size;
+    data_size += height * strides_[plane];
+  }
+
+  // The extra line of UV being allocated is because h264 chroma MC
+  // overreads by one line in some cases, see libavcodec/utils.c:
+  // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
+  // put_h264_chroma_mc4_ssse3().
+  DCHECK(IsValidPlane(kUPlane, format_));
+  data_size += strides_[kUPlane] + kFrameSizePadding;
+
+  // FFmpeg expects the initialize allocation to be zero-initialized.  Failure
+  // to do so can lead to unitialized value usage.  See http://crbug.com/390941
+  uint8* data = reinterpret_cast<uint8*>(
+      base::AlignedAlloc(data_size, kFrameAddressAlignment));
+  memset(data, 0, data_size);
+
+  for (size_t plane = 0; plane < NumPlanes(format_); ++plane)
+    data_[plane] = data + offset[plane];
+
+  AddDestructionObserver(base::Bind(&ReleaseData, data));
+}
+
 // static
 bool VideoFrame::IsValidPlane(size_t plane, Format format) {
   return (plane < NumPlanes(format));
@@ -843,6 +850,13 @@
   done_callbacks_.push_back(callback);
 }
 
+bool VideoFrame::IsEndOfStream() const {
+  bool end_of_stream;
+  return metadata_.GetBoolean(VideoFrameMetadata::END_OF_STREAM,
+                              &end_of_stream) &&
+         end_of_stream;
+}
+
 void VideoFrame::UpdateReleaseSyncPoint(SyncPointClient* client) {
 #if defined(OS_LINUX)
   DCHECK(storage_type_ == STORAGE_TEXTURE || storage_type_ == STORAGE_DMABUFS);
diff --git a/media/base/video_frame.h b/media/base/video_frame.h
index 90d29f4..e7dbc6b 100644
--- a/media/base/video_frame.h
+++ b/media/base/video_frame.h
@@ -368,7 +368,7 @@
 #endif
 
   // Returns true if this VideoFrame represents the end of the stream.
-  bool end_of_stream() const { return end_of_stream_; }
+  bool IsEndOfStream() const;
 
   base::TimeDelta timestamp() const { return timestamp_; }
   void set_timestamp(base::TimeDelta timestamp) {
@@ -405,15 +405,13 @@
              const gfx::Size& coded_size,
              const gfx::Rect& visible_rect,
              const gfx::Size& natural_size,
-             base::TimeDelta timestamp,
-             bool end_of_stream);
+             base::TimeDelta timestamp);
   VideoFrame(Format format,
              StorageType storage_type,
              const gfx::Size& coded_size,
              const gfx::Rect& visible_rect,
              const gfx::Size& natural_size,
              base::TimeDelta timestamp,
-             bool end_of_stream,
              base::SharedMemoryHandle handle,
              size_t shared_memory_offset);
   VideoFrame(Format format,
@@ -422,8 +420,7 @@
              const gfx::Rect& visible_rect,
              const gfx::Size& natural_size,
              const gpu::MailboxHolder(&mailbox_holders)[kMaxPlanes],
-             base::TimeDelta timestamp,
-             bool end_of_stream);
+             base::TimeDelta timestamp);
   virtual ~VideoFrame();
 
   static scoped_refptr<VideoFrame> WrapExternalStorage(
@@ -499,8 +496,6 @@
   base::Lock release_sync_point_lock_;
   uint32 release_sync_point_;
 
-  const bool end_of_stream_;
-
   VideoFrameMetadata metadata_;
 
   bool allow_overlay_;
diff --git a/media/base/video_frame_metadata.h b/media/base/video_frame_metadata.h
index 526383b4..10b17be 100644
--- a/media/base/video_frame_metadata.h
+++ b/media/base/video_frame_metadata.h
@@ -21,6 +21,13 @@
     CAPTURE_BEGIN_TIME,
     CAPTURE_END_TIME,
 
+    // Some VideoFrames have an indication of the color space used.  Use
+    // GetInteger()/SetInteger() and VideoFrame::ColorSpace enumeration.
+    COLOR_SPACE,
+
+    // Indicates if the current frame is the End of its current Stream.
+    END_OF_STREAM,
+
     // The estimated duration of this frame (i.e., the amount of time between
     // the media timestamp of this frame and the next).  Note that this is not
     // the same information provided by FRAME_RATE as the FRAME_DURATION can
@@ -36,9 +43,23 @@
     // key.
     FRAME_RATE,
 
-    // Some VideoFrames have an indication of the color space used.  Use
-    // GetInteger()/SetInteger() and VideoFrame::ColorSpace enumeration.
-    COLOR_SPACE,
+    // A feedback signal that indicates the fraction of the tolerable maximum
+    // amount of resources that were utilized to process this frame.  A producer
+    // can check this value after-the-fact, usually via a VideoFrame destruction
+    // observer, to determine whether the consumer can handle more or less data
+    // volume, and achieve the right quality versus performance trade-off.
+    //
+    // Use Get/SetDouble() for this key.  Values are interpreted as follows:
+    // Less than 0.0 is meaningless and should be ignored.  1.0 indicates a
+    // maximum sustainable utilization.  Greater than 1.0 indicates the consumer
+    // is likely to stall or drop frames if the data volume is not reduced.
+    //
+    // Example: In a system that encodes and transmits video frames over the
+    // network, this value can be used to indicate whether sufficient CPU
+    // is available for encoding and/or sufficient bandwidth is available for
+    // transmission over the network.  The maximum of the two utilization
+    // measurements would be used as feedback.
+    RESOURCE_UTILIZATION,
 
     NUM_KEYS
   };
diff --git a/media/base/video_frame_unittest.cc b/media/base/video_frame_unittest.cc
index 6e67668..d1a09f3 100644
--- a/media/base/video_frame_unittest.cc
+++ b/media/base/video_frame_unittest.cc
@@ -155,7 +155,7 @@
 
   // Test an empty frame.
   frame = VideoFrame::CreateEOSFrame();
-  EXPECT_TRUE(frame->end_of_stream());
+  EXPECT_TRUE(frame->IsEndOfStream());
 }
 
 TEST(VideoFrame, CreateBlackFrame) {
@@ -170,7 +170,7 @@
 
   // Test basic properties.
   EXPECT_EQ(0, frame->timestamp().InMicroseconds());
-  EXPECT_FALSE(frame->end_of_stream());
+  EXPECT_FALSE(frame->IsEndOfStream());
 
   // Test |frame| properties.
   EXPECT_EQ(VideoFrame::YV12, frame->format());
diff --git a/media/blink/run_all_unittests.cc b/media/blink/run_all_unittests.cc
index 0261dc2..e7b8b725 100644
--- a/media/blink/run_all_unittests.cc
+++ b/media/blink/run_all_unittests.cc
@@ -80,6 +80,7 @@
 
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
   gin::V8Initializer::LoadV8Snapshot();
+  gin::V8Initializer::LoadV8Natives();
 #endif
 
   // Dummy task runner is initialized here because the blink::initialize creates
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 63c66bd..ce3488f3 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -167,8 +167,6 @@
   client_->setWebLayer(NULL);
 
   DCHECK(main_task_runner_->BelongsToCurrentThread());
-  media_log_->AddEvent(
-      media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
 
   if (delegate_)
     delegate_->PlayerGone(this);
@@ -191,6 +189,9 @@
   waiter.Wait();
 
   compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_);
+
+  media_log_->AddEvent(
+      media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
 }
 
 void WebMediaPlayerImpl::load(LoadType load_type, const blink::WebURL& url,
@@ -646,11 +647,13 @@
     blink::WebContentDecryptionModuleResult result) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
 
-  // TODO(xhwang): Support setMediaKeys(0) if necessary: http://crbug.com/330324
+  // Once the CDM is set it can't be cleared as there may be frames being
+  // decrypted on other threads. So fail this request.
+  // http://crbug.com/462365#c7.
   if (!cdm) {
     result.completeWithError(
-        blink::WebContentDecryptionModuleExceptionNotSupportedError, 0,
-        "Null MediaKeys object is not supported.");
+        blink::WebContentDecryptionModuleExceptionInvalidStateError, 0,
+        "The existing MediaKeys object cannot be removed at this time.");
     return;
   }
 
diff --git a/media/cast/logging/encoding_event_subscriber.cc b/media/cast/logging/encoding_event_subscriber.cc
index 2722524..82ec06f2 100644
--- a/media/cast/logging/encoding_event_subscriber.cc
+++ b/media/cast/logging/encoding_event_subscriber.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
 #include "media/cast/logging/proto/proto_utils.h"
 
 using google::protobuf::RepeatedPtrField;
@@ -93,10 +94,24 @@
   event_proto->add_event_timestamp_ms(
       (frame_event.timestamp - base::TimeTicks()).InMilliseconds());
 
-  if (frame_event.type == FRAME_ENCODED) {
+  if (frame_event.type == FRAME_CAPTURE_END) {
+    if (frame_event.media_type == VIDEO_EVENT &&
+        frame_event.width > 0 && frame_event.height > 0) {
+      event_proto->set_width(frame_event.width);
+      event_proto->set_height(frame_event.height);
+    }
+  } else if (frame_event.type == FRAME_ENCODED) {
     event_proto->set_encoded_frame_size(frame_event.size);
+    if (frame_event.encoder_cpu_utilization >= 0.0) {
+      event_proto->set_encoder_cpu_percent_utilized(base::saturated_cast<int32>(
+              frame_event.encoder_cpu_utilization * 100.0 + 0.5));
+    }
+    if (frame_event.idealized_bitrate_utilization >= 0.0) {
+      event_proto->set_idealized_bitrate_percent_utilized(
+          base::saturated_cast<int32>(
+              frame_event.idealized_bitrate_utilization * 100.0 + 0.5));
+    }
     if (frame_event.media_type == VIDEO_EVENT) {
-      event_proto->set_encoded_frame_size(frame_event.size);
       event_proto->set_key_frame(frame_event.key_frame);
       event_proto->set_target_bitrate(frame_event.target_bitrate);
     }
diff --git a/media/cast/logging/encoding_event_subscriber_unittest.cc b/media/cast/logging/encoding_event_subscriber_unittest.cc
index 0e33c5fc8..b052bbb8 100644
--- a/media/cast/logging/encoding_event_subscriber_unittest.cc
+++ b/media/cast/logging/encoding_event_subscriber_unittest.cc
@@ -76,17 +76,25 @@
   base::TimeTicks now(testing_clock_->NowTicks());
 
   // Entry with RTP timestamp 0 should get dropped.
+  int width = 320;
+  int height = 180;
   for (int i = 0; i < 11; i++) {
     cast_environment_->Logging()->InsertFrameEvent(now,
                                                    FRAME_CAPTURE_BEGIN,
                                                    VIDEO_EVENT,
                                                    i * 100,
                                                    /*frame_id*/ 0);
+    cast_environment_->Logging()->InsertCapturedVideoFrameEvent(now,
+                                                                i * 100,
+                                                                width,
+                                                                height);
     cast_environment_->Logging()->InsertFrameEvent(now,
                                                    FRAME_DECODED,
                                                    VIDEO_EVENT,
                                                    i * 100,
                                                    /*frame_id*/ 0);
+    width += 160;
+    height += 90;
   }
 
   GetEventsAndReset();
@@ -94,6 +102,14 @@
   ASSERT_EQ(10u, frame_events_.size());
   EXPECT_EQ(100u, frame_events_.front()->relative_rtp_timestamp());
   EXPECT_EQ(1000u, frame_events_.back()->relative_rtp_timestamp());
+  width = 320;
+  height = 180;
+  for (const auto& event : frame_events_) {
+    width += 160;
+    height += 90;
+    EXPECT_EQ(width, event->width());
+    EXPECT_EQ(height, event->height());
+  }
 }
 
 TEST_F(EncodingEventSubscriberTest, PacketEventTruncating) {
@@ -223,9 +239,12 @@
   int size = 123;
   bool key_frame = true;
   int target_bitrate = 1024;
+  double encoder_cpu_utilization = 0.90;
+  double idealized_bitrate_utilization = 0.42;
   cast_environment_->Logging()->InsertEncodedFrameEvent(
       now, FRAME_ENCODED, VIDEO_EVENT, rtp_timestamp,
-      /*frame_id*/ 0, size, key_frame, target_bitrate);
+      /*frame_id*/ 0, size, key_frame, target_bitrate,
+      encoder_cpu_utilization, idealized_bitrate_utilization);
 
   GetEventsAndReset();
 
@@ -248,6 +267,8 @@
   EXPECT_TRUE(event->has_key_frame());
   EXPECT_EQ(key_frame, event->key_frame());
   EXPECT_EQ(target_bitrate, event->target_bitrate());
+  EXPECT_EQ(90, event->encoder_cpu_percent_utilized());
+  EXPECT_EQ(42, event->idealized_bitrate_percent_utilized());
 }
 
 TEST_F(EncodingEventSubscriberTest, MultipleFrameEvents) {
@@ -264,7 +285,8 @@
   cast_environment_->Logging()->InsertEncodedFrameEvent(
       now2, FRAME_ENCODED, AUDIO_EVENT, rtp_timestamp2,
       /*frame_id*/ 0, /*size*/ 123, /* key_frame - unused */ false,
-      /*target_bitrate - unused*/ 0);
+      /*target_bitrate - unused*/ 0,
+      0.44, 0.55);
 
   testing_clock_->Advance(base::TimeDelta::FromMilliseconds(20));
   base::TimeTicks now3(testing_clock_->NowTicks());
@@ -306,6 +328,8 @@
   EXPECT_EQ(InMilliseconds(now2), event->event_timestamp_ms(0));
 
   EXPECT_FALSE(event->has_key_frame());
+  EXPECT_EQ(44, event->encoder_cpu_percent_utilized());
+  EXPECT_EQ(55, event->idealized_bitrate_percent_utilized());
 }
 
 TEST_F(EncodingEventSubscriberTest, PacketEvent) {
@@ -526,11 +550,10 @@
                                                  rtp_timestamp,
                                                  /*frame_id*/ 0);
 
-  cast_environment_->Logging()->InsertFrameEvent(now,
-                                                 FRAME_CAPTURE_END,
-                                                 VIDEO_EVENT,
-                                                 rtp_timestamp + 30,
-                                                 /*frame_id*/ 1);
+  cast_environment_->Logging()->InsertCapturedVideoFrameEvent(
+      now,
+      rtp_timestamp + 30,
+      1280, 720);
 
   GetEventsAndReset();
 
@@ -542,6 +565,8 @@
   ++it;
   ASSERT_NE(frame_events_.end(), it);
   EXPECT_EQ(30u, (*it)->relative_rtp_timestamp());
+  EXPECT_EQ(1280, (*it)->width());
+  EXPECT_EQ(720, (*it)->height());
 
   rtp_timestamp = 67890;
 
@@ -567,11 +592,10 @@
                                                  /*frame_id*/ 0);
 
   // RtpTimestamp has now wrapped around.
-  cast_environment_->Logging()->InsertFrameEvent(now,
-                                                 FRAME_CAPTURE_END,
-                                                 VIDEO_EVENT,
-                                                 rtp_timestamp + 30,
-                                                 /*frame_id*/ 1);
+  cast_environment_->Logging()->InsertCapturedVideoFrameEvent(
+      now,
+      rtp_timestamp + 30,
+      1280, 720);
 
   GetEventsAndReset();
 
@@ -582,6 +606,8 @@
   ++it;
   ASSERT_NE(frame_events_.end(), it);
   EXPECT_EQ(30u, (*it)->relative_rtp_timestamp());
+  EXPECT_EQ(1280, (*it)->width());
+  EXPECT_EQ(720, (*it)->height());
 }
 
 TEST_F(EncodingEventSubscriberTest, MaxEventsPerProto) {
diff --git a/media/cast/logging/logging_defines.cc b/media/cast/logging/logging_defines.cc
index 05ceeb95..e240b2f5 100644
--- a/media/cast/logging/logging_defines.cc
+++ b/media/cast/logging/logging_defines.cc
@@ -33,8 +33,10 @@
 }
 
 FrameEvent::FrameEvent()
-    : rtp_timestamp(0u), frame_id(kFrameIdUnknown), size(0u), type(UNKNOWN),
-      media_type(UNKNOWN_EVENT), key_frame(false), target_bitrate(0) {}
+    : rtp_timestamp(0u), frame_id(kFrameIdUnknown), width(0), height(0),
+      size(0u), type(UNKNOWN), media_type(UNKNOWN_EVENT), key_frame(false),
+      target_bitrate(0), encoder_cpu_utilization(-1.0),
+      idealized_bitrate_utilization(-1.0) {}
 FrameEvent::~FrameEvent() {}
 
 PacketEvent::PacketEvent()
diff --git a/media/cast/logging/logging_defines.h b/media/cast/logging/logging_defines.h
index 0f57fe9..dc29554 100644
--- a/media/cast/logging/logging_defines.h
+++ b/media/cast/logging/logging_defines.h
@@ -55,7 +55,11 @@
   RtpTimestamp rtp_timestamp;
   uint32 frame_id;
 
-  // Size of encoded frame. Only set for FRAME_ENCODED event.
+  // Resolution of the frame. Only set for video FRAME_CAPTURE_END events.
+  int width;
+  int height;
+
+  // Size of encoded frame in bytes. Only set for FRAME_ENCODED event.
   size_t size;
 
   // Time of event logged.
@@ -77,6 +81,11 @@
   // The requested target bitrate of the encoder at the time the frame is
   // encoded. Only set for video FRAME_ENCODED event.
   int target_bitrate;
+
+  // Encoding performance metrics. See media/cast/sender/sender_encoded_frame.h
+  // for a description of these values.
+  double encoder_cpu_utilization;
+  double idealized_bitrate_utilization;
 };
 
 struct PacketEvent {
diff --git a/media/cast/logging/logging_impl.cc b/media/cast/logging/logging_impl.cc
index b5351e3..b64674f 100644
--- a/media/cast/logging/logging_impl.cc
+++ b/media/cast/logging/logging_impl.cc
@@ -28,16 +28,32 @@
       rtp_timestamp, frame_id);
 }
 
-void LoggingImpl::InsertEncodedFrameEvent(const base::TimeTicks& time_of_event,
-                                          CastLoggingEvent event,
-                                          EventMediaType event_media_type,
-                                          uint32 rtp_timestamp,
-                                          uint32 frame_id, int frame_size,
-                                          bool key_frame,
-                                          int target_bitrate) {
+void LoggingImpl::InsertCapturedVideoFrameEvent(
+    const base::TimeTicks& time_of_event,
+    uint32 rtp_timestamp,
+    int width,
+    int height) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  raw_.InsertCapturedVideoFrameEvent(
+      time_of_event, rtp_timestamp, width, height);
+}
+
+
+void LoggingImpl::InsertEncodedFrameEvent(
+    const base::TimeTicks& time_of_event,
+    CastLoggingEvent event,
+    EventMediaType event_media_type,
+    uint32 rtp_timestamp,
+    uint32 frame_id,
+    int encoded_size,
+    bool key_frame,
+    int target_bitrate,
+    double encoder_cpu_utilization,
+    double idealized_bitrate_utilization) {
   DCHECK(thread_checker_.CalledOnValidThread());
   raw_.InsertEncodedFrameEvent(time_of_event, event, event_media_type,
-      rtp_timestamp, frame_id, frame_size, key_frame, target_bitrate);
+      rtp_timestamp, frame_id, encoded_size, key_frame, target_bitrate,
+      encoder_cpu_utilization, idealized_bitrate_utilization);
 }
 
 void LoggingImpl::InsertFrameEventWithDelay(
diff --git a/media/cast/logging/logging_impl.h b/media/cast/logging/logging_impl.h
index ba453c8..1fc3e76 100644
--- a/media/cast/logging/logging_impl.h
+++ b/media/cast/logging/logging_impl.h
@@ -29,12 +29,21 @@
                         CastLoggingEvent event, EventMediaType event_media_type,
                         uint32 rtp_timestamp, uint32 frame_id);
 
+  void InsertCapturedVideoFrameEvent(const base::TimeTicks& time_of_event,
+                                     uint32 rtp_timestamp,
+                                     int width,
+                                     int height);
+
   void InsertEncodedFrameEvent(const base::TimeTicks& time_of_event,
                                CastLoggingEvent event,
                                EventMediaType event_media_type,
-                               uint32 rtp_timestamp, uint32 frame_id,
-                               int frame_size, bool key_frame,
-                               int target_bitrate);
+                               uint32 rtp_timestamp,
+                               uint32 frame_id,
+                               int encoded_size,
+                               bool key_frame,
+                               int target_bitrate,
+                               double encoder_cpu_utilization,
+                               double idealized_bitrate_utilization);
 
   void InsertFrameEventWithDelay(const base::TimeTicks& time_of_event,
                                  CastLoggingEvent event,
diff --git a/media/cast/logging/logging_impl_unittest.cc b/media/cast/logging/logging_impl_unittest.cc
index eae1dcd..fb2779c0 100644
--- a/media/cast/logging/logging_impl_unittest.cc
+++ b/media/cast/logging/logging_impl_unittest.cc
@@ -85,7 +85,8 @@
     sum_size += static_cast<size_t>(size);
     logging_.InsertEncodedFrameEvent(testing_clock_.NowTicks(),
                                      FRAME_ENCODED, VIDEO_EVENT, rtp_timestamp,
-                                     frame_id, size, true, target_bitrate);
+                                     frame_id, size, true, target_bitrate,
+                                     0.1, 2.3);
     testing_clock_.Advance(base::TimeDelta::FromMilliseconds(kFrameIntervalMs));
     rtp_timestamp += kFrameIntervalMs * 90;
     ++frame_id;
@@ -146,7 +147,7 @@
       logging_.InsertEncodedFrameEvent(testing_clock_.NowTicks(),
                                        FRAME_ENCODED, AUDIO_EVENT,
                                        rtp_timestamp,
-                                       frame_id, 1500, true, 0);
+                                       frame_id, 1500, true, 0, 4.5, 6.7);
     } else if (frame_id % 3) {
       logging_.InsertFrameEvent(testing_clock_.NowTicks(), FRAME_DECODED,
                                 VIDEO_EVENT, rtp_timestamp, frame_id);
diff --git a/media/cast/logging/logging_raw.cc b/media/cast/logging/logging_raw.cc
index 229064d7..b80c05e7 100644
--- a/media/cast/logging/logging_raw.cc
+++ b/media/cast/logging/logging_raw.cc
@@ -22,18 +22,34 @@
                                   uint32 rtp_timestamp,
                                   uint32 frame_id) {
   InsertBaseFrameEvent(time_of_event, event, event_media_type, frame_id,
-                       rtp_timestamp, base::TimeDelta(), 0, false, 0);
+                       rtp_timestamp, base::TimeDelta(), 0, 0, 0, false, 0,
+                       -1.0, -1.0);
+}
+
+void LoggingRaw::InsertCapturedVideoFrameEvent(
+    const base::TimeTicks& time_of_event,
+    uint32 rtp_timestamp,
+    int width,
+    int height) {
+ InsertBaseFrameEvent(time_of_event, FRAME_CAPTURE_END, VIDEO_EVENT,
+                       kFrameIdUnknown, rtp_timestamp, base::TimeDelta(), width,
+                       height, 0, false, 0, -1.0, -1.0);
 }
 
 void LoggingRaw::InsertEncodedFrameEvent(const base::TimeTicks& time_of_event,
                                          CastLoggingEvent event,
                                          EventMediaType event_media_type,
-                                         uint32 rtp_timestamp, uint32 frame_id,
-                                         int size, bool key_frame,
-                                         int target_bitrate) {
+                                         uint32 rtp_timestamp,
+                                         uint32 frame_id,
+                                         int encoded_size,
+                                         bool key_frame,
+                                         int target_bitrate,
+                                         double encoder_cpu_utilization,
+                                         double idealized_bitrate_utilization) {
   InsertBaseFrameEvent(time_of_event, event, event_media_type,
-                       frame_id, rtp_timestamp, base::TimeDelta(), size,
-                       key_frame, target_bitrate);
+                       frame_id, rtp_timestamp, base::TimeDelta(),
+                       0, 0, encoded_size, key_frame, target_bitrate,
+                       encoder_cpu_utilization, idealized_bitrate_utilization);
 }
 
 void LoggingRaw::InsertFrameEventWithDelay(const base::TimeTicks& time_of_event,
@@ -43,7 +59,7 @@
                                            uint32 frame_id,
                                            base::TimeDelta delay) {
   InsertBaseFrameEvent(time_of_event, event, event_media_type, frame_id,
-                       rtp_timestamp, delay, 0, false, 0);
+                       rtp_timestamp, delay, 0, 0, 0, false, 0, -1.0, -1.0);
 }
 
 void LoggingRaw::InsertBaseFrameEvent(const base::TimeTicks& time_of_event,
@@ -51,18 +67,28 @@
                                       EventMediaType event_media_type,
                                       uint32 frame_id,
                                       uint32 rtp_timestamp,
-                                      base::TimeDelta delay, int size,
-                                      bool key_frame, int target_bitrate) {
+                                      base::TimeDelta delay,
+                                      int width,
+                                      int height,
+                                      int encoded_size,
+                                      bool key_frame,
+                                      int target_bitrate,
+                                      double encoder_cpu_utilization,
+                                      double idealized_bitrate_utilization) {
   FrameEvent frame_event;
   frame_event.rtp_timestamp = rtp_timestamp;
   frame_event.frame_id = frame_id;
-  frame_event.size = size;
+  frame_event.width = width;
+  frame_event.height = height;
+  frame_event.size = encoded_size;
   frame_event.timestamp = time_of_event;
   frame_event.type = event;
   frame_event.media_type = event_media_type;
   frame_event.delay_delta = delay;
   frame_event.key_frame = key_frame;
   frame_event.target_bitrate = target_bitrate;
+  frame_event.encoder_cpu_utilization = encoder_cpu_utilization;
+  frame_event.idealized_bitrate_utilization = idealized_bitrate_utilization;
   for (std::vector<RawEventSubscriber*>::const_iterator it =
            subscribers_.begin();
        it != subscribers_.end(); ++it) {
diff --git a/media/cast/logging/logging_raw.h b/media/cast/logging/logging_raw.h
index 8ed4a599..49ec985 100644
--- a/media/cast/logging/logging_raw.h
+++ b/media/cast/logging/logging_raw.h
@@ -30,18 +30,28 @@
                         CastLoggingEvent event, EventMediaType event_media_type,
                         uint32 rtp_timestamp, uint32 frame_id);
 
+  // Inserts a FRAME_CAPTURE_END event with the VIDEO_EVENT media type.
+  void InsertCapturedVideoFrameEvent(const base::TimeTicks& time_of_event,
+                                     uint32 rtp_timestamp,
+                                     int width,
+                                     int height);
+
   // This function is only applicable for FRAME_ENCODED event.
-  // |size| - Size of encoded frame.
+  // |encoded_size| - Size of encoded frame in bytes.
   // |key_frame| - Whether the frame is a key frame. This field is only
   //               applicable for video event.
   // |target_bitrate| - The target bitrate of the encoder the time the frame
   // was encoded. Only applicable for video event.
   void InsertEncodedFrameEvent(const base::TimeTicks& time_of_event,
-                                CastLoggingEvent event,
-                                EventMediaType event_media_type,
-                                uint32 rtp_timestamp, uint32 frame_id,
-                                int size, bool key_frame,
-                                int target_bitrate);
+                               CastLoggingEvent event,
+                               EventMediaType event_media_type,
+                               uint32 rtp_timestamp,
+                               uint32 frame_id,
+                               int encoded_size,
+                               bool key_frame,
+                               int target_bitrate,
+                               double encoder_cpu_utilization,
+                               double idealized_bitrate_utilization);
 
   // Render/playout delay
   // This function is only applicable for FRAME_PLAYOUT event.
@@ -73,9 +83,16 @@
   void InsertBaseFrameEvent(const base::TimeTicks& time_of_event,
                             CastLoggingEvent event,
                             EventMediaType event_media_type,
-                            uint32 frame_id, uint32 rtp_timestamp,
-                            base::TimeDelta delay, int size, bool key_frame,
-                            int target_bitrate);
+                            uint32 frame_id,
+                            uint32 rtp_timestamp,
+                            base::TimeDelta delay,
+                            int width,
+                            int height,
+                            int encoded_size,
+                            bool key_frame,
+                            int target_bitrate,
+                            double encoder_cpu_utilization,
+                            double idealized_bitrate_utilization);
 
   // List of subscriber pointers. This class does not own the subscribers.
   std::vector<RawEventSubscriber*> subscribers_;
diff --git a/media/cast/logging/logging_raw_unittest.cc b/media/cast/logging/logging_raw_unittest.cc
index 40a1ae52..0ecfbbf 100644
--- a/media/cast/logging/logging_raw_unittest.cc
+++ b/media/cast/logging/logging_raw_unittest.cc
@@ -56,8 +56,11 @@
   int size = 1024;
   bool key_frame = true;
   int target_bitrate = 4096;
+  double encoder_cpu_utilization = 0.11;
+  double idealized_bitrate_utilization = 0.98;
   raw_.InsertEncodedFrameEvent(timestamp, event_type, media_type,
-      rtp_timestamp, frame_id, size, key_frame, target_bitrate);
+      rtp_timestamp, frame_id, size, key_frame, target_bitrate,
+      encoder_cpu_utilization, idealized_bitrate_utilization);
 
   event_subscriber_.GetPacketEventsAndReset(&packet_events_);
   EXPECT_TRUE(packet_events_.empty());
@@ -73,6 +76,9 @@
   EXPECT_EQ(base::TimeDelta(), frame_events_[0].delay_delta);
   EXPECT_EQ(key_frame, frame_events_[0].key_frame);
   EXPECT_EQ(target_bitrate, frame_events_[0].target_bitrate);
+  EXPECT_EQ(encoder_cpu_utilization, frame_events_[0].encoder_cpu_utilization);
+  EXPECT_EQ(idealized_bitrate_utilization,
+            frame_events_[0].idealized_bitrate_utilization);
 }
 
 TEST_F(LoggingRawTest, FrameEventWithDelay) {
diff --git a/media/cast/logging/proto/raw_events.proto b/media/cast/logging/proto/raw_events.proto
index e9e75bc2..34639986 100644
--- a/media/cast/logging/proto/raw_events.proto
+++ b/media/cast/logging/proto/raw_events.proto
@@ -127,6 +127,14 @@
   
   // Only set if there is a video frame encoded event.
   optional int32 target_bitrate = 7;
+
+  // Only set if there is a frame capture event.
+  optional int32 width = 8;
+  optional int32 height = 9;
+
+  // Only set if there is a frame encoded event.
+  optional int32 encoder_cpu_percent_utilized = 10;
+  optional int32 idealized_bitrate_percent_utilized = 11;
 };
 
 message BasePacketEvent {
diff --git a/media/cast/logging/receiver_time_offset_estimator_impl_unittest.cc b/media/cast/logging/receiver_time_offset_estimator_impl_unittest.cc
index bc1fc51..ca791d4 100644
--- a/media/cast/logging/receiver_time_offset_estimator_impl_unittest.cc
+++ b/media/cast/logging/receiver_time_offset_estimator_impl_unittest.cc
@@ -70,7 +70,9 @@
       frame_id,
       1234,
       true,
-      5678);
+      5678,
+      9.10,
+      11.12);
 
   cast_environment_->Logging()->InsertPacketEvent(
       sender_clock_->NowTicks(),
@@ -133,7 +135,9 @@
       frame_id,
       1234,
       true,
-      5678);
+      5678,
+      9.10,
+      11.12);
 
   cast_environment_->Logging()->InsertPacketEvent(
       sender_clock_->NowTicks(),
@@ -201,7 +205,9 @@
       frame_id_a,
       1234,
       true,
-      5678);
+      5678,
+      9.10,
+      11.12);
 
   cast_environment_->Logging()->InsertPacketEvent(
       sender_clock_->NowTicks(),
@@ -218,7 +224,9 @@
       frame_id_b,
       1234,
       true,
-      5678);
+      5678,
+      9.10,
+      11.12);
 
   cast_environment_->Logging()->InsertPacketEvent(
       sender_clock_->NowTicks(),
@@ -266,7 +274,9 @@
       frame_id_c,
       1234,
       true,
-      5678);
+      5678,
+      9.10,
+      11.12);
 
   cast_environment_->Logging()->InsertPacketEvent(
       sender_clock_->NowTicks(),
diff --git a/media/cast/logging/serialize_deserialize_test.cc b/media/cast/logging/serialize_deserialize_test.cc
index af36cda0..f1766d04 100644
--- a/media/cast/logging/serialize_deserialize_test.cc
+++ b/media/cast/logging/serialize_deserialize_test.cc
@@ -28,8 +28,12 @@
     media::cast::PACKET_SENT_TO_NETWORK, media::cast::PACKET_RECEIVED};
 
 // The frame event fields cycle through these numbers.
+const int kWidth[] = {1280, 1280, 1280, 1280, 1920, 1920, 1920, 1920};
+const int kHeight[] = {720, 720, 720, 720, 1080, 1080, 1080, 1080};
 const int kEncodedFrameSize[] = {512, 425, 399, 400, 237};
 const int64 kDelayMillis[] = {15, 4, 8, 42, 23, 16};
+const int kEncoderCPUPercentUtilized[] = {10, 9, 42, 3, 11, 12, 15, 7};
+const int kIdealizedBitratePercentUtilized[] = {9, 9, 9, 15, 36, 38, 35, 40};
 
 const int kMaxSerializedBytes = 10000;
 
@@ -63,9 +67,16 @@
         frame_event->add_event_timestamp_ms(event_time_ms);
         event_time_ms += 1024;
       }
+      frame_event->set_width(kWidth[i % arraysize(kWidth)]);
+      frame_event->set_height(kHeight[i % arraysize(kHeight)]);
       frame_event->set_encoded_frame_size(
           kEncodedFrameSize[i % arraysize(kEncodedFrameSize)]);
       frame_event->set_delay_millis(kDelayMillis[i % arraysize(kDelayMillis)]);
+      frame_event->set_encoder_cpu_percent_utilized(kEncoderCPUPercentUtilized[
+              i % arraysize(kEncoderCPUPercentUtilized)]);
+      frame_event->set_idealized_bitrate_percent_utilized(
+          kIdealizedBitratePercentUtilized[
+              i % arraysize(kIdealizedBitratePercentUtilized)]);
 
       frame_event_list_.push_back(frame_event);
     }
diff --git a/media/cast/logging/simple_event_subscriber_unittest.cc b/media/cast/logging/simple_event_subscriber_unittest.cc
index 653eecd..bf2c210 100644
--- a/media/cast/logging/simple_event_subscriber_unittest.cc
+++ b/media/cast/logging/simple_event_subscriber_unittest.cc
@@ -43,7 +43,7 @@
   cast_environment_->Logging()->InsertEncodedFrameEvent(
       testing_clock_->NowTicks(), FRAME_ENCODED, AUDIO_EVENT,
       /*rtp_timestamp*/ 100u, /*frame_id*/ 0u, /*frame_size*/ 123,
-      /*key_frame*/ false, 0);
+      /*key_frame*/ false, 0, 0.01, 0.02);
   cast_environment_->Logging()->InsertFrameEventWithDelay(
       testing_clock_->NowTicks(), FRAME_PLAYOUT, AUDIO_EVENT,
       /*rtp_timestamp*/ 100u,
diff --git a/media/cast/logging/stats_event_subscriber_unittest.cc b/media/cast/logging/stats_event_subscriber_unittest.cc
index 4501454..bd6da06 100644
--- a/media/cast/logging/stats_event_subscriber_unittest.cc
+++ b/media/cast/logging/stats_event_subscriber_unittest.cc
@@ -99,7 +99,9 @@
           frame_id,
           1024,
           true,
-          5678);
+          5678,
+          9.10,
+          11.12);
     } else if (i < extra_frames) {
       dropped_frames++;
     }
@@ -159,7 +161,9 @@
         frame_id,
         size,
         true,
-        5678);
+        5678,
+        9.10,
+        11.12);
     last_event_time = sender_clock_->NowTicks();
 
     AdvanceClocks(base::TimeDelta::FromMicroseconds(35678));
@@ -553,7 +557,9 @@
         frame_id,
         1024,
         true,
-        5678);
+        5678,
+        9.10,
+        11.12);
   }
 
   // Send 3 packets for the last frame.
diff --git a/media/cast/sender/audio_encoder.cc b/media/cast/sender/audio_encoder.cc
index 3ded497..4173ff0 100644
--- a/media/cast/sender/audio_encoder.cc
+++ b/media/cast/sender/audio_encoder.cc
@@ -36,7 +36,7 @@
 
 // Base class that handles the common problem of feeding one or more AudioBus'
 // data into a buffer and then, once the buffer is full, encoding the signal and
-// emitting an EncodedFrame via the FrameEncodedCallback.
+// emitting a SenderEncodedFrame via the FrameEncodedCallback.
 //
 // Subclasses complete the implementation by handling the actual encoding
 // details.
@@ -114,6 +114,11 @@
     // Encode all audio in |audio_bus| into zero or more frames.
     int src_pos = 0;
     while (src_pos < audio_bus->frames()) {
+      // Note: This is used to compute the deadline utilization and so it uses
+      // the real-world clock instead of the CastEnvironment clock, the latter
+      // of which might be simulated.
+      const base::TimeTicks start_time = base::TimeTicks::Now();
+
       const int num_samples_to_xfer = std::min(
           samples_per_frame_ - buffer_fill_end_, audio_bus->frames() - src_pos);
       DCHECK_EQ(audio_bus->channels(), num_channels_);
@@ -125,8 +130,8 @@
       if (buffer_fill_end_ < samples_per_frame_)
         break;
 
-      scoped_ptr<EncodedFrame> audio_frame(
-          new EncodedFrame());
+      scoped_ptr<SenderEncodedFrame> audio_frame(
+          new SenderEncodedFrame());
       audio_frame->dependency = EncodedFrame::KEY;
       audio_frame->frame_id = frame_id_;
       audio_frame->referenced_frame_id = frame_id_;
@@ -134,6 +139,12 @@
       audio_frame->reference_time = frame_capture_time_;
 
       if (EncodeFromFilledBuffer(&audio_frame->data)) {
+        // Compute deadline utilization as the real-world time elapsed divided
+        // by the signal duration.
+        audio_frame->deadline_utilization =
+            (base::TimeTicks::Now() - start_time).InSecondsF() /
+                frame_duration_.InSecondsF();
+
         cast_environment_->PostTask(
             CastEnvironment::MAIN,
             FROM_HERE,
diff --git a/media/cast/sender/audio_encoder.h b/media/cast/sender/audio_encoder.h
index e692242..61ac08b 100644
--- a/media/cast/sender/audio_encoder.h
+++ b/media/cast/sender/audio_encoder.h
@@ -10,6 +10,7 @@
 #include "base/threading/thread_checker.h"
 #include "media/base/audio_bus.h"
 #include "media/cast/cast_environment.h"
+#include "media/cast/sender/sender_encoded_frame.h"
 
 namespace base {
 class TimeTicks;
@@ -20,10 +21,10 @@
 
 class AudioEncoder {
  public:
-  // Callback to deliver each EncodedFrame, plus the number of audio samples
-  // skipped since the last frame.
-  typedef base::Callback<void(scoped_ptr<EncodedFrame>, int)>
-      FrameEncodedCallback;
+  // Callback to deliver each SenderEncodedFrame, plus the number of audio
+  // samples skipped since the last frame.
+  using FrameEncodedCallback =
+      base::Callback<void(scoped_ptr<SenderEncodedFrame>, int)>;
 
   AudioEncoder(const scoped_refptr<CastEnvironment>& cast_environment,
                int num_channels,
diff --git a/media/cast/sender/audio_encoder_unittest.cc b/media/cast/sender/audio_encoder_unittest.cc
index 12b5f2c..70b5041 100644
--- a/media/cast/sender/audio_encoder_unittest.cc
+++ b/media/cast/sender/audio_encoder_unittest.cc
@@ -42,7 +42,7 @@
     samples_per_frame_ = samples_per_frame;
   }
 
-  void FrameEncoded(scoped_ptr<EncodedFrame> encoded_frame,
+  void FrameEncoded(scoped_ptr<SenderEncodedFrame> encoded_frame,
                     int samples_skipped) {
     EXPECT_EQ(encoded_frame->dependency, EncodedFrame::KEY);
     EXPECT_EQ(static_cast<uint8>(frames_received_ & 0xff),
@@ -59,6 +59,9 @@
     lower_bound_ = encoded_frame->reference_time;
     EXPECT_GT(upper_bound_, encoded_frame->reference_time);
 
+    EXPECT_LE(0.0, encoded_frame->deadline_utilization);
+    EXPECT_EQ(-1.0, encoded_frame->lossy_utilization);
+
     ++frames_received_;
   }
 
diff --git a/media/cast/sender/audio_sender.cc b/media/cast/sender/audio_sender.cc
index d084b364..87e4d3cca 100644
--- a/media/cast/sender/audio_sender.cc
+++ b/media/cast/sender/audio_sender.cc
@@ -110,7 +110,7 @@
 
 void AudioSender::OnEncodedAudioFrame(
     int encoder_bitrate,
-    scoped_ptr<EncodedFrame> encoded_frame,
+    scoped_ptr<SenderEncodedFrame> encoded_frame,
     int samples_skipped) {
   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
 
diff --git a/media/cast/sender/audio_sender.h b/media/cast/sender/audio_sender.h
index b6333b10..78006c6 100644
--- a/media/cast/sender/audio_sender.h
+++ b/media/cast/sender/audio_sender.h
@@ -52,7 +52,7 @@
  private:
   // Called by the |audio_encoder_| with the next EncodedFrame to send.
   void OnEncodedAudioFrame(int encoder_bitrate,
-                           scoped_ptr<EncodedFrame> encoded_frame,
+                           scoped_ptr<SenderEncodedFrame> encoded_frame,
                            int samples_skipped);
 
   // Encodes AudioBuses into EncodedFrames.
diff --git a/media/cast/sender/frame_sender.cc b/media/cast/sender/frame_sender.cc
index fc9aa36..a7d9a27 100644
--- a/media/cast/sender/frame_sender.cc
+++ b/media/cast/sender/frame_sender.cc
@@ -5,6 +5,7 @@
 #include "media/cast/sender/frame_sender.h"
 
 #include "base/trace_event/trace_event.h"
+#include "media/cast/sender/sender_encoded_frame.h"
 
 namespace media {
 namespace cast {
@@ -192,7 +193,7 @@
 
 void FrameSender::SendEncodedFrame(
     int requested_bitrate_before_encode,
-    scoped_ptr<EncodedFrame> encoded_frame) {
+    scoped_ptr<SenderEncodedFrame> encoded_frame) {
   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
 
   VLOG(2) << SENDER_SSRC << "About to send another frame: last_sent="
@@ -220,7 +221,9 @@
       encoded_frame->rtp_timestamp,
       frame_id, static_cast<int>(encoded_frame->data.size()),
       encoded_frame->dependency == EncodedFrame::KEY,
-      requested_bitrate_before_encode);
+      requested_bitrate_before_encode,
+      encoded_frame->deadline_utilization,
+      encoded_frame->lossy_utilization);
 
   RecordLatestFrameTimestamps(frame_id,
                               encoded_frame->reference_time,
diff --git a/media/cast/sender/frame_sender.h b/media/cast/sender/frame_sender.h
index 7a53c343..f264490 100644
--- a/media/cast/sender/frame_sender.h
+++ b/media/cast/sender/frame_sender.h
@@ -20,6 +20,8 @@
 namespace media {
 namespace cast {
 
+struct SenderEncodedFrame;
+
 class FrameSender {
  public:
   FrameSender(scoped_refptr<CastEnvironment> cast_environment,
@@ -45,7 +47,7 @@
 
   // Called by the encoder with the next EncodeFrame to send.
   void SendEncodedFrame(int requested_bitrate_before_encode,
-                        scoped_ptr<EncodedFrame> encoded_frame);
+                        scoped_ptr<SenderEncodedFrame> encoded_frame);
 
  protected:
   // Returns the number of frames in the encoder's backlog.
diff --git a/media/cast/sender/h264_vt_encoder_unittest.cc b/media/cast/sender/h264_vt_encoder_unittest.cc
index d9790a8..89e7c54 100644
--- a/media/cast/sender/h264_vt_encoder_unittest.cc
+++ b/media/cast/sender/h264_vt_encoder_unittest.cc
@@ -65,8 +65,8 @@
 // See comment in end2end_unittest.cc for details on this value.
 const double kVideoAcceptedPSNR = 38.0;
 
-void SavePipelineStatus(PipelineStatus* out_status, PipelineStatus in_status) {
-  *out_status = in_status;
+void SaveDecoderInitResult(bool* out_result, bool in_result) {
+  *out_result = in_result;
 }
 
 void SaveOperationalStatus(OperationalStatus* out_status,
@@ -132,13 +132,13 @@
   explicit EndToEndFrameChecker(const VideoDecoderConfig& config)
       : decoder_(base::MessageLoop::current()->task_runner()),
         count_frames_checked_(0) {
-    PipelineStatus pipeline_status;
+    bool decoder_init_result;
     decoder_.Initialize(
-        config, false, base::Bind(&SavePipelineStatus, &pipeline_status),
+        config, false, base::Bind(&SaveDecoderInitResult, &decoder_init_result),
         base::Bind(&EndToEndFrameChecker::CompareFrameWithExpected,
                    base::Unretained(this)));
     base::MessageLoop::current()->RunUntilIdle();
-    EXPECT_EQ(PIPELINE_OK, pipeline_status);
+    EXPECT_TRUE(decoder_init_result);
   }
 
   void PushExpectation(const scoped_refptr<VideoFrame>& frame) {
diff --git a/media/cast/sender/sender_encoded_frame.h b/media/cast/sender/sender_encoded_frame.h
index 5b9f6803..8a3b2fa 100644
--- a/media/cast/sender/sender_encoded_frame.h
+++ b/media/cast/sender/sender_encoded_frame.h
@@ -25,6 +25,8 @@
   // utilization, 1.0 representing 100% utilization, and values greater than 1.0
   // indicating the encode time took longer than the media duration of the
   // frame.  Negative values indicate the field was not computed.
+  //
+  // TODO(miu): Rename to encoder_cpu_utilization.
   double deadline_utilization;
 
   // The amount of "lossiness" needed to encode the frame within the targeted
@@ -37,6 +39,8 @@
   // very small, and values greater than 1.0 indicating the encoder cannot
   // encode the frame within the target bitrate (even at its lowest quality
   // setting).  Negative values indicate the field was not computed.
+  //
+  // TODO(miu): Rename to idealized_bitrate_utilization.
   double lossy_utilization;
 };
 
diff --git a/media/cast/sender/video_sender.cc b/media/cast/sender/video_sender.cc
index 383d8023..ebdde8e 100644
--- a/media/cast/sender/video_sender.cc
+++ b/media/cast/sender/video_sender.cc
@@ -26,11 +26,18 @@
 //
 // This is how many round trips we think we need on the network.
 const int kRoundTripsNeeded = 4;
+
 // This is an estimate of all the the constant time needed independent of
 // network quality (e.g., additional time that accounts for encode and decode
 // time).
 const int kConstantTimeMs = 75;
 
+// The target maximum utilization of the encoder and network resources.  This is
+// used to attenuate the actual measured utilization values in order to provide
+// "breathing room" (i.e., to ensure there will be sufficient CPU and bandwidth
+// available to handle the occasional more-complex frames).
+const int kTargetUtilizationPercentage = 75;
+
 // Extract capture begin/end timestamps from |video_frame|'s metadata and log
 // it.
 void LogVideoCaptureTimestamps(const CastEnvironment& cast_environment,
@@ -50,9 +57,9 @@
   cast_environment.Logging()->InsertFrameEvent(
       capture_begin_time, FRAME_CAPTURE_BEGIN, VIDEO_EVENT, rtp_timestamp,
       kFrameIdUnknown);
-  cast_environment.Logging()->InsertFrameEvent(
-      capture_end_time, FRAME_CAPTURE_END, VIDEO_EVENT, rtp_timestamp,
-      kFrameIdUnknown);
+  cast_environment.Logging()->InsertCapturedVideoFrameEvent(
+      capture_end_time, rtp_timestamp, video_frame.visible_rect().width(),
+      video_frame.visible_rect().height());
 }
 
 }  // namespace
@@ -208,6 +215,7 @@
           reference_time,
           base::Bind(&VideoSender::OnEncodedVideoFrame,
                      weak_factory_.GetWeakPtr(),
+                     video_frame,
                      bitrate))) {
     frames_in_encoder_++;
     duration_in_encoder_ += duration_added_by_next_frame;
@@ -241,6 +249,7 @@
 }
 
 void VideoSender::OnEncodedVideoFrame(
+    const scoped_refptr<media::VideoFrame>& video_frame,
     int encoder_bitrate,
     scoped_ptr<SenderEncodedFrame> encoded_frame) {
   DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
@@ -253,8 +262,23 @@
 
   last_reported_deadline_utilization_ = encoded_frame->deadline_utilization;
   last_reported_lossy_utilization_ = encoded_frame->lossy_utilization;
-  // TODO(miu): Plumb-in a utilization feedback signal back to the producer of
-  // the video frames.  http://crbug.com/156767
+
+  // Report the resource utilization for processing this frame.  Take the
+  // greater of the two utilization values and attenuate them such that the
+  // target utilization is reported as the maximum sustainable amount.
+  const double attenuated_utilization =
+      std::max(last_reported_deadline_utilization_,
+               last_reported_lossy_utilization_) /
+          (kTargetUtilizationPercentage / 100.0);
+  if (attenuated_utilization >= 0.0) {
+    // Key frames are artificially capped to 1.0 because their actual
+    // utilization is atypical compared to the other frames in the stream, and
+    // this can misguide the producer of the input video frames.
+    video_frame->metadata()->SetDouble(
+        media::VideoFrameMetadata::RESOURCE_UTILIZATION,
+        encoded_frame->dependency == EncodedFrame::KEY ?
+            std::min(1.0, attenuated_utilization) : attenuated_utilization);
+  }
 
   SendEncodedFrame(encoder_bitrate, encoded_frame.Pass());
 }
diff --git a/media/cast/sender/video_sender.h b/media/cast/sender/video_sender.h
index f9b49e2..ac5d6d06 100644
--- a/media/cast/sender/video_sender.h
+++ b/media/cast/sender/video_sender.h
@@ -23,7 +23,6 @@
 namespace cast {
 
 class CastTransportSender;
-struct SenderEncodedFrame;
 class VideoEncoder;
 class VideoFrameFactory;
 
@@ -67,7 +66,8 @@
 
  private:
   // Called by the |video_encoder_| with the next EncodedFrame to send.
-  void OnEncodedVideoFrame(int encoder_bitrate,
+  void OnEncodedVideoFrame(const scoped_refptr<media::VideoFrame>& video_frame,
+                           int encoder_bitrate,
                            scoped_ptr<SenderEncodedFrame> encoded_frame);
 
   // Encodes media::VideoFrame images into EncodedFrames.  Per configuration,
diff --git a/media/cast/sender/video_sender_unittest.cc b/media/cast/sender/video_sender_unittest.cc
index 1dbccf0..8100b22 100644
--- a/media/cast/sender/video_sender_unittest.cc
+++ b/media/cast/sender/video_sender_unittest.cc
@@ -563,5 +563,35 @@
   EXPECT_EQ(nullptr, video_sender_->CreateVideoFrameFactory().get());
 }
 
+TEST_F(VideoSenderTest, PopulatesResourceUtilizationInFrameMetadata) {
+  InitEncoder(false, true);
+  ASSERT_EQ(STATUS_INITIALIZED, operational_status_);
+
+  for (int i = 0; i < 3; ++i) {
+    scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
+    ASSERT_FALSE(video_frame->metadata()->HasKey(
+        media::VideoFrameMetadata::RESOURCE_UTILIZATION));
+
+    const base::TimeTicks reference_time = testing_clock_->NowTicks();
+    video_sender_->InsertRawVideoFrame(video_frame, reference_time);
+
+    // Run encode tasks.  VideoSender::OnEncodedVideoFrame() will be called once
+    // encoding of the frame is complete, and this is when the
+    // RESOURCE_UTILIZATION metadata is populated.
+    RunTasks(33);
+
+    // Check that the RESOURCE_UTILIZATION value is set and non-negative.  Don't
+    // check for specific values because they are dependent on real-world CPU
+    // encode time, which can vary across test runs.
+    double utilization = -1.0;
+    EXPECT_TRUE(video_frame->metadata()->GetDouble(
+        media::VideoFrameMetadata::RESOURCE_UTILIZATION, &utilization));
+    EXPECT_LE(0.0, utilization);
+    if (i == 0)
+      EXPECT_GE(1.0, utilization);  // Key frames never exceed 1.0.
+    DVLOG(1) << "Utilization computed by VideoSender is: " << utilization;
+  }
+}
+
 }  // namespace cast
 }  // namespace media
diff --git a/media/filters/audio_decoder_selector_unittest.cc b/media/filters/audio_decoder_selector_unittest.cc
index 2bb1f6d2..29570c9 100644
--- a/media/filters/audio_decoder_selector_unittest.cc
+++ b/media/filters/audio_decoder_selector_unittest.cc
@@ -196,8 +196,7 @@
   UseClearStream();
   InitializeDecoderSelector(kNoDecryptor, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(_, _, _))
-      .WillOnce(RunCallback<1>(PIPELINE_OK));
+  EXPECT_CALL(*decoder_1_, Initialize(_, _, _)).WillOnce(RunCallback<1>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_1_, IsNull()));
 
   SelectDecoder();
@@ -219,10 +218,8 @@
   UseClearStream();
   InitializeDecoderSelector(kNoDecryptor, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(_, _, _))
-      .WillOnce(RunCallback<1>(DECODER_ERROR_NOT_SUPPORTED));
-  EXPECT_CALL(*decoder_2_, Initialize(_, _, _))
-      .WillOnce(RunCallback<1>(PIPELINE_OK));
+  EXPECT_CALL(*decoder_1_, Initialize(_, _, _)).WillOnce(RunCallback<1>(false));
+  EXPECT_CALL(*decoder_2_, Initialize(_, _, _)).WillOnce(RunCallback<1>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_2_, IsNull()));
 
   SelectDecoder();
@@ -233,8 +230,7 @@
   UseClearStream();
   InitializeDecoderSelector(kNoDecryptor, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(_, _, _))
-      .WillOnce(RunCallback<1>(DECODER_ERROR_NOT_SUPPORTED));
+  EXPECT_CALL(*decoder_1_, Initialize(_, _, _)).WillOnce(RunCallback<1>(false));
   EXPECT_CALL(*decoder_2_, Initialize(_, _, _));
 
   SelectDecoderAndDestroy();
@@ -246,8 +242,7 @@
   UseClearStream();
   InitializeDecoderSelector(kDecryptOnly, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(_, _, _))
-      .WillOnce(RunCallback<1>(PIPELINE_OK));
+  EXPECT_CALL(*decoder_1_, Initialize(_, _, _)).WillOnce(RunCallback<1>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_1_, IsNull()));
 
   SelectDecoder();
@@ -297,8 +292,7 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kDecryptOnly, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(_, _, _))
-      .WillOnce(RunCallback<1>(PIPELINE_OK));
+  EXPECT_CALL(*decoder_1_, Initialize(_, _, _)).WillOnce(RunCallback<1>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_1_, NotNull()));
 
   SelectDecoder();
@@ -322,10 +316,8 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kDecryptOnly, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(_, _, _))
-      .WillOnce(RunCallback<1>(DECODER_ERROR_NOT_SUPPORTED));
-  EXPECT_CALL(*decoder_2_, Initialize(_, _, _))
-      .WillOnce(RunCallback<1>(PIPELINE_OK));
+  EXPECT_CALL(*decoder_1_, Initialize(_, _, _)).WillOnce(RunCallback<1>(false));
+  EXPECT_CALL(*decoder_2_, Initialize(_, _, _)).WillOnce(RunCallback<1>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_2_, NotNull()));
 
   SelectDecoder();
@@ -336,8 +328,7 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kDecryptOnly, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(_, _, _))
-      .WillOnce(RunCallback<1>(DECODER_ERROR_NOT_SUPPORTED));
+  EXPECT_CALL(*decoder_1_, Initialize(_, _, _)).WillOnce(RunCallback<1>(false));
   EXPECT_CALL(*decoder_2_, Initialize(_, _, _));
 
   SelectDecoderAndDestroy();
diff --git a/media/filters/audio_decoder_unittest.cc b/media/filters/audio_decoder_unittest.cc
index 42b00ee..cd38e42 100644
--- a/media/filters/audio_decoder_unittest.cc
+++ b/media/filters/audio_decoder_unittest.cc
@@ -161,14 +161,13 @@
   }
 
   void InitializeDecoder(const AudioDecoderConfig& config) {
-    InitializeDecoderWithStatus(config, PIPELINE_OK);
+    InitializeDecoderWithResult(config, true);
   }
 
-  void InitializeDecoderWithStatus(const AudioDecoderConfig& config,
-                                   PipelineStatus status) {
+  void InitializeDecoderWithResult(const AudioDecoderConfig& config,
+                                   bool success) {
     decoder_->Initialize(
-        config,
-        NewExpectedStatusCB(status),
+        config, NewExpectedBoolCB(success),
         base::Bind(&AudioDecoderTest::OnDecoderOutput, base::Unretained(this)));
     base::RunLoop().RunUntilIdle();
   }
@@ -403,7 +402,7 @@
       base::TimeDelta::FromMilliseconds(80),
       // Use a different codec delay than in the extradata.
       100);
-  InitializeDecoderWithStatus(decoder_config, DECODER_ERROR_NOT_SUPPORTED);
+  InitializeDecoderWithResult(decoder_config, false);
 }
 
 TEST_P(FFmpegAudioDecoderBehavioralTest, InitializeWithBadConfig) {
@@ -415,7 +414,7 @@
                                           NULL,
                                           0,
                                           false);
-  InitializeDecoderWithStatus(decoder_config, DECODER_ERROR_NOT_SUPPORTED);
+  InitializeDecoderWithResult(decoder_config, false);
 }
 
 const DecodedBufferExpectations kSfxOpusExpectations[] = {
diff --git a/media/filters/decoder_selector.cc b/media/filters/decoder_selector.cc
index 555a411..4463001 100644
--- a/media/filters/decoder_selector.cc
+++ b/media/filters/decoder_selector.cc
@@ -119,12 +119,11 @@
 }
 
 template <DemuxerStream::Type StreamType>
-void DecoderSelector<StreamType>::DecryptingDecoderInitDone(
-    PipelineStatus status) {
+void DecoderSelector<StreamType>::DecryptingDecoderInitDone(bool success) {
   DVLOG(2) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
 
-  if (status == PIPELINE_OK) {
+  if (success) {
     base::ResetAndReturn(&select_decoder_cb_)
         .Run(decoder_.Pass(), scoped_ptr<DecryptingDemuxerStream>());
     return;
@@ -179,11 +178,11 @@
 }
 
 template <DemuxerStream::Type StreamType>
-void DecoderSelector<StreamType>::DecoderInitDone(PipelineStatus status) {
+void DecoderSelector<StreamType>::DecoderInitDone(bool success) {
   DVLOG(2) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
 
-  if (status != PIPELINE_OK) {
+  if (!success) {
     decoder_.reset();
     InitializeDecoder();
     return;
diff --git a/media/filters/decoder_selector.h b/media/filters/decoder_selector.h
index 59c90f57..9fa591e 100644
--- a/media/filters/decoder_selector.h
+++ b/media/filters/decoder_selector.h
@@ -74,10 +74,10 @@
                      const base::Closure& waiting_for_decryption_key_cb);
 
  private:
-  void DecryptingDecoderInitDone(PipelineStatus status);
+  void DecryptingDecoderInitDone(bool success);
   void DecryptingDemuxerStreamInitDone(PipelineStatus status);
   void InitializeDecoder();
-  void DecoderInitDone(PipelineStatus status);
+  void DecoderInitDone(bool success);
   void ReturnNullDecoder();
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/media/filters/decoder_stream.cc b/media/filters/decoder_stream.cc
index d68aede..bacba00 100644
--- a/media/filters/decoder_stream.cc
+++ b/media/filters/decoder_stream.cc
@@ -379,7 +379,6 @@
     const scoped_refptr<Output>& output) {
   FUNCTION_DVLOG(2) << ": " << output->timestamp().InMilliseconds() << " ms";
   DCHECK(output.get());
-  DCHECK(!output->end_of_stream());
   DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER ||
          state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR)
       << state_;
@@ -507,7 +506,7 @@
 }
 
 template <DemuxerStream::Type StreamType>
-void DecoderStream<StreamType>::OnDecoderReinitialized(PipelineStatus status) {
+void DecoderStream<StreamType>::OnDecoderReinitialized(bool success) {
   FUNCTION_DVLOG(2);
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(state_, STATE_REINITIALIZING_DECODER);
@@ -518,7 +517,7 @@
   // Also, Reset() can be called during pending ReinitializeDecoder().
   // This function needs to handle them all!
 
-  if (status != PIPELINE_OK) {
+  if (!success) {
     // 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.
diff --git a/media/filters/decoder_stream.h b/media/filters/decoder_stream.h
index e5b0cfce..ce29ac0 100644
--- a/media/filters/decoder_stream.h
+++ b/media/filters/decoder_stream.h
@@ -36,7 +36,6 @@
   typedef DecoderStreamTraits<StreamType> StreamTraits;
   typedef typename StreamTraits::DecoderType Decoder;
   typedef typename StreamTraits::OutputType Output;
-  typedef typename StreamTraits::StreamInitCB InitCB;
   typedef typename Decoder::Status DecoderStatus;
 
   enum Status {
@@ -46,6 +45,9 @@
     DECODE_ERROR,  // Decoder returned decode error.
   };
 
+  // Indicates completion of a DecoderStream initialization.
+  typedef base::Callback<void(bool success)> InitCB;
+
   // Indicates completion of a DecoderStream read.
   typedef base::Callback<void(Status, const scoped_refptr<Output>&)> ReadCB;
 
@@ -155,7 +157,7 @@
   void ReinitializeDecoder();
 
   // Callback for Decoder reinitialization.
-  void OnDecoderReinitialized(PipelineStatus status);
+  void OnDecoderReinitialized(bool success);
 
   void CompleteDecoderReinitialization(bool success);
 
diff --git a/media/filters/decoder_stream_traits.cc b/media/filters/decoder_stream_traits.cc
index de8f8600..7583b172b 100644
--- a/media/filters/decoder_stream_traits.cc
+++ b/media/filters/decoder_stream_traits.cc
@@ -21,10 +21,10 @@
 void DecoderStreamTraits<DemuxerStream::AUDIO>::InitializeDecoder(
     DecoderType* decoder,
     DemuxerStream* stream,
-    const PipelineStatusCB& status_cb,
+    const InitCB& init_cb,
     const OutputCB& output_cb) {
   DCHECK(stream->audio_decoder_config().IsValidConfig());
-  decoder->Initialize(stream->audio_decoder_config(), status_cb, output_cb);
+  decoder->Initialize(stream->audio_decoder_config(), init_cb, output_cb);
 }
 
 void DecoderStreamTraits<DemuxerStream::AUDIO>::ReportStatistics(
@@ -47,12 +47,12 @@
 void DecoderStreamTraits<DemuxerStream::VIDEO>::InitializeDecoder(
     DecoderType* decoder,
     DemuxerStream* stream,
-    const PipelineStatusCB& status_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,
-                      status_cb, output_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 707ff1c..8caf2df1 100644
--- a/media/filters/decoder_stream_traits.h
+++ b/media/filters/decoder_stream_traits.h
@@ -26,13 +26,13 @@
   typedef AudioBuffer OutputType;
   typedef AudioDecoder DecoderType;
   typedef DecryptingAudioDecoder DecryptingDecoderType;
-  typedef base::Callback<void(bool success)> StreamInitCB;
+  typedef base::Callback<void(bool success)> InitCB;
   typedef base::Callback<void(const scoped_refptr<OutputType>&)> OutputCB;
 
   static std::string ToString();
   static void InitializeDecoder(DecoderType* decoder,
                                 DemuxerStream* stream,
-                                const PipelineStatusCB& status_cb,
+                                const InitCB& init_cb,
                                 const OutputCB& output_cb);
   static bool NeedsBitstreamConversion(DecoderType* decoder) { return false; }
   static void ReportStatistics(const StatisticsCB& statistics_cb,
@@ -45,13 +45,13 @@
   typedef VideoFrame OutputType;
   typedef VideoDecoder DecoderType;
   typedef DecryptingVideoDecoder DecryptingDecoderType;
-  typedef base::Callback<void(bool success)> StreamInitCB;
+  typedef base::Callback<void(bool success)> InitCB;
   typedef base::Callback<void(const scoped_refptr<OutputType>&)> OutputCB;
 
   static std::string ToString();
   static void InitializeDecoder(DecoderType* decoder,
                                 DemuxerStream* stream,
-                                const PipelineStatusCB& status_cb,
+                                const InitCB& init_cb,
                                 const OutputCB& output_cb);
   static bool NeedsBitstreamConversion(DecoderType* decoder);
   static void ReportStatistics(const StatisticsCB& statistics_cb,
diff --git a/media/filters/decrypting_audio_decoder.cc b/media/filters/decrypting_audio_decoder.cc
index 7c8f4b2..7b3d2796 100644
--- a/media/filters/decrypting_audio_decoder.cc
+++ b/media/filters/decrypting_audio_decoder.cc
@@ -48,7 +48,7 @@
 }
 
 void DecryptingAudioDecoder::Initialize(const AudioDecoderConfig& config,
-                                        const PipelineStatusCB& status_cb,
+                                        const InitCB& init_cb,
                                         const OutputCB& output_cb) {
   DVLOG(2) << "Initialize()";
   DCHECK(task_runner_->BelongsToCurrentThread());
@@ -56,18 +56,18 @@
   DCHECK(reset_cb_.is_null());
 
   weak_this_ = weak_factory_.GetWeakPtr();
-  init_cb_ = BindToCurrentLoop(status_cb);
+  init_cb_ = BindToCurrentLoop(init_cb);
   output_cb_ = BindToCurrentLoop(output_cb);
 
   if (!config.IsValidConfig()) {
     DLOG(ERROR) << "Invalid audio stream config.";
-    base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_DECODE);
+    base::ResetAndReturn(&init_cb_).Run(false);
     return;
   }
 
   // DecryptingAudioDecoder only accepts potentially encrypted stream.
   if (!config.is_encrypted()) {
-    base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
+    base::ResetAndReturn(&init_cb_).Run(false);
     return;
   }
 
@@ -162,7 +162,7 @@
     base::ResetAndReturn(&set_decryptor_ready_cb_).Run(DecryptorReadyCB());
   pending_buffer_to_decode_ = NULL;
   if (!init_cb_.is_null())
-    base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
+    base::ResetAndReturn(&init_cb_).Run(false);
   if (!decode_cb_.is_null())
     base::ResetAndReturn(&decode_cb_).Run(kAborted);
   if (!reset_cb_.is_null())
@@ -181,7 +181,7 @@
   set_decryptor_ready_cb_.Reset();
 
   if (!decryptor) {
-    base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
+    base::ResetAndReturn(&init_cb_).Run(false);
     state_ = kError;
     decryptor_attached_cb.Run(false);
     return;
@@ -210,7 +210,7 @@
   DCHECK(decode_cb_.is_null());  // No Decode() before initialization finished.
 
   if (!success) {
-    base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
+    base::ResetAndReturn(&init_cb_).Run(false);
     decryptor_ = NULL;
     state_ = kError;
     return;
@@ -226,7 +226,7 @@
           base::Bind(&DecryptingAudioDecoder::OnKeyAdded, weak_this_)));
 
   state_ = kIdle;
-  base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
+  base::ResetAndReturn(&init_cb_).Run(true);
 }
 
 void DecryptingAudioDecoder::DecodePendingBuffer() {
diff --git a/media/filters/decrypting_audio_decoder.h b/media/filters/decrypting_audio_decoder.h
index 30b0a63..e1cc048 100644
--- a/media/filters/decrypting_audio_decoder.h
+++ b/media/filters/decrypting_audio_decoder.h
@@ -39,7 +39,7 @@
   // AudioDecoder implementation.
   std::string GetDisplayName() const override;
   void Initialize(const AudioDecoderConfig& config,
-                  const PipelineStatusCB& status_cb,
+                  const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
               const DecodeCB& decode_cb) override;
@@ -93,7 +93,7 @@
 
   State state_;
 
-  PipelineStatusCB init_cb_;
+  InitCB init_cb_;
   OutputCB output_cb_;
   DecodeCB decode_cb_;
   base::Closure reset_cb_;
diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc
index 1f8395bf..bb82a4c 100644
--- a/media/filters/decrypting_audio_decoder_unittest.cc
+++ b/media/filters/decrypting_audio_decoder_unittest.cc
@@ -79,8 +79,8 @@
     Destroy();
   }
 
-  void InitializeAndExpectStatus(const AudioDecoderConfig& config,
-                                 PipelineStatus status) {
+  void InitializeAndExpectResult(const AudioDecoderConfig& config,
+                                 bool success) {
     // Initialize data now that the config is known. Since the code uses
     // invalid values (that CreateEmptyBuffer() doesn't support), tweak them
     // just for CreateEmptyBuffer().
@@ -94,7 +94,7 @@
                                                     kNoTimestamp());
     decoded_frame_list_.push_back(decoded_frame_);
 
-    decoder_->Initialize(config, NewExpectedStatusCB(status),
+    decoder_->Initialize(config, NewExpectedBoolCB(success),
                          base::Bind(&DecryptingAudioDecoderTest::FrameReady,
                                     base::Unretained(this)));
     message_loop_.RunUntilIdle();
@@ -119,7 +119,7 @@
     config_.Initialize(kCodecVorbis, kSampleFormatPlanarF32,
                        CHANNEL_LAYOUT_STEREO, kSampleRate, NULL, 0, true, true,
                        base::TimeDelta(), 0);
-    InitializeAndExpectStatus(config_, PIPELINE_OK);
+    InitializeAndExpectResult(config_, true);
   }
 
   void Reinitialize() {
@@ -132,7 +132,7 @@
         .WillOnce(RunCallback<1>(true));
     EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kAudio, _))
               .WillOnce(SaveArg<1>(&key_added_cb_));
-    decoder_->Initialize(new_config, NewExpectedStatusCB(PIPELINE_OK),
+    decoder_->Initialize(new_config, NewExpectedBoolCB(true),
                          base::Bind(&DecryptingAudioDecoderTest::FrameReady,
                                     base::Unretained(this)));
   }
@@ -288,7 +288,7 @@
   AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
                             CHANNEL_LAYOUT_STEREO, kSampleRate, NULL, 0, false);
 
-  InitializeAndExpectStatus(config, DECODER_ERROR_NOT_SUPPORTED);
+  InitializeAndExpectResult(config, false);
 }
 
 // Ensure decoder handles invalid audio configs without crashing.
@@ -296,7 +296,7 @@
   AudioDecoderConfig config(kUnknownAudioCodec, kUnknownSampleFormat,
                             CHANNEL_LAYOUT_STEREO, 0, NULL, 0, true);
 
-  InitializeAndExpectStatus(config, PIPELINE_ERROR_DECODE);
+  InitializeAndExpectResult(config, false);
 }
 
 // Ensure decoder handles unsupported audio configs without crashing.
@@ -307,14 +307,14 @@
 
   AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
                             CHANNEL_LAYOUT_STEREO, kSampleRate, NULL, 0, true);
-  InitializeAndExpectStatus(config, DECODER_ERROR_NOT_SUPPORTED);
+  InitializeAndExpectResult(config, false);
 }
 
 TEST_F(DecryptingAudioDecoderTest, Initialize_NullDecryptor) {
   ExpectDecryptorNotification(NULL, false);
   AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
                             CHANNEL_LAYOUT_STEREO, kSampleRate, NULL, 0, true);
-  InitializeAndExpectStatus(config, DECODER_ERROR_NOT_SUPPORTED);
+  InitializeAndExpectResult(config, false);
 }
 
 // Test normal decrypt and decode case.
diff --git a/media/filters/decrypting_video_decoder.cc b/media/filters/decrypting_video_decoder.cc
index 8f30331..3627080 100644
--- a/media/filters/decrypting_video_decoder.cc
+++ b/media/filters/decrypting_video_decoder.cc
@@ -39,7 +39,7 @@
 
 void DecryptingVideoDecoder::Initialize(const VideoDecoderConfig& config,
                                         bool /* low_delay */,
-                                        const PipelineStatusCB& status_cb,
+                                        const InitCB& init_cb,
                                         const OutputCB& output_cb) {
   DVLOG(2) << "Initialize()";
   DCHECK(task_runner_->BelongsToCurrentThread());
@@ -51,7 +51,7 @@
   DCHECK(config.IsValidConfig());
   DCHECK(config.is_encrypted());
 
-  init_cb_ = BindToCurrentLoop(status_cb);
+  init_cb_ = BindToCurrentLoop(init_cb);
   output_cb_ = BindToCurrentLoop(output_cb);
   weak_this_ = weak_factory_.GetWeakPtr();
   config_ = config;
@@ -146,7 +146,7 @@
     base::ResetAndReturn(&set_decryptor_ready_cb_).Run(DecryptorReadyCB());
   pending_buffer_to_decode_ = NULL;
   if (!init_cb_.is_null())
-    base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
+    base::ResetAndReturn(&init_cb_).Run(false);
   if (!decode_cb_.is_null())
     base::ResetAndReturn(&decode_cb_).Run(kAborted);
   if (!reset_cb_.is_null())
@@ -164,7 +164,7 @@
   set_decryptor_ready_cb_.Reset();
 
   if (!decryptor) {
-    base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
+    base::ResetAndReturn(&init_cb_).Run(false);
     state_ = kError;
     decryptor_attached_cb.Run(false);
     return;
@@ -189,7 +189,7 @@
   DCHECK(decode_cb_.is_null());  // No Decode() before initialization finished.
 
   if (!success) {
-    base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
+    base::ResetAndReturn(&init_cb_).Run(false);
     decryptor_ = NULL;
     state_ = kError;
     return;
@@ -202,7 +202,7 @@
 
   // Success!
   state_ = kIdle;
-  base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
+  base::ResetAndReturn(&init_cb_).Run(true);
 }
 
 
@@ -285,7 +285,7 @@
 
   DCHECK_EQ(status, Decryptor::kSuccess);
   // No frame returned with kSuccess should be end-of-stream frame.
-  DCHECK(!frame->end_of_stream());
+  DCHECK(!frame->IsEndOfStream());
   output_cb_.Run(frame);
 
   if (scoped_pending_buffer_to_decode->end_of_stream()) {
diff --git a/media/filters/decrypting_video_decoder.h b/media/filters/decrypting_video_decoder.h
index a2a9528..fda546e8f 100644
--- a/media/filters/decrypting_video_decoder.h
+++ b/media/filters/decrypting_video_decoder.h
@@ -36,7 +36,7 @@
   std::string GetDisplayName() const override;
   void Initialize(const VideoDecoderConfig& config,
                   bool low_delay,
-                  const PipelineStatusCB& status_cb,
+                  const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
               const DecodeCB& decode_cb) override;
@@ -85,7 +85,7 @@
 
   State state_;
 
-  PipelineStatusCB init_cb_;
+  InitCB init_cb_;
   OutputCB output_cb_;
   DecodeCB decode_cb_;
   base::Closure reset_cb_;
diff --git a/media/filters/decrypting_video_decoder_unittest.cc b/media/filters/decrypting_video_decoder_unittest.cc
index 285bab67..bc3f93a 100644
--- a/media/filters/decrypting_video_decoder_unittest.cc
+++ b/media/filters/decrypting_video_decoder_unittest.cc
@@ -81,11 +81,11 @@
     EXPECT_CALL(*this, DecryptorSet(expected_result));
   }
 
-  // Initializes the |decoder_| and expects |status|. Note the initialization
+  // Initializes the |decoder_| and expects |success|. Note the initialization
   // can succeed or fail.
-  void InitializeAndExpectStatus(const VideoDecoderConfig& config,
-                                 PipelineStatus status) {
-    decoder_->Initialize(config, false, NewExpectedStatusCB(status),
+  void InitializeAndExpectResult(const VideoDecoderConfig& config,
+                                 bool success) {
+    decoder_->Initialize(config, false, NewExpectedBoolCB(success),
                          base::Bind(&DecryptingVideoDecoderTest::FrameReady,
                                     base::Unretained(this)));
     message_loop_.RunUntilIdle();
@@ -99,7 +99,7 @@
     EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kVideo, _))
         .WillOnce(SaveArg<1>(&key_added_cb_));
 
-    InitializeAndExpectStatus(TestVideoConfig::NormalEncrypted(), PIPELINE_OK);
+    InitializeAndExpectResult(TestVideoConfig::NormalEncrypted(), true);
   }
 
   // Reinitialize the |decoder_| and expects it to succeed.
@@ -110,7 +110,7 @@
     EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kVideo, _))
         .WillOnce(SaveArg<1>(&key_added_cb_));
 
-    InitializeAndExpectStatus(TestVideoConfig::LargeEncrypted(), PIPELINE_OK);
+    InitializeAndExpectResult(TestVideoConfig::LargeEncrypted(), true);
   }
 
   // Decode |buffer| and expect DecodeDone to get called with |status|.
@@ -259,8 +259,7 @@
 
 TEST_F(DecryptingVideoDecoderTest, Initialize_NullDecryptor) {
   ExpectDecryptorNotification(NULL, false);
-  InitializeAndExpectStatus(TestVideoConfig::NormalEncrypted(),
-                            DECODER_ERROR_NOT_SUPPORTED);
+  InitializeAndExpectResult(TestVideoConfig::NormalEncrypted(), false);
 }
 
 TEST_F(DecryptingVideoDecoderTest, Initialize_Failure) {
@@ -270,8 +269,7 @@
       .WillRepeatedly(SaveArg<1>(&key_added_cb_));
   EXPECT_CALL(*this, RequestDecryptorNotification(_)).Times(2);
 
-  InitializeAndExpectStatus(TestVideoConfig::NormalEncrypted(),
-                            DECODER_ERROR_NOT_SUPPORTED);
+  InitializeAndExpectResult(TestVideoConfig::NormalEncrypted(), false);
 }
 
 TEST_F(DecryptingVideoDecoderTest, Reinitialize_Normal) {
@@ -289,9 +287,8 @@
       .WillOnce(RunCallback<1>(false));
 
   // Reinitialize() expects the reinitialization to succeed. Call
-  // InitializeAndExpectStatus() directly to test the reinitialization failure.
-  InitializeAndExpectStatus(TestVideoConfig::NormalEncrypted(),
-                            DECODER_ERROR_NOT_SUPPORTED);
+  // InitializeAndExpectResult() directly to test the reinitialization failure.
+  InitializeAndExpectResult(TestVideoConfig::NormalEncrypted(), false);
 }
 
 // Test normal decrypt and decode case.
@@ -413,9 +410,8 @@
   DecryptorReadyCB decryptor_ready_cb;
   EXPECT_CALL(*this, RequestDecryptorNotification(_))
       .WillOnce(SaveArg<0>(&decryptor_ready_cb));
-  decoder_->Initialize(TestVideoConfig::NormalEncrypted(),
-                       false,
-                       NewExpectedStatusCB(DECODER_ERROR_NOT_SUPPORTED),
+  decoder_->Initialize(TestVideoConfig::NormalEncrypted(), false,
+                       NewExpectedBoolCB(false),
                        base::Bind(&DecryptingVideoDecoderTest::FrameReady,
                                   base::Unretained(this)));
   message_loop_.RunUntilIdle();
@@ -439,8 +435,7 @@
   EXPECT_CALL(*decryptor_, InitializeVideoDecoder(_, _))
       .WillOnce(SaveArg<1>(&pending_init_cb_));
 
-  InitializeAndExpectStatus(TestVideoConfig::NormalEncrypted(),
-                            DECODER_ERROR_NOT_SUPPORTED);
+  InitializeAndExpectResult(TestVideoConfig::NormalEncrypted(), false);
   EXPECT_FALSE(pending_init_cb_.is_null());
 
   Destroy();
diff --git a/media/filters/fake_video_decoder.cc b/media/filters/fake_video_decoder.cc
index 4c6fa9a7..276a5ac 100644
--- a/media/filters/fake_video_decoder.cc
+++ b/media/filters/fake_video_decoder.cc
@@ -47,7 +47,7 @@
 
 void FakeVideoDecoder::Initialize(const VideoDecoderConfig& config,
                                   bool low_delay,
-                                  const PipelineStatusCB& status_cb,
+                                  const InitCB& init_cb,
                                   const OutputCB& output_cb) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(config.IsValidConfig());
@@ -56,7 +56,7 @@
   DCHECK(reset_cb_.IsNull()) << "No reinitialization during pending reset.";
 
   current_config_ = config;
-  init_cb_.SetCallback(BindToCurrentLoop(status_cb));
+  init_cb_.SetCallback(BindToCurrentLoop(init_cb));
 
   // Don't need BindToCurrentLoop() because |output_cb_| is only called from
   // RunDecodeCallback() which is posted from Decode().
@@ -69,10 +69,10 @@
 
   if (fail_to_initialize_) {
     state_ = STATE_ERROR;
-    init_cb_.RunOrHold(DECODER_ERROR_NOT_SUPPORTED);
+    init_cb_.RunOrHold(false);
   } else {
     state_ = STATE_NORMAL;
-    init_cb_.RunOrHold(PIPELINE_OK);
+    init_cb_.RunOrHold(true);
   }
 }
 
diff --git a/media/filters/fake_video_decoder.h b/media/filters/fake_video_decoder.h
index bf407b9..e784387 100644
--- a/media/filters/fake_video_decoder.h
+++ b/media/filters/fake_video_decoder.h
@@ -44,7 +44,7 @@
   std::string GetDisplayName() const override;
   void Initialize(const VideoDecoderConfig& config,
                   bool low_delay,
-                  const PipelineStatusCB& status_cb,
+                  const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
               const DecodeCB& decode_cb) override;
@@ -101,7 +101,7 @@
 
   State state_;
 
-  CallbackHolder<PipelineStatusCB> init_cb_;
+  CallbackHolder<InitCB> init_cb_;
   CallbackHolder<base::Closure> reset_cb_;
 
   OutputCB output_cb_;
diff --git a/media/filters/fake_video_decoder_unittest.cc b/media/filters/fake_video_decoder_unittest.cc
index 448dcdd..f335c02 100644
--- a/media/filters/fake_video_decoder_unittest.cc
+++ b/media/filters/fake_video_decoder_unittest.cc
@@ -47,17 +47,17 @@
     Destroy();
   }
 
-  void InitializeWithConfigAndExpectStatus(const VideoDecoderConfig& config,
-                                           PipelineStatus status) {
+  void InitializeWithConfigAndExpectResult(const VideoDecoderConfig& config,
+                                           bool success) {
     decoder_->Initialize(
-        config, false, NewExpectedStatusCB(status),
+        config, false, NewExpectedBoolCB(success),
         base::Bind(&FakeVideoDecoderTest::FrameReady, base::Unretained(this)));
     message_loop_.RunUntilIdle();
     current_config_ = config;
   }
 
   void Initialize() {
-    InitializeWithConfigAndExpectStatus(TestVideoConfig::Normal(), PIPELINE_OK);
+    InitializeWithConfigAndExpectResult(TestVideoConfig::Normal(), true);
   }
 
   void EnterPendingInitState() {
@@ -78,7 +78,7 @@
   }
 
   void FrameReady(const scoped_refptr<VideoFrame>& frame) {
-    DCHECK(!frame->end_of_stream());
+    DCHECK(!frame->IsEndOfStream());
     last_decoded_frame_ = frame;
     num_decoded_frames_++;
   }
@@ -252,8 +252,7 @@
 
 TEST_P(FakeVideoDecoderTest, SimulateFailureToInitialize) {
   decoder_->SimulateFailureToInit();
-  InitializeWithConfigAndExpectStatus(TestVideoConfig::Normal(),
-                                      DECODER_ERROR_NOT_SUPPORTED);
+  InitializeWithConfigAndExpectResult(TestVideoConfig::Normal(), false);
   Decode();
   EXPECT_EQ(last_decode_status_, VideoDecoder::kDecodeError);
 }
@@ -345,7 +344,7 @@
 TEST_P(FakeVideoDecoderTest, Reinitialize) {
   Initialize();
   ReadOneFrame();
-  InitializeWithConfigAndExpectStatus(TestVideoConfig::Large(), PIPELINE_OK);
+  InitializeWithConfigAndExpectResult(TestVideoConfig::Large(), true);
   ReadOneFrame();
 }
 
@@ -353,8 +352,7 @@
   Initialize();
   ReadOneFrame();
   decoder_->SimulateFailureToInit();
-  InitializeWithConfigAndExpectStatus(TestVideoConfig::Normal(),
-                                      DECODER_ERROR_NOT_SUPPORTED);
+  InitializeWithConfigAndExpectResult(TestVideoConfig::Normal(), false);
   Decode();
   EXPECT_EQ(last_decode_status_, VideoDecoder::kDecodeError);
 }
diff --git a/media/filters/ffmpeg_audio_decoder.cc b/media/filters/ffmpeg_audio_decoder.cc
index 2f8bf1b..22a907b 100644
--- a/media/filters/ffmpeg_audio_decoder.cc
+++ b/media/filters/ffmpeg_audio_decoder.cc
@@ -147,7 +147,7 @@
 }
 
 void FFmpegAudioDecoder::Initialize(const AudioDecoderConfig& config,
-                                    const PipelineStatusCB& status_cb,
+                                    const InitCB& init_cb,
                                     const OutputCB& output_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(!config.is_encrypted());
@@ -155,17 +155,17 @@
   FFmpegGlue::InitializeFFmpeg();
 
   config_ = config;
-  PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb);
+  InitCB bound_init_cb = BindToCurrentLoop(init_cb);
 
   if (!config.IsValidConfig() || !ConfigureDecoder()) {
-    initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
+    bound_init_cb.Run(false);
     return;
   }
 
   // Success!
   output_cb_ = BindToCurrentLoop(output_cb);
   state_ = kNormal;
-  initialize_cb.Run(PIPELINE_OK);
+  bound_init_cb.Run(true);
 }
 
 void FFmpegAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
diff --git a/media/filters/ffmpeg_audio_decoder.h b/media/filters/ffmpeg_audio_decoder.h
index c9429f9..2446ce5 100644
--- a/media/filters/ffmpeg_audio_decoder.h
+++ b/media/filters/ffmpeg_audio_decoder.h
@@ -38,7 +38,7 @@
   // AudioDecoder implementation.
   std::string GetDisplayName() const override;
   void Initialize(const AudioDecoderConfig& config,
-                  const PipelineStatusCB& status_cb,
+                  const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
               const DecodeCB& decode_cb) override;
diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc
index 5d03c80..43f72de 100644
--- a/media/filters/ffmpeg_video_decoder.cc
+++ b/media/filters/ffmpeg_video_decoder.cc
@@ -162,7 +162,7 @@
 
 void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config,
                                     bool low_delay,
-                                    const PipelineStatusCB& status_cb,
+                                    const InitCB& init_cb,
                                     const OutputCB& output_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(!config.is_encrypted());
@@ -171,10 +171,10 @@
   FFmpegGlue::InitializeFFmpeg();
 
   config_ = config;
-  PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb);
+  InitCB bound_init_cb = BindToCurrentLoop(init_cb);
 
   if (!config.IsValidConfig() || !ConfigureDecoder(low_delay)) {
-    initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
+    bound_init_cb.Run(false);
     return;
   }
 
@@ -182,7 +182,7 @@
 
   // Success!
   state_ = kNormal;
-  initialize_cb.Run(PIPELINE_OK);
+  bound_init_cb.Run(true);
 }
 
 void FFmpegVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
diff --git a/media/filters/ffmpeg_video_decoder.h b/media/filters/ffmpeg_video_decoder.h
index 8acc4c8..6cd1a52 100644
--- a/media/filters/ffmpeg_video_decoder.h
+++ b/media/filters/ffmpeg_video_decoder.h
@@ -39,7 +39,7 @@
   std::string GetDisplayName() const override;
   void Initialize(const VideoDecoderConfig& config,
                   bool low_delay,
-                  const PipelineStatusCB& status_cb,
+                  const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
               const DecodeCB& decode_cb) override;
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index d33a5723..160d18f2 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -68,16 +68,16 @@
     InitializeWithConfig(TestVideoConfig::Normal());
   }
 
-  void InitializeWithConfigAndStatus(const VideoDecoderConfig& config,
-                                     PipelineStatus status) {
-    decoder_->Initialize(config, false, NewExpectedStatusCB(status),
+  void InitializeWithConfigWithResult(const VideoDecoderConfig& config,
+                                      bool success) {
+    decoder_->Initialize(config, false, NewExpectedBoolCB(success),
                          base::Bind(&FFmpegVideoDecoderTest::FrameReady,
                                     base::Unretained(this)));
     message_loop_.RunUntilIdle();
   }
 
   void InitializeWithConfig(const VideoDecoderConfig& config) {
-    InitializeWithConfigAndStatus(config, PIPELINE_OK);
+    InitializeWithConfigWithResult(config, true);
   }
 
   void Reinitialize() {
@@ -188,7 +188,7 @@
   }
 
   void FrameReady(const scoped_refptr<VideoFrame>& frame) {
-    DCHECK(!frame->end_of_stream());
+    DCHECK(!frame->IsEndOfStream());
     output_frames_.push_back(frame);
   }
 
@@ -217,8 +217,7 @@
 
 TEST_F(FFmpegVideoDecoderTest, Initialize_UnsupportedDecoder) {
   // Test avcodec_find_decoder() returning NULL.
-  InitializeWithConfigAndStatus(TestVideoConfig::Invalid(),
-                                DECODER_ERROR_NOT_SUPPORTED);
+  InitializeWithConfigWithResult(TestVideoConfig::Invalid(), false);
 }
 
 TEST_F(FFmpegVideoDecoderTest, Initialize_UnsupportedPixelFormat) {
@@ -227,7 +226,7 @@
                             VideoFrame::UNKNOWN,
                             kCodedSize, kVisibleRect, kNaturalSize,
                             NULL, 0, false);
-  InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
+  InitializeWithConfigWithResult(config, false);
 }
 
 TEST_F(FFmpegVideoDecoderTest, Initialize_OpenDecoderFails) {
@@ -236,7 +235,7 @@
                             kVideoFormat,
                             kCodedSize, kVisibleRect, kNaturalSize,
                             NULL, 0, false);
-  InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
+  InitializeWithConfigWithResult(config, false);
 }
 
 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorZero) {
@@ -250,7 +249,7 @@
                             NULL,
                             0,
                             false);
-  InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
+  InitializeWithConfigWithResult(config, false);
 }
 
 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorZero) {
@@ -264,7 +263,7 @@
                             NULL,
                             0,
                             false);
-  InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
+  InitializeWithConfigWithResult(config, false);
 }
 
 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorNegative) {
@@ -278,7 +277,7 @@
                             NULL,
                             0,
                             false);
-  InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
+  InitializeWithConfigWithResult(config, false);
 }
 
 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorNegative) {
@@ -292,7 +291,7 @@
                             NULL,
                             0,
                             false);
-  InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
+  InitializeWithConfigWithResult(config, false);
 }
 
 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioNumeratorTooLarge) {
@@ -308,7 +307,7 @@
                             NULL,
                             0,
                             false);
-  InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
+  InitializeWithConfigWithResult(config, false);
 }
 
 TEST_F(FFmpegVideoDecoderTest, Initialize_AspectRatioDenominatorTooLarge) {
@@ -323,7 +322,7 @@
                             NULL,
                             0,
                             false);
-  InitializeWithConfigAndStatus(config, DECODER_ERROR_NOT_SUPPORTED);
+  InitializeWithConfigWithResult(config, false);
 }
 
 TEST_F(FFmpegVideoDecoderTest, Reinitialize_Normal) {
@@ -333,8 +332,7 @@
 
 TEST_F(FFmpegVideoDecoderTest, Reinitialize_Failure) {
   Initialize();
-  InitializeWithConfigAndStatus(TestVideoConfig::Invalid(),
-                                DECODER_ERROR_NOT_SUPPORTED);
+  InitializeWithConfigWithResult(TestVideoConfig::Invalid(), false);
 }
 
 TEST_F(FFmpegVideoDecoderTest, Reinitialize_AfterDecodeFrame) {
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
index 7211655..504ed84 100644
--- a/media/filters/gpu_video_decoder.cc
+++ b/media/filters/gpu_video_decoder.cc
@@ -105,15 +105,17 @@
       coded_size.height() >= min_resolution.height());
 }
 
-// Report |status| to UMA and run |cb| with it.  This is super-specific to the
+// Report |success| to UMA and run |cb| with it.  This is super-specific to the
 // UMA stat reported because the UMA_HISTOGRAM_ENUMERATION API requires a
 // callsite to always be called with the same stat name (can't parameterize it).
 static void ReportGpuVideoDecoderInitializeStatusToUMAAndRunCB(
-    const PipelineStatusCB& cb,
-    PipelineStatus status) {
+    const VideoDecoder::InitCB& cb,
+    bool success) {
+  // TODO(xhwang): Report |success| directly.
+  PipelineStatus status = success ? PIPELINE_OK : DECODER_ERROR_NOT_SUPPORTED;
   UMA_HISTOGRAM_ENUMERATION(
       "Media.GpuVideoDecoderInitializeStatus", status, PIPELINE_STATUS_MAX + 1);
-  cb.Run(status);
+  cb.Run(success);
 }
 
 std::string GpuVideoDecoder::GetDisplayName() const {
@@ -122,16 +124,16 @@
 
 void GpuVideoDecoder::Initialize(const VideoDecoderConfig& config,
                                  bool /* low_delay */,
-                                 const PipelineStatusCB& orig_status_cb,
+                                 const InitCB& init_cb,
                                  const OutputCB& output_cb) {
   DVLOG(3) << "Initialize()";
   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
   DCHECK(config.IsValidConfig());
   DCHECK(!config.is_encrypted());
 
-  PipelineStatusCB status_cb =
+  InitCB bound_init_cb =
       base::Bind(&ReportGpuVideoDecoderInitializeStatusToUMAAndRunCB,
-                 BindToCurrentLoop(orig_status_cb));
+                 BindToCurrentLoop(init_cb));
 
   bool previously_initialized = config_.IsValidConfig();
   DVLOG(1) << "(Re)initializing GVD with config: "
@@ -141,12 +143,12 @@
   // (http://crbug.com/260224).
   if (previously_initialized && (config_.profile() != config.profile())) {
     DVLOG(1) << "Codec or profile changed, cannot reinitialize.";
-    status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
+    bound_init_cb.Run(false);
     return;
   }
 
   if (!IsProfileSupported(config.profile(), config.coded_size())) {
-    status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
+    bound_init_cb.Run(false);
     return;
   }
 
@@ -158,18 +160,18 @@
     // Reinitialization with a different config (but same codec and profile).
     // VDA should handle it by detecting this in-stream by itself,
     // no need to notify it.
-    status_cb.Run(PIPELINE_OK);
+    bound_init_cb.Run(true);
     return;
   }
 
   vda_ = factories_->CreateVideoDecodeAccelerator().Pass();
   if (!vda_ || !vda_->Initialize(config.profile(), this)) {
-    status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
+    bound_init_cb.Run(false);
     return;
   }
 
   DVLOG(3) << "GpuVideoDecoder::Initialize() succeeded.";
-  status_cb.Run(PIPELINE_OK);
+  bound_init_cb.Run(true);
 }
 
 void GpuVideoDecoder::DestroyPictureBuffers(PictureBufferMap* buffers) {
diff --git a/media/filters/gpu_video_decoder.h b/media/filters/gpu_video_decoder.h
index 49ede615..28eceb3 100644
--- a/media/filters/gpu_video_decoder.h
+++ b/media/filters/gpu_video_decoder.h
@@ -44,7 +44,7 @@
   std::string GetDisplayName() const override;
   void Initialize(const VideoDecoderConfig& config,
                   bool low_delay,
-                  const PipelineStatusCB& status_cb,
+                  const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
               const DecodeCB& decode_cb) override;
diff --git a/media/filters/opus_audio_decoder.cc b/media/filters/opus_audio_decoder.cc
index 51484ea..181f340 100644
--- a/media/filters/opus_audio_decoder.cc
+++ b/media/filters/opus_audio_decoder.cc
@@ -254,20 +254,20 @@
 }
 
 void OpusAudioDecoder::Initialize(const AudioDecoderConfig& config,
-                                  const PipelineStatusCB& status_cb,
+                                  const InitCB& init_cb,
                                   const OutputCB& output_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb);
+  InitCB bound_init_cb = BindToCurrentLoop(init_cb);
 
   config_ = config;
   output_cb_ = BindToCurrentLoop(output_cb);
 
   if (!ConfigureDecoder()) {
-    initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
+    bound_init_cb.Run(false);
     return;
   }
 
-  initialize_cb.Run(PIPELINE_OK);
+  bound_init_cb.Run(true);
 }
 
 void OpusAudioDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
diff --git a/media/filters/opus_audio_decoder.h b/media/filters/opus_audio_decoder.h
index b3fb188b..3b0cd716 100644
--- a/media/filters/opus_audio_decoder.h
+++ b/media/filters/opus_audio_decoder.h
@@ -33,7 +33,7 @@
   // AudioDecoder implementation.
   std::string GetDisplayName() const override;
   void Initialize(const AudioDecoderConfig& config,
-                  const PipelineStatusCB& status_cb,
+                  const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
               const DecodeCB& decode_cb) override;
diff --git a/media/filters/video_decoder_selector_unittest.cc b/media/filters/video_decoder_selector_unittest.cc
index 86f4c0ec..2471e76 100644
--- a/media/filters/video_decoder_selector_unittest.cc
+++ b/media/filters/video_decoder_selector_unittest.cc
@@ -194,7 +194,7 @@
   InitializeDecoderSelector(kNoDecryptor, 1);
 
   EXPECT_CALL(*decoder_1_, Initialize(_, _, _, _))
-      .WillOnce(RunCallback<2>(PIPELINE_OK));
+      .WillOnce(RunCallback<2>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_1_, IsNull()));
 
   SelectDecoder();
@@ -217,9 +217,9 @@
   InitializeDecoderSelector(kNoDecryptor, 2);
 
   EXPECT_CALL(*decoder_1_, Initialize(_, _, _, _))
-      .WillOnce(RunCallback<2>(DECODER_ERROR_NOT_SUPPORTED));
+      .WillOnce(RunCallback<2>(false));
   EXPECT_CALL(*decoder_2_, Initialize(_, _, _, _))
-      .WillOnce(RunCallback<2>(PIPELINE_OK));
+      .WillOnce(RunCallback<2>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_2_, IsNull()));
 
   SelectDecoder();
@@ -231,7 +231,7 @@
   InitializeDecoderSelector(kNoDecryptor, 2);
 
   EXPECT_CALL(*decoder_1_, Initialize(_, _, _, _))
-      .WillOnce(RunCallback<2>(DECODER_ERROR_NOT_SUPPORTED));
+      .WillOnce(RunCallback<2>(false));
   EXPECT_CALL(*decoder_2_, Initialize(_, _, _, _));
 
   SelectDecoderAndDestroy();
@@ -244,7 +244,7 @@
   InitializeDecoderSelector(kDecryptOnly, 1);
 
   EXPECT_CALL(*decoder_1_, Initialize(_, _, _, _))
-      .WillOnce(RunCallback<2>(PIPELINE_OK));
+      .WillOnce(RunCallback<2>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_1_, IsNull()));
 
   SelectDecoder();
@@ -295,7 +295,7 @@
   InitializeDecoderSelector(kDecryptOnly, 1);
 
   EXPECT_CALL(*decoder_1_, Initialize(_, _, _, _))
-      .WillOnce(RunCallback<2>(PIPELINE_OK));
+      .WillOnce(RunCallback<2>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_1_, NotNull()));
 
   SelectDecoder();
@@ -320,9 +320,9 @@
   InitializeDecoderSelector(kDecryptOnly, 2);
 
   EXPECT_CALL(*decoder_1_, Initialize(_, _, _, _))
-      .WillOnce(RunCallback<2>(DECODER_ERROR_NOT_SUPPORTED));
+      .WillOnce(RunCallback<2>(false));
   EXPECT_CALL(*decoder_2_, Initialize(_, _, _, _))
-      .WillOnce(RunCallback<2>(PIPELINE_OK));
+      .WillOnce(RunCallback<2>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_2_, NotNull()));
 
   SelectDecoder();
@@ -334,7 +334,7 @@
   InitializeDecoderSelector(kDecryptOnly, 2);
 
   EXPECT_CALL(*decoder_1_, Initialize(_, _, _, _))
-      .WillOnce(RunCallback<2>(DECODER_ERROR_NOT_SUPPORTED));
+      .WillOnce(RunCallback<2>(false));
   EXPECT_CALL(*decoder_2_, Initialize(_, _, _, _));
 
   SelectDecoderAndDestroy();
diff --git a/media/filters/video_frame_stream_unittest.cc b/media/filters/video_frame_stream_unittest.cc
index d35b57b..316a538 100644
--- a/media/filters/video_frame_stream_unittest.cc
+++ b/media/filters/video_frame_stream_unittest.cc
@@ -189,7 +189,7 @@
     DCHECK(pending_read_);
     frame_read_ = frame;
     last_read_status_ = status;
-    if (frame.get() && !frame->end_of_stream())
+    if (frame.get() && !frame->IsEndOfStream())
       num_decoded_frames_++;
     pending_read_ = false;
   }
@@ -223,7 +223,7 @@
   void ReadAllFrames() {
     do {
       ReadOneFrame();
-    } while (frame_read_.get() && !frame_read_->end_of_stream());
+    } while (frame_read_.get() && !frame_read_->IsEndOfStream());
 
     const int total_num_frames = kNumConfigs * kNumBuffersInOneConfig;
     DCHECK_EQ(num_decoded_frames_, total_num_frames);
@@ -576,7 +576,7 @@
 
   // The read output should indicate end of stream.
   ASSERT_TRUE(frame_read_.get());
-  EXPECT_TRUE(frame_read_->end_of_stream());
+  EXPECT_TRUE(frame_read_->IsEndOfStream());
 }
 
 // No Reset() before initialization is successfully completed.
diff --git a/media/filters/video_renderer_algorithm.cc b/media/filters/video_renderer_algorithm.cc
index 59b6d51b..d29cad8 100644
--- a/media/filters/video_renderer_algorithm.cc
+++ b/media/filters/video_renderer_algorithm.cc
@@ -355,7 +355,7 @@
 void VideoRendererAlgorithm::EnqueueFrame(
     const scoped_refptr<VideoFrame>& frame) {
   DCHECK(frame);
-  DCHECK(!frame->end_of_stream());
+  DCHECK(!frame->IsEndOfStream());
 
   ReadyFrame ready_frame(frame);
   auto it = frame_queue_.empty() ? frame_queue_.end()
diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc
index 01338c3..26b60fa 100644
--- a/media/filters/vpx_video_decoder.cc
+++ b/media/filters/vpx_video_decoder.cc
@@ -209,15 +209,17 @@
 
 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config,
                                  bool low_delay,
-                                 const PipelineStatusCB& status_cb,
+                                 const InitCB& init_cb,
                                  const OutputCB& output_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(config.IsValidConfig());
   DCHECK(!config.is_encrypted());
   DCHECK(decode_cb_.is_null());
 
+  InitCB bound_init_cb = BindToCurrentLoop(init_cb);
+
   if (!ConfigureDecoder(config)) {
-    status_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
+    bound_init_cb.Run(false);
     return;
   }
 
@@ -225,7 +227,7 @@
   config_ = config;
   state_ = kNormal;
   output_cb_ = BindToCurrentLoop(output_cb);
-  status_cb.Run(PIPELINE_OK);
+  bound_init_cb.Run(true);
 }
 
 static vpx_codec_ctx* InitializeVpxContext(vpx_codec_ctx* context,
diff --git a/media/filters/vpx_video_decoder.h b/media/filters/vpx_video_decoder.h
index 72d7a2c..bbf9895 100644
--- a/media/filters/vpx_video_decoder.h
+++ b/media/filters/vpx_video_decoder.h
@@ -35,7 +35,7 @@
   std::string GetDisplayName() const override;
   void Initialize(const VideoDecoderConfig& config,
                   bool low_delay,
-                  const PipelineStatusCB& status_cb,
+                  const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
               const DecodeCB& decode_cb) override;
diff --git a/media/media.gyp b/media/media.gyp
index 7e36cff..4427bf0 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -35,11 +35,6 @@
         'use_alsa%': 0,
         'use_pulseaudio%': 0,
       }],
-      ['sysroot!=""', {
-        'pkg-config': '../build/linux/pkg-config-wrapper "<(sysroot)" "<(target_arch)" "<(system_libdir)"',
-      }, {
-        'pkg-config': 'pkg-config'
-      }],
       # low memory buffer is used in non-Android based chromecast build due to hardware limitation.
       ['chromecast==1 and OS!="android"', {
         'use_low_memory_buffer%': 1,
@@ -1046,10 +1041,12 @@
         ['target_arch=="ia32" or target_arch=="x64"', {
           'dependencies': [
             'media_asm',
-            'media_sse2',
           ],
           'sources': [
+            'base/simd/convert_rgb_to_yuv_sse2.cc',
+            'base/simd/convert_rgb_to_yuv_ssse3.cc',
             'base/simd/convert_yuv_to_rgb_x86.cc',
+            'base/simd/filter_yuv_sse2.cc',
           ],
         }],
         ['OS!="linux" and OS!="win"', {
@@ -1645,25 +1642,6 @@
             '../third_party/yasm/yasm_compile.gypi',
           ],
         },
-        {
-          # GN version: //media/base:media_sse2
-          'target_name': 'media_sse2',
-          'type': 'static_library',
-          'cflags': [
-            '-msse2',
-          ],
-          'defines': [
-            'MEDIA_IMPLEMENTATION',
-          ],
-          'include_dirs': [
-            '..',
-          ],
-          'sources': [
-            'base/simd/convert_rgb_to_yuv_sse2.cc',
-            'base/simd/convert_rgb_to_yuv_ssse3.cc',
-            'base/simd/filter_yuv_sse2.cc',
-          ],
-        },
       ], # targets
     }],
     ['OS=="android"', {
diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc
index fe439e25..59f05b3 100644
--- a/media/renderers/audio_renderer_impl.cc
+++ b/media/renderers/audio_renderer_impl.cc
@@ -135,6 +135,7 @@
 
   base::AutoUnlock auto_unlock(lock_);
   sink_->Pause();
+  stop_rendering_time_ = last_render_time_;
 }
 
 void AudioRendererImpl::SetMediaTime(base::TimeDelta time) {
@@ -147,7 +148,7 @@
 
   start_timestamp_ = time;
   ended_timestamp_ = kInfiniteDuration();
-  last_render_ticks_ = base::TimeTicks();
+  last_render_time_ = stop_rendering_time_ = base::TimeTicks();
   first_packet_timestamp_ = kNoTimestamp();
   audio_clock_.reset(new AudioClock(time, audio_parameters_.sample_rate()));
 }
@@ -170,8 +171,9 @@
     const std::vector<base::TimeDelta>& media_timestamps,
     std::vector<base::TimeTicks>* wall_clock_times) {
   base::AutoLock auto_lock(lock_);
-  if (last_render_ticks_.is_null() || !playback_rate_ ||
-      buffering_state_ != BUFFERING_HAVE_ENOUGH || !sink_playing_) {
+  if (last_render_time_.is_null() || !stop_rendering_time_.is_null() ||
+      !playback_rate_ || buffering_state_ != BUFFERING_HAVE_ENOUGH ||
+      !sink_playing_) {
     return false;
   }
 
@@ -188,7 +190,7 @@
     } else {
       // No need to estimate time, so return the actual wallclock time.
       wall_clock_times->push_back(
-          last_render_ticks_ +
+          last_render_time_ +
           audio_clock_->TimeUntilPlayback(media_timestamp));
       continue;
     }
@@ -196,7 +198,7 @@
     // In practice, most calls will be estimates given the relatively small
     // window in which clients can get the actual time.
     wall_clock_times->push_back(
-        last_render_ticks_ + audio_clock_->TimeUntilPlayback(base_time) +
+        last_render_time_ + audio_clock_->TimeUntilPlayback(base_time) +
         base::TimeDelta::FromMicroseconds(
             (media_timestamp - base_time).InMicroseconds() / playback_rate_));
   }
@@ -594,7 +596,12 @@
   int frames_written = 0;
   {
     base::AutoLock auto_lock(lock_);
-    last_render_ticks_ = base::TimeTicks::Now();
+    last_render_time_ = base::TimeTicks::Now();
+
+    if (!stop_rendering_time_.is_null()) {
+      // TODO(dalecurtis): Use |stop_rendering_time_| to advance the AudioClock.
+      stop_rendering_time_ = base::TimeTicks();
+    }
 
     // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread.
     if (!algorithm_) {
diff --git a/media/renderers/audio_renderer_impl.h b/media/renderers/audio_renderer_impl.h
index 0f55f09..43d12eab 100644
--- a/media/renderers/audio_renderer_impl.h
+++ b/media/renderers/audio_renderer_impl.h
@@ -254,7 +254,11 @@
 
   // Set every Render() and used to provide an interpolated time value to
   // CurrentMediaTimeForSyncingVideo().
-  base::TimeTicks last_render_ticks_;
+  base::TimeTicks last_render_time_;
+
+  // Set to the value of |last_render_time_| when StopRendering_Locked() is
+  // called for any reason.  Cleared by the next successful Render() call.
+  base::TimeTicks stop_rendering_time_;
 
   // Set upon receipt of the first decoded buffer after a StartPlayingFrom().
   // Used to determine how long to delay playback.
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc
index 119fb76b..e65dd4b 100644
--- a/media/renderers/audio_renderer_impl_unittest.cc
+++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -106,8 +106,7 @@
 
   void ExpectUnsupportedAudioDecoder() {
     EXPECT_CALL(*decoder_, Initialize(_, _, _))
-        .WillOnce(DoAll(SaveArg<2>(&output_cb_),
-                        RunCallback<1>(DECODER_ERROR_NOT_SUPPORTED)));
+        .WillOnce(DoAll(SaveArg<2>(&output_cb_), RunCallback<1>(false)));
   }
 
   MOCK_METHOD1(OnStatistics, void(const PipelineStatistics&));
@@ -131,8 +130,7 @@
 
   void Initialize() {
     EXPECT_CALL(*decoder_, Initialize(_, _, _))
-        .WillOnce(DoAll(SaveArg<2>(&output_cb_),
-                        RunCallback<1>(PIPELINE_OK)));
+        .WillOnce(DoAll(SaveArg<2>(&output_cb_), RunCallback<1>(true)));
     InitializeWithStatus(PIPELINE_OK);
 
     next_timestamp_.reset(new AudioTimestampHelper(kInputSamplesPerSecond));
@@ -150,8 +148,7 @@
   }
 
   void InitializeAndDestroy() {
-    EXPECT_CALL(*decoder_, Initialize(_, _, _))
-        .WillOnce(RunCallback<1>(PIPELINE_OK));
+    EXPECT_CALL(*decoder_, Initialize(_, _, _)).WillOnce(RunCallback<1>(true));
 
     WaitableMessageLoopEvent event;
     InitializeRenderer(event.GetPipelineStatusCB());
@@ -176,7 +173,7 @@
     event.RunAndWaitForStatus(PIPELINE_ERROR_ABORT);
   }
 
-  void EnterPendingDecoderInitState(PipelineStatusCB cb) {
+  void EnterPendingDecoderInitState(const AudioDecoder::InitCB& cb) {
     init_decoder_cb_ = cb;
   }
 
@@ -398,7 +395,7 @@
   // Run during DecodeDecoder() to unblock WaitForPendingRead().
   base::Closure wait_for_pending_decode_cb_;
 
-  PipelineStatusCB init_decoder_cb_;
+  AudioDecoder::InitCB init_decoder_cb_;
   bool ended_;
 
   DISALLOW_COPY_AND_ASSIGN(AudioRendererImplTest);
diff --git a/media/renderers/video_renderer_impl.cc b/media/renderers/video_renderer_impl.cc
index 88d92c54..2bb45472 100644
--- a/media/renderers/video_renderer_impl.cc
+++ b/media/renderers/video_renderer_impl.cc
@@ -486,7 +486,7 @@
       return;
     }
 
-    if (frame->end_of_stream()) {
+    if (frame->IsEndOfStream()) {
       DCHECK(!received_end_of_stream_);
       received_end_of_stream_ = true;
 
@@ -590,7 +590,7 @@
     const scoped_refptr<VideoFrame>& frame) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   lock_.AssertAcquired();
-  DCHECK(!frame->end_of_stream());
+  DCHECK(!frame->IsEndOfStream());
 
   frames_decoded_++;
 
diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc
index aa494cb..75c599e 100644
--- a/media/renderers/video_renderer_impl_unittest.cc
+++ b/media/renderers/video_renderer_impl_unittest.cc
@@ -97,24 +97,26 @@
         .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FlushRequested));
 
     // Initialize, we shouldn't have any reads.
-    InitializeRenderer(PIPELINE_OK, low_delay);
+    InitializeRenderer(low_delay, true);
   }
 
-  void InitializeRenderer(PipelineStatus expected, bool low_delay) {
-    SCOPED_TRACE(base::StringPrintf("InitializeRenderer(%d)", expected));
+  void InitializeRenderer(bool low_delay, bool expect_to_success) {
+    SCOPED_TRACE(
+        base::StringPrintf("InitializeRenderer(%d)", expect_to_success));
     WaitableMessageLoopEvent event;
-    CallInitialize(event.GetPipelineStatusCB(), low_delay, expected);
-    event.RunAndWaitForStatus(expected);
+    CallInitialize(event.GetPipelineStatusCB(), low_delay, expect_to_success);
+    event.RunAndWaitForStatus(expect_to_success ? PIPELINE_OK
+                                                : DECODER_ERROR_NOT_SUPPORTED);
   }
 
   void CallInitialize(const PipelineStatusCB& status_cb,
                       bool low_delay,
-                      PipelineStatus decoder_status) {
+                      bool expect_to_success) {
     if (low_delay)
       demuxer_stream_.set_liveness(DemuxerStream::LIVENESS_LIVE);
     EXPECT_CALL(*decoder_, Initialize(_, _, _, _))
         .WillOnce(
-            DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(decoder_status)));
+            DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(expect_to_success)));
     EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
     renderer_->Initialize(
         &demuxer_stream_, status_cb, media::SetDecryptorReadyCB(),
@@ -530,7 +532,7 @@
 }
 
 TEST_P(VideoRendererImplTest, VideoDecoder_InitFailure) {
-  InitializeRenderer(DECODER_ERROR_NOT_SUPPORTED, false);
+  InitializeRenderer(false, false);
   Destroy();
 }
 
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index 78ebfe0..dcbb66d 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -663,7 +663,9 @@
         .Times(AtMost(1))
         .WillRepeatedly(SaveArg<0>(&metadata_));
     EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH))
-        .Times(AtMost(1));
+        .Times(AnyNumber());
+    EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_NOTHING))
+        .Times(AnyNumber());
 
     // Encrypted content not used, so this is never called.
     EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
@@ -700,7 +702,9 @@
         .Times(AtMost(1))
         .WillRepeatedly(SaveArg<0>(&metadata_));
     EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH))
-        .Times(AtMost(1));
+        .Times(AnyNumber());
+    EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_NOTHING))
+        .Times(AnyNumber());
     EXPECT_CALL(*this, DecryptorAttached(true));
 
     // Encrypted content used but keys provided in advance, so this is
diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc
index 72a8b97f..3953bed2 100644
--- a/media/test/pipeline_integration_test_base.cc
+++ b/media/test/pipeline_integration_test_base.cc
@@ -25,6 +25,7 @@
 
 using ::testing::_;
 using ::testing::AnyNumber;
+using ::testing::AtLeast;
 using ::testing::AtMost;
 using ::testing::Invoke;
 using ::testing::InvokeWithoutArgs;
@@ -113,7 +114,9 @@
       .Times(AtMost(1))
       .WillRepeatedly(SaveArg<0>(&metadata_));
   EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH))
-      .Times(AtMost(1));
+      .Times(AnyNumber());
+  EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_NOTHING))
+      .Times(AnyNumber());
   CreateDemuxer(filename);
 
   if (cdm_context) {
diff --git a/media/video/capture/file_video_capture_device.cc b/media/video/capture/file_video_capture_device.cc
index 5584c0b..5a45b4a 100644
--- a/media/video/capture/file_video_capture_device.cc
+++ b/media/video/capture/file_video_capture_device.cc
@@ -210,6 +210,7 @@
   current_byte_index_ = 0;
   first_frame_byte_index_ = 0;
   frame_size_ = 0;
+  next_frame_time_ = base::TimeTicks();
   video_frame_.reset();
 }
 
@@ -217,7 +218,6 @@
   DCHECK_EQ(capture_thread_.message_loop(), base::MessageLoop::current());
   if (!client_)
     return;
-  const base::TimeTicks timestamp_before_reading = base::TimeTicks::Now();
   int result = file_.Read(current_byte_index_,
                           reinterpret_cast<char*>(video_frame_.get()),
                           frame_size_);
@@ -236,25 +236,25 @@
   }
 
   // Give the captured frame to the client.
+  const base::TimeTicks current_time = base::TimeTicks::Now();
   client_->OnIncomingCapturedData(video_frame_.get(),
                                   frame_size_,
                                   capture_format_,
                                   0,
-                                  base::TimeTicks::Now());
+                                  current_time);
   // Reschedule next CaptureTask.
   const base::TimeDelta frame_interval =
       base::TimeDelta::FromMicroseconds(1E6 / capture_format_.frame_rate);
-  base::TimeDelta next_on_capture_timedelta = frame_interval -
-      (base::TimeTicks::Now() - timestamp_before_reading);
-  if (next_on_capture_timedelta.InMilliseconds() < 0) {
-    DLOG(WARNING) << "Frame reading took longer than the frame interval.";
-    next_on_capture_timedelta = frame_interval;
+  if (next_frame_time_.is_null()) {
+    next_frame_time_ = current_time + frame_interval;
+  } else {
+    next_frame_time_ += frame_interval;
   }
   base::MessageLoop::current()->PostDelayedTask(
       FROM_HERE,
       base::Bind(&FileVideoCaptureDevice::OnCaptureTask,
                  base::Unretained(this)),
-      next_on_capture_timedelta);
+      next_frame_time_ - current_time);
 }
 
 }  // namespace media
diff --git a/media/video/capture/file_video_capture_device.h b/media/video/capture/file_video_capture_device.h
index bd3b2985..2ea6f358 100644
--- a/media/video/capture/file_video_capture_device.h
+++ b/media/video/capture/file_video_capture_device.h
@@ -67,6 +67,8 @@
   int frame_size_;
   int64 current_byte_index_;
   int64 first_frame_byte_index_;
+  // Target time for the next frame.
+  base::TimeTicks next_frame_time_;
 
   DISALLOW_COPY_AND_ASSIGN(FileVideoCaptureDevice);
 };
diff --git a/mojo/application/public/cpp/BUILD.gn b/mojo/application/public/cpp/BUILD.gn
index e393615..809abd9 100644
--- a/mojo/application/public/cpp/BUILD.gn
+++ b/mojo/application/public/cpp/BUILD.gn
@@ -6,6 +6,21 @@
 
 # GYP version: mojo/mojo_base.gyp:mojo_application_base
 source_set("cpp") {
+  deps = [
+    ":sources",
+    ":init_commandline",
+  ]
+}
+
+# Like the target above, but without special commandline initialization that
+# apps use.
+source_set("cpp_for_chromium") {
+  deps = [
+    ":sources",
+  ]
+}
+
+source_set("sources") {
   sources = [
     "app_lifetime_helper.h",
     "application_connection.h",
@@ -40,6 +55,12 @@
   ]
 }
 
+source_set("init_commandline") {
+  sources = [
+    "lib/init_commandline.cc",
+  ]
+}
+
 source_set("content_handler") {
   sources = [
     "content_handler_factory.h",
diff --git a/mojo/application/public/cpp/application_impl.h b/mojo/application/public/cpp/application_impl.h
index 272f17b8..7036d33d 100644
--- a/mojo/application/public/cpp/application_impl.h
+++ b/mojo/application/public/cpp/application_impl.h
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/memory/weak_ptr.h"
 #include "mojo/application/public/cpp/app_lifetime_helper.h"
 #include "mojo/application/public/cpp/application_connection.h"
 #include "mojo/application/public/cpp/application_delegate.h"
@@ -133,6 +134,7 @@
   base::Closure termination_closure_;
   AppLifetimeHelper app_lifetime_helper_;
   bool quit_requested_;
+  base::WeakPtrFactory<ApplicationImpl> weak_factory_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationImpl);
 };
diff --git a/mojo/application/public/cpp/application_runner.h b/mojo/application/public/cpp/application_runner.h
index 0341c90..90329a9 100644
--- a/mojo/application/public/cpp/application_runner.h
+++ b/mojo/application/public/cpp/application_runner.h
@@ -37,6 +37,13 @@
   // Once the various parameters have been set above, use Run to initialize an
   // ApplicationImpl wired to the provided delegate, and run a MessageLoop until
   // the application exits.
+  //
+  // Iff |init_base| is true, the runner will perform some initialization of
+  // base globals (e.g. CommandLine and AtExitManager) before starting the
+  // application.
+  MojoResult Run(MojoHandle shell_handle, bool init_base);
+
+  // Calls Run above with |init_base| set to |true|.
   MojoResult Run(MojoHandle shell_handle);
 
  private:
diff --git a/mojo/application/public/cpp/lib/application_impl.cc b/mojo/application/public/cpp/lib/application_impl.cc
index 7de757f0..bafabe2 100644
--- a/mojo/application/public/cpp/lib/application_impl.cc
+++ b/mojo/application/public/cpp/lib/application_impl.cc
@@ -35,7 +35,8 @@
       binding_(this, request.Pass()),
       termination_closure_(termination_closure),
       app_lifetime_helper_(this),
-      quit_requested_(false) {
+      quit_requested_(false),
+      weak_factory_(this) {
 }
 
 void ApplicationImpl::ClearConnections() {
@@ -140,7 +141,10 @@
 }
 
 void ApplicationImpl::OnConnectionError() {
+  base::WeakPtr<ApplicationImpl> ptr(weak_factory_.GetWeakPtr());
   QuitNow();
+  if (!ptr)
+    return;
   shell_ = nullptr;
 }
 
diff --git a/mojo/application/public/cpp/lib/application_runner.cc b/mojo/application/public/cpp/lib/application_runner.cc
index 5afd825a..cacead23 100644
--- a/mojo/application/public/cpp/lib/application_runner.cc
+++ b/mojo/application/public/cpp/lib/application_runner.cc
@@ -13,20 +13,11 @@
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/common/message_pump_mojo.h"
 
-int g_argc;
-const char* const* g_argv;
-#if !defined(OS_WIN)
-extern "C" {
-__attribute__((visibility("default"))) void InitCommandLineArgs(
-    int argc, const char* const* argv) {
-  g_argc = argc;
-  g_argv = argv;
-}
-}
-#endif
-
 namespace mojo {
 
+int g_application_runner_argc;
+const char* const* g_application_runner_argv;
+
 ApplicationRunner::ApplicationRunner(ApplicationDelegate* delegate)
     : delegate_(scoped_ptr<ApplicationDelegate>(delegate)),
       message_loop_type_(base::MessageLoop::TYPE_CUSTOM),
@@ -35,7 +26,7 @@
 ApplicationRunner::~ApplicationRunner() {}
 
 void ApplicationRunner::InitBaseCommandLine() {
-  base::CommandLine::Init(g_argc, g_argv);
+  base::CommandLine::Init(g_application_runner_argc, g_application_runner_argv);
 }
 
 void ApplicationRunner::set_message_loop_type(base::MessageLoop::Type type) {
@@ -45,16 +36,19 @@
   message_loop_type_ = type;
 }
 
-MojoResult ApplicationRunner::Run(MojoHandle application_request_handle) {
+MojoResult ApplicationRunner::Run(MojoHandle application_request_handle,
+                                  bool init_base) {
   DCHECK(!has_run_);
   has_run_ = true;
 
-  InitBaseCommandLine();
-  base::AtExitManager at_exit;
-
+  scoped_ptr<base::AtExitManager> at_exit;
+  if (init_base) {
+    InitBaseCommandLine();
+    at_exit.reset(new base::AtExitManager);
 #ifndef NDEBUG
-  base::debug::EnableInProcessStackDumping();
+    base::debug::EnableInProcessStackDumping();
 #endif
+  }
 
   {
     scoped_ptr<base::MessageLoop> loop;
@@ -79,4 +73,8 @@
   return MOJO_RESULT_OK;
 }
 
+MojoResult ApplicationRunner::Run(MojoHandle application_request_handle) {
+  return Run(application_request_handle, true);
+}
+
 }  // namespace mojo
diff --git a/mojo/application/public/cpp/lib/init_commandline.cc b/mojo/application/public/cpp/lib/init_commandline.cc
new file mode 100644
index 0000000..a61797b
--- /dev/null
+++ b/mojo/application/public/cpp/lib/init_commandline.cc
@@ -0,0 +1,22 @@
+// 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 "build/build_config.h"
+
+namespace mojo {
+
+extern int g_application_runner_argc;
+extern const char* const* g_application_runner_argv;
+
+}
+
+#if !defined(OS_WIN)
+extern "C" {
+__attribute__((visibility("default"))) void InitCommandLineArgs(
+    int argc, const char* const* argv) {
+  mojo::g_application_runner_argc = argc;
+  mojo::g_application_runner_argv = argv;
+}
+}
+#endif
diff --git a/mojo/mojo_base.gyp b/mojo/mojo_base.gyp
index 3e7ced6..70948a1 100644
--- a/mojo/mojo_base.gyp
+++ b/mojo/mojo_base.gyp
@@ -185,10 +185,10 @@
         ],
       },
       'dependencies': [
-        'mojo_services.gyp:network_service_bindings_mojom',
+        'mojo_services.gyp:network_service_bindings_generation',
       ],
       'export_dependent_settings': [
-        'mojo_services.gyp:network_service_bindings_mojom',
+        'mojo_services.gyp:network_service_bindings_generation',
       ],
       'includes': [ '../third_party/mojo/mojom_bindings_generator_explicit.gypi' ],
     },
@@ -221,9 +221,7 @@
       ],
       'dependencies': [
         'mojo_application_bindings',
-      ],
-      'export_dependent_settings': [
-        'mojo_application_bindings',
+        'mojo_common_lib',
       ],
     },
     {
@@ -232,10 +230,11 @@
       'type': 'static_library',
       'dependencies': [
         'mojo_application_bindings_mojom',
+        'mojo_services.gyp:network_service_bindings_lib',
         '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
       ],
       'export_dependent_settings': [
-        '../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
+        'mojo_services.gyp:network_service_bindings_lib',
       ],
     },
     {
diff --git a/mojo/mojo_services.gyp b/mojo/mojo_services.gyp
index 00d789d..7649421 100644
--- a/mojo/mojo_services.gyp
+++ b/mojo/mojo_services.gyp
@@ -20,6 +20,7 @@
         'services/network/public/interfaces/tcp_server_socket.mojom',
         'services/network/public/interfaces/udp_socket.mojom',
         'services/network/public/interfaces/url_loader.mojom',
+        'services/network/public/interfaces/url_loader_factory.mojom',
         'services/network/public/interfaces/web_socket.mojom',
       ],
       'mojom_include_path': '<(DEPTH)/mojo/services',
@@ -29,10 +30,19 @@
     ],
   }, {
     # GN version: //mojo/services/network/public/interfaces
-    'target_name': 'network_service_bindings_libs',
+    'target_name': 'network_service_bindings_lib',
     'type': 'static_library',
     'dependencies': [
       'network_service_bindings_mojom',
     ],
+  }, {
+    # Target used to depend only on the bindings generation action, not on any
+    # outputs.
+    'target_name': 'network_service_bindings_generation',
+    'type': 'none',
+    'hard_dependency': 1,
+    'dependencies': [
+      'network_service_bindings_mojom',
+    ],
   }],
 }
diff --git a/mojo/mojo_shell.gyp b/mojo/mojo_shell.gyp
index d39652c..0569a6b 100644
--- a/mojo/mojo_shell.gyp
+++ b/mojo/mojo_shell.gyp
@@ -25,6 +25,8 @@
       'shell/query_util.h',
       'shell/shell_impl.cc',
       'shell/shell_impl.h',
+      'shell/static_application_loader.cc',
+      'shell/static_application_loader.h',
       'shell/switches.cc',
       'shell/switches.h',
       'util/filename_util.cc',
@@ -34,12 +36,12 @@
       '<(DEPTH)/base/base.gyp:base',
       '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
       '<(DEPTH)/crypto/crypto.gyp:crypto',
-      '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_bindings_mojom',
+      '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_base',
+      '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_bindings',
       '<(DEPTH)/mojo/mojo_base.gyp:mojo_common_lib',
       '<(DEPTH)/mojo/mojo_base.gyp:mojo_environment_chromium',
       '<(DEPTH)/mojo/mojo_base.gyp:mojo_url_type_converters',
       '<(DEPTH)/mojo/mojo_services.gyp:network_service_bindings_lib',
-      '<(DEPTH)/third_party/mojo/mojo_edk.gyp:mojo_system_impl',
       '<(DEPTH)/url/url.gyp:url_lib',
     ],
   }, {
@@ -58,7 +60,6 @@
       '<(DEPTH)/mojo/mojo_base.gyp:mojo_environment_chromium',
       '<(DEPTH)/mojo/mojo_base.gyp:mojo_url_type_converters',
       '<(DEPTH)/third_party/mojo/mojo_edk.gyp:mojo_run_all_unittests',
-      '<(DEPTH)/third_party/mojo/mojo_public.gyp:mojo_application_base',
       '<(DEPTH)/third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
       '<(DEPTH)/testing/gtest.gyp:gtest',
       '<(DEPTH)/url/url.gyp:url_lib',
diff --git a/mojo/runner/BUILD.gn b/mojo/runner/BUILD.gn
index aad598d..6ed8bb19 100644
--- a/mojo/runner/BUILD.gn
+++ b/mojo/runner/BUILD.gn
@@ -309,6 +309,9 @@
     outputs = [
       "$root_out_dir/lib.stripped/libmojo_runner.so",
     ]
+    deps = [
+      ":mojo_runner",
+    ]
   }
 
   copy_ex("copy_mojo_runner_test_assets") {
diff --git a/mojo/runner/android/apk/AndroidManifest.xml b/mojo/runner/android/apk/AndroidManifest.xml
index 080a466d..95a704d0 100644
--- a/mojo/runner/android/apk/AndroidManifest.xml
+++ b/mojo/runner/android/apk/AndroidManifest.xml
@@ -14,7 +14,7 @@
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
 
     <application android:name="MojoShellApplication"
-            android:label="Mojo Shell">
+                 android:label="Mojo Shell">
         <meta-data android:name="com.google.android.gms.version"
                    android:value="@integer/google_play_services_version" />
         <meta-data android:name="mojo_lib"
diff --git a/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java b/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java
index 901012fb..bf74956 100644
--- a/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java
+++ b/mojo/runner/android/apk/src/org/chromium/mojo/shell/MojoShellActivity.java
@@ -8,26 +8,24 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
-import android.util.JsonReader;
 
 import org.chromium.base.Log;
 
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Activity for managing the Mojo Shell.
  */
 public class MojoShellActivity extends Activity {
     private static final String TAG = "MojoShellActivity";
+    private static final String EXTRAS = "org.chromium.mojo.shell.extras";
 
     @Override
     protected void onCreate(final Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        String[] parameters = getParametersFromIntent(getIntent());
+        String[] parameters = getIntent().getStringArrayExtra(EXTRAS);
+        for (String s : parameters) {
+            s = s.replace("\\,", ",");
+        }
         if (Intent.ACTION_VIEW.equals(getIntent().getAction())) {
             Uri uri = getIntent().getData();
             if (uri != null) {
@@ -55,31 +53,4 @@
         // TODO(eseidel): ShellMain can fail, but we're ignoring the return.
         ShellMain.start();
     }
-
-    private static String[] getParametersFromIntent(Intent intent) {
-        if (intent == null) {
-            return null;
-        }
-        String[] parameters = intent.getStringArrayExtra("parameters");
-        if (parameters != null) {
-            return parameters;
-        }
-        String encodedParameters = intent.getStringExtra("encodedParameters");
-        if (encodedParameters != null) {
-            JsonReader reader = new JsonReader(new StringReader(encodedParameters));
-            List<String> parametersList = new ArrayList<String>();
-            try {
-                reader.beginArray();
-                while (reader.hasNext()) {
-                    parametersList.add(reader.nextString());
-                }
-                reader.endArray();
-                reader.close();
-                return parametersList.toArray(new String[parametersList.size()]);
-            } catch (IOException e) {
-                Log.w(TAG, e.getMessage(), e);
-            }
-        }
-        return null;
-    }
 }
diff --git a/mojo/runner/android/native_viewport_application_loader.cc b/mojo/runner/android/native_viewport_application_loader.cc
deleted file mode 100644
index 55979c76..0000000
--- a/mojo/runner/android/native_viewport_application_loader.cc
+++ /dev/null
@@ -1,55 +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 "mojo/runner/android/native_viewport_application_loader.h"
-
-#include "components/view_manager/gles2/gpu_state.h"
-#include "components/view_manager/native_viewport/native_viewport_impl.h"
-#include "mojo/application/public/cpp/application_impl.h"
-
-namespace mojo {
-namespace runner {
-
-NativeViewportApplicationLoader::NativeViewportApplicationLoader() {
-}
-
-NativeViewportApplicationLoader::~NativeViewportApplicationLoader() {
-}
-
-void NativeViewportApplicationLoader::Load(
-    const GURL& url,
-    InterfaceRequest<Application> application_request) {
-  DCHECK(application_request.is_pending());
-  app_.reset(new ApplicationImpl(this, application_request.Pass()));
-}
-
-bool NativeViewportApplicationLoader::ConfigureIncomingConnection(
-    ApplicationConnection* connection) {
-  connection->AddService<NativeViewport>(this);
-  connection->AddService<Gpu>(this);
-  return true;
-}
-
-void NativeViewportApplicationLoader::Create(
-    ApplicationConnection* connection,
-    InterfaceRequest<NativeViewport> request) {
-  if (!gpu_state_)
-    gpu_state_ = new gles2::GpuState;
-  // Pass a null AppRefCount because on Android the NativeViewPort app must
-  // live on the main thread and we don't want to exit that when all the native
-  // viewports are gone.
-  new native_viewport::NativeViewportImpl(
-      false, gpu_state_, request.Pass(),
-      make_scoped_ptr<mojo::AppRefCount>(nullptr));
-}
-
-void NativeViewportApplicationLoader::Create(ApplicationConnection* connection,
-                                             InterfaceRequest<Gpu> request) {
-  if (!gpu_state_)
-    gpu_state_ = new gles2::GpuState;
-  new gles2::GpuImpl(request.Pass(), gpu_state_);
-}
-
-}  // namespace runner
-}  // namespace mojo
diff --git a/mojo/runner/android/native_viewport_application_loader.h b/mojo/runner/android/native_viewport_application_loader.h
deleted file mode 100644
index 25b02fd..0000000
--- a/mojo/runner/android/native_viewport_application_loader.h
+++ /dev/null
@@ -1,58 +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 MOJO_RUNNER_ANDROID_NATIVE_VIEWPORT_APPLICATION_LOADER_H_
-#define MOJO_RUNNER_ANDROID_NATIVE_VIEWPORT_APPLICATION_LOADER_H_
-
-#include "components/view_manager/gles2/gpu_impl.h"
-#include "components/view_manager/public/interfaces/gpu.mojom.h"
-#include "components/view_manager/public/interfaces/native_viewport.mojom.h"
-#include "mojo/application/public/cpp/application_delegate.h"
-#include "mojo/application/public/cpp/interface_factory.h"
-#include "mojo/shell/application_loader.h"
-
-namespace gles2 {
-class GpuState;
-}
-
-namespace mojo {
-
-class ApplicationImpl;
-
-namespace runner {
-
-class NativeViewportApplicationLoader : public shell::ApplicationLoader,
-                                        public ApplicationDelegate,
-                                        public InterfaceFactory<NativeViewport>,
-                                        public InterfaceFactory<Gpu> {
- public:
-  NativeViewportApplicationLoader();
-  ~NativeViewportApplicationLoader();
-
- private:
-  // ApplicationLoader implementation.
-  void Load(const GURL& url,
-            InterfaceRequest<Application> application_request) override;
-
-  // ApplicationDelegate implementation.
-  bool ConfigureIncomingConnection(ApplicationConnection* connection) override;
-
-  // InterfaceFactory<NativeViewport> implementation.
-  void Create(ApplicationConnection* connection,
-              InterfaceRequest<NativeViewport> request) override;
-
-  // InterfaceFactory<Gpu> implementation.
-  void Create(ApplicationConnection* connection,
-              InterfaceRequest<Gpu> request) override;
-
-  scoped_refptr<gles2::GpuState> gpu_state_;
-  scoped_ptr<ApplicationImpl> app_;
-
-  DISALLOW_COPY_AND_ASSIGN(NativeViewportApplicationLoader);
-};
-
-}  // namespace runner
-}  // namespace mojo
-
-#endif  // MOJO_RUNNER_ANDROID_NATIVE_VIEWPORT_APPLICATION_LOADER_H_
diff --git a/mojo/services/BUILD.gn b/mojo/services/BUILD.gn
index dea71211..9272f92 100644
--- a/mojo/services/BUILD.gn
+++ b/mojo/services/BUILD.gn
@@ -9,12 +9,12 @@
   testonly = true
   deps = [
     "//mojo/services/network/public/interfaces",
-    "//mojo/services/test_service",
   ]
 
   if (!is_component_build) {
     deps += [
       "//mojo/services/network",
+      "//mojo/services/test_service",
       "//mojo/services/tracing",
     ]
   }
diff --git a/mojo/services/network/BUILD.gn b/mojo/services/network/BUILD.gn
index b7a9573e..6642b7ef 100644
--- a/mojo/services/network/BUILD.gn
+++ b/mojo/services/network/BUILD.gn
@@ -76,6 +76,8 @@
     "tcp_server_socket_impl.h",
     "udp_socket_impl.cc",
     "udp_socket_impl.h",
+    "url_loader_factory_impl.cc",
+    "url_loader_factory_impl.h",
     "url_loader_impl.cc",
     "url_loader_impl.h",
     "web_socket_impl.cc",
diff --git a/mojo/services/network/network_service_delegate.cc b/mojo/services/network/network_service_delegate.cc
index 02f12fd..b3b1c8e8 100644
--- a/mojo/services/network/network_service_delegate.cc
+++ b/mojo/services/network/network_service_delegate.cc
@@ -10,6 +10,8 @@
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "mojo/application/public/cpp/application_connection.h"
+#include "mojo/services/network/network_service_impl.h"
+#include "mojo/services/network/url_loader_factory_impl.h"
 
 NetworkServiceDelegate::NetworkServiceDelegate() : app_(nullptr) {}
 
@@ -26,7 +28,8 @@
 bool NetworkServiceDelegate::ConfigureIncomingConnection(
     mojo::ApplicationConnection* connection) {
   DCHECK(context_);
-  connection->AddService(this);
+  connection->AddService<mojo::NetworkService>(this);
+  connection->AddService<mojo::URLLoaderFactory>(this);
   return true;
 }
 
@@ -46,3 +49,13 @@
       app_->app_lifetime_helper()->CreateAppRefCount(),
       request.Pass());
 }
+
+void NetworkServiceDelegate::Create(
+    mojo::ApplicationConnection* connection,
+    mojo::InterfaceRequest<mojo::URLLoaderFactory> request) {
+  new mojo::URLLoaderFactoryImpl(
+      connection,
+      context_.get(),
+      app_->app_lifetime_helper()->CreateAppRefCount(),
+      request.Pass());
+}
diff --git a/mojo/services/network/network_service_delegate.h b/mojo/services/network/network_service_delegate.h
index 2e98300..2c1718f 100644
--- a/mojo/services/network/network_service_delegate.h
+++ b/mojo/services/network/network_service_delegate.h
@@ -9,12 +9,14 @@
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/application/public/cpp/interface_factory.h"
 #include "mojo/services/network/network_context.h"
-#include "mojo/services/network/network_service_impl.h"
+#include "mojo/services/network/public/interfaces/network_service.mojom.h"
+#include "mojo/services/network/public/interfaces/url_loader_factory.mojom.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h"
 
 class NetworkServiceDelegate
     : public mojo::ApplicationDelegate,
-      public mojo::InterfaceFactory<mojo::NetworkService> {
+      public mojo::InterfaceFactory<mojo::NetworkService>,
+      public mojo::InterfaceFactory<mojo::URLLoaderFactory> {
  public:
   NetworkServiceDelegate();
   ~NetworkServiceDelegate() override;
@@ -30,6 +32,10 @@
   void Create(mojo::ApplicationConnection* connection,
               mojo::InterfaceRequest<mojo::NetworkService> request) override;
 
+  // mojo::InterfaceFactory<mojo::URLLoaderFactory> implementation.
+  void Create(mojo::ApplicationConnection* connection,
+              mojo::InterfaceRequest<mojo::URLLoaderFactory> request) override;
+
  private:
   mojo::ApplicationImpl* app_;
   scoped_ptr<mojo::NetworkContext> context_;
diff --git a/mojo/services/network/network_service_impl.cc b/mojo/services/network/network_service_impl.cc
index bb83cfa..661f7e0 100644
--- a/mojo/services/network/network_service_impl.cc
+++ b/mojo/services/network/network_service_impl.cc
@@ -29,14 +29,6 @@
 NetworkServiceImpl::~NetworkServiceImpl() {
 }
 
-void NetworkServiceImpl::CreateURLLoader(InterfaceRequest<URLLoader> loader) {
-  // TODO(darin): Plumb origin_. Use for CORS.
-  // The loader will delete itself when the pipe is closed, unless a request is
-  // in progress. In which case, the loader will delete itself when the request
-  // is finished.
-  new URLLoaderImpl(context_, loader.Pass(), app_refcount_->Clone());
-}
-
 void NetworkServiceImpl::GetCookieStore(InterfaceRequest<CookieStore> store) {
   new CookieStoreImpl(context_, origin_, app_refcount_->Clone(), store.Pass());
 }
diff --git a/mojo/services/network/network_service_impl.h b/mojo/services/network/network_service_impl.h
index 0531cc1..32373610 100644
--- a/mojo/services/network/network_service_impl.h
+++ b/mojo/services/network/network_service_impl.h
@@ -24,7 +24,6 @@
   ~NetworkServiceImpl() override;
 
   // NetworkService methods:
-  void CreateURLLoader(InterfaceRequest<URLLoader> loader) override;
   void GetCookieStore(InterfaceRequest<CookieStore> store) override;
   void CreateWebSocket(InterfaceRequest<WebSocket> socket) override;
   void CreateTCPBoundSocket(
diff --git a/mojo/services/network/public/interfaces/BUILD.gn b/mojo/services/network/public/interfaces/BUILD.gn
index 79ddbdc..e72ff78 100644
--- a/mojo/services/network/public/interfaces/BUILD.gn
+++ b/mojo/services/network/public/interfaces/BUILD.gn
@@ -19,6 +19,7 @@
     "tcp_server_socket.mojom",
     "udp_socket.mojom",
     "url_loader.mojom",
+    "url_loader_factory.mojom",
     "web_socket.mojom",
   ]
 
diff --git a/mojo/services/network/public/interfaces/network_service.mojom b/mojo/services/network/public/interfaces/network_service.mojom
index fc0e6b3e..1f67253 100644
--- a/mojo/services/network/public/interfaces/network_service.mojom
+++ b/mojo/services/network/public/interfaces/network_service.mojom
@@ -11,15 +11,12 @@
 import "network/public/interfaces/tcp_bound_socket.mojom";
 import "network/public/interfaces/tcp_connected_socket.mojom";
 import "network/public/interfaces/udp_socket.mojom";
-import "network/public/interfaces/url_loader.mojom";
 import "network/public/interfaces/web_socket.mojom";
 
 // TODO Darin suggests that this should probably be two classes. One for
 // high-level origin-build requests like WebSockets and HTTP, and the other for
 // non-origin-bound low-level stuff like DNS, UDP, and TCP.
 interface NetworkService {
-  CreateURLLoader(URLLoader& loader);
-
   GetCookieStore(CookieStore& cookie_store);
 
   CreateWebSocket(WebSocket& socket);
diff --git a/mojo/services/network/public/interfaces/url_loader_factory.mojom b/mojo/services/network/public/interfaces/url_loader_factory.mojom
new file mode 100644
index 0000000..f6339df
--- /dev/null
+++ b/mojo/services/network/public/interfaces/url_loader_factory.mojom
@@ -0,0 +1,11 @@
+// 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;
+
+import "network/public/interfaces/url_loader.mojom";
+
+interface URLLoaderFactory {
+  CreateURLLoader(URLLoader& loader);
+};
diff --git a/mojo/services/network/url_loader_factory_impl.cc b/mojo/services/network/url_loader_factory_impl.cc
new file mode 100644
index 0000000..f9e6cc34
--- /dev/null
+++ b/mojo/services/network/url_loader_factory_impl.cc
@@ -0,0 +1,33 @@
+// 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/services/network/url_loader_factory_impl.h"
+
+#include "mojo/services/network/url_loader_impl.h"
+
+namespace mojo {
+
+URLLoaderFactoryImpl::URLLoaderFactoryImpl(
+    ApplicationConnection* connection,
+    NetworkContext* context,
+    scoped_ptr<mojo::AppRefCount> app_refcount,
+    InterfaceRequest<URLLoaderFactory> request)
+    : context_(context),
+      app_refcount_(app_refcount.Pass()),
+      binding_(this, request.Pass()) {
+}
+
+URLLoaderFactoryImpl::~URLLoaderFactoryImpl() {
+}
+
+void URLLoaderFactoryImpl::CreateURLLoader(InterfaceRequest<URLLoader> loader) {
+  // TODO(darin): Plumb origin. Use for CORS.
+  // TODO(beng): Figure out how to get origin through to here.
+  // The loader will delete itself when the pipe is closed, unless a request is
+  // in progress. In which case, the loader will delete itself when the request
+  // is finished.
+  new URLLoaderImpl(context_, loader.Pass(), app_refcount_->Clone());
+}
+
+}  // namespace mojo
diff --git a/mojo/services/network/url_loader_factory_impl.h b/mojo/services/network/url_loader_factory_impl.h
new file mode 100644
index 0000000..22bf994
--- /dev/null
+++ b/mojo/services/network/url_loader_factory_impl.h
@@ -0,0 +1,38 @@
+// 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_SERVICES_NETWORK_URL_LOADER_FACTORY_IMPL_H_
+#define MOJO_SERVICES_NETWORK_URL_LOADER_FACTORY_IMPL_H_
+
+#include "base/compiler_specific.h"
+#include "mojo/application/public/cpp/app_lifetime_helper.h"
+#include "mojo/services/network/public/interfaces/url_loader_factory.mojom.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
+
+namespace mojo {
+class ApplicationConnection;
+class NetworkContext;
+
+class URLLoaderFactoryImpl : public URLLoaderFactory {
+ public:
+  URLLoaderFactoryImpl(ApplicationConnection* connection,
+                       NetworkContext* context,
+                       scoped_ptr<mojo::AppRefCount> app_refcount,
+                       InterfaceRequest<URLLoaderFactory> request);
+  ~URLLoaderFactoryImpl() override;
+
+  // URLLoaderFactory methods:
+  void CreateURLLoader(InterfaceRequest<URLLoader> loader) override;
+
+ private:
+  NetworkContext* context_;
+  scoped_ptr<mojo::AppRefCount> app_refcount_;
+  StrongBinding<URLLoaderFactory> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(URLLoaderFactoryImpl);
+};
+
+}  // namespace mojo
+
+#endif  // MOJO_SERVICES_NETWORK_URL_LOADER_FACTORY_IMPL_H_
diff --git a/mojo/shell/BUILD.gn b/mojo/shell/BUILD.gn
index 331af9a..2e599b6f 100644
--- a/mojo/shell/BUILD.gn
+++ b/mojo/shell/BUILD.gn
@@ -26,6 +26,8 @@
     "query_util.h",
     "shell_impl.cc",
     "shell_impl.h",
+    "static_application_loader.cc",
+    "static_application_loader.h",
     "switches.cc",
     "switches.h",
   ]
diff --git a/mojo/shell/application_manager.cc b/mojo/shell/application_manager.cc
index 3354fbd7..39b133fa 100644
--- a/mojo/shell/application_manager.cc
+++ b/mojo/shell/application_manager.cc
@@ -179,8 +179,8 @@
     return;
   }
 
-  if (!network_service_)
-    ConnectToService(GURL("mojo:network_service"), &network_service_);
+  if (!url_loader_factory_)
+    ConnectToService(GURL("mojo:network_service"), &url_loader_factory_);
 
   const NativeApplicationCleanup cleanup =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -193,12 +193,13 @@
     mojo::URLRequestPtr resolved_url_request(mojo::URLRequest::New());
     resolved_url_request->url = resolved_url.spec();
     new NetworkFetcher(disable_cache_, resolved_url_request.Pass(),
-                       network_service_.get(), base::Bind(callback, cleanup));
+                       url_loader_factory_.get(),
+                       base::Bind(callback, cleanup));
     return;
   }
 
   new NetworkFetcher(disable_cache_, requested_url.Pass(),
-                     network_service_.get(), base::Bind(callback, cleanup));
+                     url_loader_factory_.get(), base::Bind(callback, cleanup));
 }
 
 bool ApplicationManager::ConnectToRunningApplication(
diff --git a/mojo/shell/application_manager.h b/mojo/shell/application_manager.h
index 3512e80b..9581ac5 100644
--- a/mojo/shell/application_manager.h
+++ b/mojo/shell/application_manager.h
@@ -15,7 +15,7 @@
 #include "mojo/application/public/interfaces/service_provider.mojom.h"
 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/services/network/public/interfaces/network_service.mojom.h"
+#include "mojo/services/network/public/interfaces/url_loader_factory.mojom.h"
 #include "mojo/shell/application_loader.h"
 #include "mojo/shell/fetcher.h"
 #include "mojo/shell/identity.h"
@@ -242,7 +242,7 @@
   URLToNativeOptionsMap url_to_native_options_;
 
   base::SequencedWorkerPool* blocking_pool_;
-  NetworkServicePtr network_service_;
+  URLLoaderFactoryPtr url_loader_factory_;
   MimeTypeToURLMap mime_type_to_url_;
   ScopedVector<NativeRunner> native_runners_;
   bool disable_cache_;
diff --git a/mojo/shell/network_fetcher.cc b/mojo/shell/network_fetcher.cc
index 27cd92b..da403a3a 100644
--- a/mojo/shell/network_fetcher.cc
+++ b/mojo/shell/network_fetcher.cc
@@ -22,7 +22,7 @@
 #include "mojo/common/common_type_converters.h"
 #include "mojo/common/data_pipe_utils.h"
 #include "mojo/common/url_type_converters.h"
-#include "mojo/services/network/public/interfaces/network_service.mojom.h"
+#include "mojo/services/network/public/interfaces/url_loader_factory.mojom.h"
 #include "mojo/shell/data_pipe_peek.h"
 #include "mojo/shell/switches.h"
 
@@ -31,13 +31,13 @@
 
 NetworkFetcher::NetworkFetcher(bool disable_cache,
                                mojo::URLRequestPtr request,
-                               NetworkService* network_service,
+                               URLLoaderFactory* url_loader_factory,
                                const FetchCallback& loader_callback)
     : Fetcher(loader_callback),
       disable_cache_(false),
       url_(request->url.To<GURL>()),
       weak_ptr_factory_(this) {
-  StartNetworkRequest(request.Pass(), network_service);
+  StartNetworkRequest(request.Pass(), url_loader_factory);
 }
 
 NetworkFetcher::~NetworkFetcher() {
@@ -219,13 +219,13 @@
 }
 
 void NetworkFetcher::StartNetworkRequest(mojo::URLRequestPtr request,
-                                         NetworkService* network_service) {
+                                         URLLoaderFactory* url_loader_factory) {
   TRACE_EVENT_ASYNC_BEGIN1("mojo_shell", "NetworkFetcher::NetworkRequest", this,
                            "url", request->url.To<std::string>());
   request->auto_follow_redirects = false;
   request->bypass_cache = disable_cache_;
 
-  network_service->CreateURLLoader(GetProxy(&url_loader_));
+  url_loader_factory->CreateURLLoader(GetProxy(&url_loader_));
   url_loader_->Start(request.Pass(),
                      base::Bind(&NetworkFetcher::OnLoadComplete,
                                 weak_ptr_factory_.GetWeakPtr()));
diff --git a/mojo/shell/network_fetcher.h b/mojo/shell/network_fetcher.h
index 21fb143..5b9ab650 100644
--- a/mojo/shell/network_fetcher.h
+++ b/mojo/shell/network_fetcher.h
@@ -14,7 +14,7 @@
 
 namespace mojo {
 
-class NetworkService;
+class URLLoaderFactory;
 
 namespace shell {
 
@@ -23,7 +23,7 @@
  public:
   NetworkFetcher(bool disable_cache,
                  mojo::URLRequestPtr request,
-                 NetworkService* network_service,
+                 URLLoaderFactory* url_loader_factory,
                  const FetchCallback& loader_callback);
 
   ~NetworkFetcher() override;
@@ -65,7 +65,7 @@
   bool PeekFirstLine(std::string* line) override;
 
   void StartNetworkRequest(mojo::URLRequestPtr request,
-                           NetworkService* network_service);
+                           URLLoaderFactory* url_loader_factory);
 
   void OnLoadComplete(URLResponsePtr response);
 
diff --git a/mojo/shell/static_application_loader.cc b/mojo/shell/static_application_loader.cc
new file mode 100644
index 0000000..a0f90a87
--- /dev/null
+++ b/mojo/shell/static_application_loader.cc
@@ -0,0 +1,95 @@
+// 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/shell/static_application_loader.h"
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/simple_thread.h"
+#include "mojo/application/public/cpp/application_delegate.h"
+#include "mojo/application/public/cpp/application_runner.h"
+#include "mojo/application/public/interfaces/application.mojom.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
+
+namespace mojo {
+namespace shell {
+
+namespace {
+
+class RunnerThread : public base::SimpleThread {
+ public:
+  RunnerThread(const GURL& url,
+               InterfaceRequest<Application> request,
+               scoped_refptr<base::TaskRunner> exit_task_runner,
+               const base::Closure& exit_callback,
+               const StaticApplicationLoader::ApplicationFactory& factory)
+      : base::SimpleThread("Mojo Application: " + url.spec()),
+        request_(request.Pass()),
+        exit_task_runner_(exit_task_runner),
+        exit_callback_(exit_callback),
+        factory_(factory) {}
+
+  void Run() override {
+    scoped_ptr<ApplicationRunner> runner(
+        new ApplicationRunner(factory_.Run().release()));
+    runner->Run(request_.PassMessagePipe().release().value(),
+                false /* init_base */);
+    exit_task_runner_->PostTask(FROM_HERE, exit_callback_);
+  }
+
+ private:
+  InterfaceRequest<Application> request_;
+  scoped_refptr<base::TaskRunner> exit_task_runner_;
+  base::Closure exit_callback_;
+  StaticApplicationLoader::ApplicationFactory factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(RunnerThread);
+};
+
+}  // namespace
+
+StaticApplicationLoader::StaticApplicationLoader(
+    const ApplicationFactory& factory)
+    : StaticApplicationLoader(factory, base::Closure()) {
+}
+
+StaticApplicationLoader::StaticApplicationLoader(
+    const ApplicationFactory& factory,
+    const base::Closure& quit_callback)
+    : factory_(factory), quit_callback_(quit_callback), weak_factory_(this) {
+}
+
+StaticApplicationLoader::~StaticApplicationLoader() {
+  if (thread_)
+    StopAppThread();
+}
+
+void StaticApplicationLoader::Load(const GURL& url,
+                                   InterfaceRequest<Application> request) {
+  if (thread_)
+    return;
+
+  // If the application's thread quits on its own before this loader dies, we
+  // reset the Thread object, allowing future Load requests to be fulfilled
+  // with a new app instance.
+  auto exit_callback = base::Bind(&StaticApplicationLoader::StopAppThread,
+                                  weak_factory_.GetWeakPtr());
+  thread_.reset(
+      new RunnerThread(url, request.Pass(), base::ThreadTaskRunnerHandle::Get(),
+                       exit_callback, factory_));
+  thread_->Start();
+}
+
+void StaticApplicationLoader::StopAppThread() {
+  thread_->Join();
+  thread_.reset();
+  if (!quit_callback_.is_null())
+    quit_callback_.Run();
+}
+
+}  // namespace shell
+}  // namespace mojo
diff --git a/mojo/shell/static_application_loader.h b/mojo/shell/static_application_loader.h
new file mode 100644
index 0000000..cbf611a
--- /dev/null
+++ b/mojo/shell/static_application_loader.h
@@ -0,0 +1,69 @@
+// 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_SHELL_STATIC_APPLICATION_LOADER_H_
+#define MOJO_SHELL_STATIC_APPLICATION_LOADER_H_
+
+#include <list>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/shell/application_loader.h"
+
+namespace base {
+class SimpleThread;
+}
+
+namespace mojo {
+class ApplicationDelegate;
+}
+
+namespace mojo {
+namespace shell {
+
+// An ApplicationLoader which loads a single type of app from a given
+// ApplicationDelegate factory. A Load() request is fulfilled by creating an
+// instance of the app on a new thread. Only one instance of the app will run at
+// a time. Any Load requests received while the app is running will be dropped.
+class StaticApplicationLoader : public mojo::shell::ApplicationLoader {
+ public:
+  using ApplicationFactory =
+      base::Callback<scoped_ptr<mojo::ApplicationDelegate>()>;
+
+  // Constructs a static loader for |factory|.
+  explicit StaticApplicationLoader(const ApplicationFactory& factory);
+
+  // Constructs a static loader for |factory| with a closure that will be called
+  // when the loaded application quits.
+  StaticApplicationLoader(const ApplicationFactory& factory,
+                          const base::Closure& quit_callback);
+
+  ~StaticApplicationLoader() override;
+
+  // mojo::shell::ApplicationLoader:
+  void Load(const GURL& url,
+            mojo::InterfaceRequest<mojo::Application> request) override;
+
+ private:
+  void StopAppThread();
+
+  // The factory used t create new instances of the application delegate.
+  ApplicationFactory factory_;
+
+  // If not null, this is run when the loaded application quits.
+  base::Closure quit_callback_;
+
+  // Thread for the application if currently running.
+  scoped_ptr<base::SimpleThread> thread_;
+
+  base::WeakPtrFactory<StaticApplicationLoader> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(StaticApplicationLoader);
+};
+
+}  // namespace shell
+}  // namespace mojo
+
+#endif  // MOJO_SHELL_STATIC_APPLICATION_LOADER_H_
diff --git a/mojo/tools/android_mojo_shell.py b/mojo/tools/android_mojo_shell.py
index 3ff5427..61dcd4e 100755
--- a/mojo/tools/android_mojo_shell.py
+++ b/mojo/tools/android_mojo_shell.py
@@ -40,9 +40,7 @@
                   is_debug=runner_args.debug,
                   apk_name="MojoRunner.apk")
   shell = AndroidShell(config)
-  args.extend(shell.PrepareShellRun(runner_args.origin, runner_args.device))
-
-  shell.CleanLogs()
+  shell.InitShell(runner_args.origin, runner_args.device)
   p = shell.ShowLogs()
   shell.StartShell(args, sys.stdout, p.terminate)
   return 0
diff --git a/mojo/tools/apptest_runner.py b/mojo/tools/apptest_runner.py
index 0259768..d33fbea 100755
--- a/mojo/tools/apptest_runner.py
+++ b/mojo/tools/apptest_runner.py
@@ -8,6 +8,7 @@
 import argparse
 import json
 import logging
+import os
 import sys
 import time
 
@@ -39,11 +40,12 @@
   logger.debug("Test list: %s" % test_list)
 
   shell = None
-  extra_args = []
   if config.target_os == Config.OS_ANDROID:
     from mopy.android import AndroidShell
     shell = AndroidShell(config)
-    extra_args.extend(shell.PrepareShellRun('localhost'))
+    result = shell.InitShell()
+    if result != 0:
+      return result
 
   tests = []
   passed = []
@@ -52,7 +54,7 @@
     test = test_dict["test"]
     test_name = test_dict.get("name", test)
     test_type = test_dict.get("type", "gtest")
-    test_args = test_dict.get("args", []) + extra_args
+    test_args = test_dict.get("args", [])
 
     print "Running %s...%s" % (test_name, ("\n" if args.verbose else "")),
     sys.stdout.flush()
diff --git a/mojo/tools/data/apptests b/mojo/tools/data/apptests
index 522c57f..382e8599 100644
--- a/mojo/tools/data/apptests
+++ b/mojo/tools/data/apptests
@@ -53,4 +53,9 @@
       "test": "mojo:resource_provider_apptests",
       "type": "gtest_isolated",
     },
+    {
+      "test": "mojo:mandoline_frame_apptests",
+      "type": "gtest_isolated",
+      "args": ["--use-headless-config"]
+    },
   ]
diff --git a/mojo/tools/mopy/android.py b/mojo/tools/mopy/android.py
index afed31b..e1c747df 100644
--- a/mojo/tools/mopy/android.py
+++ b/mojo/tools/mopy/android.py
@@ -4,7 +4,6 @@
 
 import atexit
 import itertools
-import json
 import logging
 import os
 import shutil
@@ -24,6 +23,7 @@
 from pylib.base import base_test_runner
 from pylib.device import device_errors
 from pylib.device import device_utils
+from pylib.utils import base_error
 from pylib.utils import apk_helper
 
 
@@ -55,6 +55,7 @@
     self.adb_path = constants.GetAdbPath()
     self.paths = Paths(config)
     self.device = None
+    self.shell_args = []
     self.target_package = apk_helper.GetPackageName(self.paths.apk_path)
     # This is used by decive_utils.Install to check if the apk needs updating.
     constants.SetOutputDirectory(self.paths.build_dir)
@@ -66,35 +67,30 @@
     logging.getLogger().debug("Command: %s", " ".join(adb_command))
     return adb_command
 
-  def _ReadFifo(self, fifo_path, pipe, on_fifo_closed, max_attempts=5):
+  def _ReadFifo(self, path, pipe, on_fifo_closed, max_attempts=5):
     """
-    Reads |fifo_path| on the device and write the contents to |pipe|. Calls
-    |on_fifo_closed| when the fifo is closed. This method will try to find the
-    path up to |max_attempts|, waiting 1 second between each attempt. If it
-    cannot find |fifo_path|, a exception will be raised.
+    Reads the fifo at |path| on the device and write the contents to |pipe|.
+    Calls |on_fifo_closed| when the fifo is closed. This method will try to find
+    the path up to |max_attempts|, waiting 1 second between each attempt. If it
+    cannot find |path|, a exception will be raised.
     """
-    fifo_command = self._CreateADBCommand(
-        ['shell', 'test -e "%s"; echo $?' % fifo_path])
-
     def Run():
       def _WaitForFifo():
         for _ in xrange(max_attempts):
-          if subprocess.check_output(fifo_command)[0] == '0':
+          if self.device.FileExists(path):
             return
           time.sleep(1)
-        if on_fifo_closed:
-          on_fifo_closed()
+        on_fifo_closed()
         raise Exception("Unable to find fifo.")
       _WaitForFifo()
       stdout_cat = subprocess.Popen(self._CreateADBCommand([
-                                     'shell',
-                                     'cat',
-                                     fifo_path]),
+                                      'shell',
+                                      'cat',
+                                      path]),
                                     stdout=pipe)
       atexit.register(_ExitIfNeeded, stdout_cat)
       stdout_cat.wait()
-      if on_fifo_closed:
-        on_fifo_closed()
+      on_fifo_closed()
 
     thread = threading.Thread(target=Run, name="StdoutRedirector")
     thread.start()
@@ -137,42 +133,42 @@
       result.append(self._StartHttpServerForOriginMapping(value))
     return [MAPPING_PREFIX + ','.join(result)]
 
-  def PrepareShellRun(self, origin=None, device=None, gdb=False):
+  def InitShell(self, origin='localhost', device=None):
     """
-    Prepares for StartShell: runs adb as root and installs the apk as needed.
-    If the origin specified is 'localhost', a local http server will be set up
-    to serve files from the build directory along with port forwarding.
-    |device| is the device to run on, if multiple devices are connected.
-    Returns arguments that should be appended to shell argument list.
+    Runs adb as root, starts an origin server, and installs the apk as needed.
+    |origin| is the origin for mojo: URLs; if its value is 'localhost', a local
+    http server will be set up to serve files from the build directory.
+    |device| is the target device to run on, if multiple devices are connected.
+    Returns 0 on success or a non-zero exit code on a terminal failure.
     """
-    devices = device_utils.DeviceUtils.HealthyDevices()
-    if device:
-      self.device = next((d for d in devices if d == device), None)
-      if not self.device:
-        raise device_errors.DeviceUnreachableError(device)
-    elif devices:
-      self.device = devices[0]
-    else:
-      raise device_errors.NoDevicesError()
+    try:
+      devices = device_utils.DeviceUtils.HealthyDevices()
+      if device:
+        self.device = next((d for d in devices if d == device), None)
+        if not self.device:
+          raise device_errors.DeviceUnreachableError(device)
+      elif devices:
+        self.device = devices[0]
+      else:
+        raise device_errors.NoDevicesError()
 
-    logging.getLogger().debug("Using device: %s", self.device)
-    self.device.EnableRoot()
-    self.device.Install(self.paths.apk_path)
+      logging.getLogger().debug("Using device: %s", self.device)
+      # Clean the logs on the device to avoid displaying prior activity.
+      subprocess.check_call(self._CreateADBCommand(['logcat', '-c']))
+      self.device.EnableRoot()
+      self.device.Install(self.paths.apk_path)
+    except base_error.BaseError as e:
+      # Report "device not found" as infra failures. See http://crbug.com/493900
+      print "Exception in AndroidShell.InitShell:\n%s" % str(e)
+      if e.is_infra_error or "error: device not found" in str(e):
+        return constants.INFRA_EXIT_CODE
+      return constants.ERROR_EXIT_CODE
 
-    atexit.register(self.StopShell)
-
-    extra_args = []
     if origin is 'localhost':
       origin = self._StartHttpServerForDirectory(self.paths.build_dir)
     if origin:
-      extra_args.append("--origin=" + origin)
-
-    if gdb:
-      # Remote debugging needs a port forwarded.
-      subprocess.check_call(self._CreateADBCommand(['forward', 'tcp:5039',
-                                                    'tcp:5039']))
-
-    return extra_args
+      self.shell_args.append("--origin=" + origin)
+    return 0
 
   def _GetProcessId(self, process):
     """Returns the process id of the process on the remote device."""
@@ -232,19 +228,14 @@
     local_gdb_process.wait()
     signal.signal(signal.SIGINT, signal.SIG_DFL)
 
-  def StartShell(self,
-                 arguments,
-                 stdout=None,
-                 on_application_stop=None,
-                 gdb=False):
+  def StartShell(self, arguments, stdout, on_fifo_closed, gdb=False):
     """
-    Starts the mojo shell, passing it the given arguments.
-
-    The |arguments| list must contain the "--origin=" arg from PrepareShellRun.
-    If |stdout| is not None, it should be a valid argument for subprocess.Popen.
+    Starts the shell with the given |arguments|, directing output to |stdout|.
+    |on_fifo_closed| will be run if the FIFO can't be found or when it's closed.
+    |gdb| is a flag that attaches gdb to the device's remote process on startup.
     """
-
-    STDOUT_PIPE = "/data/data/%s/stdout.fifo" % self.target_package
+    assert self.device
+    arguments += self.shell_args
 
     cmd = self._CreateADBCommand([
            'shell',
@@ -256,29 +247,27 @@
                                               'org.chromium.mojo.shell')])
 
     logcat_process = None
-
     if gdb:
-      arguments += ['--wait-for-debugger']
+      arguments.append('--wait-for-debugger')
+      # Remote debugging needs a port forwarded.
+      self.device.adb.Forward('tcp:5039', 'tcp:5039')
       logcat_process = self.ShowLogs(stdout=subprocess.PIPE)
 
-    if stdout or on_application_stop:
-      subprocess.check_call(self._CreateADBCommand(
-          ['shell', 'rm', '-f', STDOUT_PIPE]))
-      arguments.append('--fifo-path=%s' % STDOUT_PIPE)
-      max_attempts = 5
-      if '--wait-for-debugger' in arguments:
-        max_attempts = 200
-      self._ReadFifo(STDOUT_PIPE, stdout, on_application_stop,
-                     max_attempts=max_attempts)
+    fifo_path = "/data/data/%s/stdout.fifo" % self.target_package
+    subprocess.check_call(self._CreateADBCommand(
+        ['shell', 'rm', '-f', fifo_path]))
+    arguments.append('--fifo-path=%s' % fifo_path)
+    max_attempts = 200 if '--wait-for-debugger' in arguments else 5
+    self._ReadFifo(fifo_path, stdout, on_fifo_closed, max_attempts)
 
-    # Extract map-origin arguments.
+    # Extract map-origin args and add the extras array with commas escaped.
     parameters = [a for a in arguments if not a.startswith(MAPPING_PREFIX)]
     map_parameters = [a for a in arguments if a.startswith(MAPPING_PREFIX)]
     parameters += self._StartHttpServerForOriginMappings(map_parameters)
+    parameters = [p.replace(',', '\,') for p in parameters]
+    cmd += ['--esa', 'org.chromium.mojo.shell.extras', ','.join(parameters)]
 
-    if parameters:
-      cmd += ['--es', 'encodedParameters', json.dumps(parameters)]
-
+    atexit.register(self.StopShell)
     with open(os.devnull, 'w') as devnull:
       cmd_process = subprocess.Popen(cmd, stdout=devnull)
       if logcat_process:
@@ -287,14 +276,7 @@
 
   def StopShell(self):
     """Stops the mojo shell."""
-    subprocess.check_call(self._CreateADBCommand(['shell',
-                                                  'am',
-                                                  'force-stop',
-                                                  self.target_package]))
-
-  def CleanLogs(self):
-    """Cleans the logs on the device."""
-    subprocess.check_call(self._CreateADBCommand(['logcat', '-c']))
+    self.device.ForceStop(self.target_package)
 
   def ShowLogs(self, stdout=sys.stdout):
     """Displays the mojo shell logs and returns the process reading the logs."""
diff --git a/mojo/tools/rev_sdk.py b/mojo/tools/rev_sdk.py
index 0ca317fb..db81034 100755
--- a/mojo/tools/rev_sdk.py
+++ b/mojo/tools/rev_sdk.py
@@ -96,10 +96,5 @@
   sys.exit(1)
 
 # Allow override of the roll revision.
-if len(sys.argv) == 3:
-  mojo_revision = sys.argv[2]
-else:
-  mojo_revision = 'origin/HEAD'
-
-rev(sys.argv[1], chromium_root_dir, mojo_revision)
-
+revision = sys.argv[2] if len(sys.argv) == 3 else 'origin/HEAD'
+rev(sys.argv[1], chromium_root_dir, revision)
diff --git a/net/base/mime_extension_chromeos.cc b/net/base/mime_extension_chromeos.cc
index 864a0ef..03e8e25 100644
--- a/net/base/mime_extension_chromeos.cc
+++ b/net/base/mime_extension_chromeos.cc
@@ -27,9 +27,9 @@
                                       std::string* mime_type) {
   base::FilePath path_ext(ext);
   const std::string ext_narrow_str = path_ext.AsUTF8Unsafe();
-  const char* result = net::FindMimeType(mimetype_extension_mapping,
-                                         arraysize(mimetype_extension_mapping),
-                                         ext_narrow_str.c_str());
+  const char* result =
+      net::FindMimeType(mimetype_extension_mapping,
+                        arraysize(mimetype_extension_mapping), ext_narrow_str);
   if (result) {
     *mime_type = result;
     return true;
diff --git a/net/base/mime_sniffer.cc b/net/base/mime_sniffer.cc
index b71e5eb..447f594 100644
--- a/net/base/mime_sniffer.cc
+++ b/net/base/mime_sniffer.cc
@@ -92,11 +92,11 @@
 // Note that our definition of HTML payload is much stricter than IE's
 // definition and roughly the same as Firefox's definition.
 
+#include <stdint.h>
 #include <string>
 
 #include "net/base/mime_sniffer.h"
 
-#include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/string_util.h"
@@ -949,10 +949,10 @@
   // one bit per byte, with 1 for a "binary" bit, and 0 for a "text" bit. The
   // least-significant bit represents byte 0x00, the most-significant bit
   // represents byte 0x1F.
-  const uint32 kBinaryBits =
+  const uint32_t kBinaryBits =
       ~(1u << '\t' | 1u << '\n' | 1u << '\r' | 1u << '\f' | 1u << '\x1b');
   for (size_t i = 0; i < size; ++i) {
-    uint8 byte = static_cast<uint8>(content[i]);
+    uint8_t byte = static_cast<uint8_t>(content[i]);
     if (byte < 0x20 && (kBinaryBits & (1u << byte)))
       return true;
   }
diff --git a/net/base/mime_sniffer_perftest.cc b/net/base/mime_sniffer_perftest.cc
index eaced27b..72ff0dc 100644
--- a/net/base/mime_sniffer_perftest.cc
+++ b/net/base/mime_sniffer_perftest.cc
@@ -99,7 +99,7 @@
   base::ElapsedTimer elapsed_timer;
   RunLooksLikeBinary(plaintext, kMeasuredIterations);
   LOG(INFO) << (elapsed_timer.Elapsed().InMicroseconds() * 1000 * 1024 /
-                (static_cast<int64>(plaintext.size()) * kMeasuredIterations))
+                (static_cast<int64_t>(plaintext.size()) * kMeasuredIterations))
             << "ns per KB";
 }
 
diff --git a/net/base/mime_sniffer_unittest.cc b/net/base/mime_sniffer_unittest.cc
index 3905ced..6e52baf5 100644
--- a/net/base/mime_sniffer_unittest.cc
+++ b/net/base/mime_sniffer_unittest.cc
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/basictypes.h"
 #include "net/base/mime_sniffer.h"
+
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
diff --git a/net/base/mime_util.cc b/net/base/mime_util.cc
index d3333c6..4c0d1e0c 100644
--- a/net/base/mime_util.cc
+++ b/net/base/mime_util.cc
@@ -110,15 +110,13 @@
 
 const char* FindMimeType(const MimeInfo* mappings,
                          size_t mappings_len,
-                         const char* ext) {
-  size_t ext_len = strlen(ext);
-
+                         const std::string& ext) {
   for (size_t i = 0; i < mappings_len; ++i) {
     const char* extensions = mappings[i].extensions;
     for (;;) {
       size_t end_pos = strcspn(extensions, ",");
-      if (end_pos == ext_len &&
-          base::strncasecmp(extensions, ext, ext_len) == 0)
+      if (end_pos == ext.size() &&
+          base::strncasecmp(extensions, ext.data(), ext.size()) == 0)
         return mappings[i].mime_type;
       extensions += end_pos;
       if (!*extensions)
@@ -171,9 +169,8 @@
 
   base::FilePath path_ext(ext);
   const string ext_narrow_str = path_ext.AsUTF8Unsafe();
-  const char* mime_type = FindMimeType(primary_mappings,
-                                       arraysize(primary_mappings),
-                                       ext_narrow_str.c_str());
+  const char* mime_type = FindMimeType(
+      primary_mappings, arraysize(primary_mappings), ext_narrow_str);
   if (mime_type) {
     *result = mime_type;
     return true;
@@ -183,7 +180,7 @@
     return true;
 
   mime_type = FindMimeType(secondary_mappings, arraysize(secondary_mappings),
-                           ext_narrow_str.c_str());
+                           ext_narrow_str);
   if (mime_type) {
     *result = mime_type;
     return true;
@@ -271,7 +268,7 @@
   const std::string::size_type star = base_pattern.find('*');
   if (star == std::string::npos) {
     if (base_pattern.size() == base_type.size() &&
-        base::strncasecmp(base_pattern.c_str(), base_type.c_str(),
+        base::strncasecmp(base_pattern.data(), base_type.data(),
                           base_pattern.size()) == 0) {
       return MatchesMimeTypeParameters(mime_type_pattern, mime_type);
     } else {
diff --git a/net/base/mime_util.h b/net/base/mime_util.h
index b5243ef..34fceda 100644
--- a/net/base/mime_util.h
+++ b/net/base/mime_util.h
@@ -118,7 +118,7 @@
 // Finds mime type of |ext| from |mappings|.
 const char* FindMimeType(const MimeInfo* mappings,
                          size_t mappings_len,
-                         const char* ext);
+                         const std::string& ext);
 
 }  // namespace net
 
diff --git a/net/base/net_util.cc b/net/base/net_util.cc
index 031f836..028b56b 100644
--- a/net/base/net_util.cc
+++ b/net/base/net_util.cc
@@ -55,6 +55,7 @@
 #include "url/third_party/mozilla/url_parse.h"
 #include "url/url_canon.h"
 #include "url/url_canon_ip.h"
+#include "url/url_constants.h"
 
 #if defined(OS_ANDROID)
 #include "net/android/network_library.h"
@@ -271,32 +272,39 @@
   return port >= 0 && port <= std::numeric_limits<uint16_t>::max();
 }
 
-bool IsPortAllowedByDefault(int port) {
-  int array_size = arraysize(kRestrictedPorts);
-  for (int i = 0; i < array_size; i++) {
-    if (kRestrictedPorts[i] == port) {
-      return false;
-    }
-  }
-  return IsPortValid(port);
+bool IsWellKnownPort(int port) {
+  return port >= 0 && port < 1024;
 }
 
-bool IsPortAllowedByFtp(int port) {
-  int array_size = arraysize(kAllowedFtpPorts);
-  for (int i = 0; i < array_size; i++) {
-    if (kAllowedFtpPorts[i] == port) {
+NET_EXPORT bool IsPortAllowedForScheme(int port,
+                                       const std::string& url_scheme,
+                                       PortOverrideMode port_override_mode) {
+  // Reject invalid ports.
+  if (!IsPortValid(port))
+    return false;
+
+  // Allow explitly allowed ports for any scheme.
+  if (port_override_mode == PORT_OVERRIDES_ALLOWED &&
+      g_explicitly_allowed_ports.Get().count(port) > 0) {
+    return true;
+  }
+
+  // FTP requests have an extra set of whitelisted schemes.
+  if (LowerCaseEqualsASCII(url_scheme, url::kFtpScheme)) {
+    for (int allowed_ftp_port : kAllowedFtpPorts) {
+      if (allowed_ftp_port == port)
         return true;
     }
   }
-  // Port not explicitly allowed by FTP, so return the default restrictions.
-  return IsPortAllowedByDefault(port);
-}
 
-bool IsPortAllowedByOverride(int port) {
-  if (g_explicitly_allowed_ports.Get().empty())
-    return false;
+  // Finally check against the generic list of restricted ports for all
+  // schemes.
+  for (int restricted_port : kRestrictedPorts) {
+    if (restricted_port == port)
+      return false;
+  }
 
-  return g_explicitly_allowed_ports.Get().count(port) > 0;
+  return true;
 }
 
 int SetNonBlocking(int fd) {
diff --git a/net/base/net_util.h b/net/base/net_util.h
index 1a32fbe..f2ba404 100644
--- a/net/base/net_util.h
+++ b/net/base/net_util.h
@@ -222,17 +222,19 @@
 // reserved).  Should be used before casting a port to a uint16_t.
 NET_EXPORT bool IsPortValid(int port);
 
-// Checks |port| against a list of ports which are restricted by default.
-// Returns true if |port| is allowed, false if it is restricted.
-NET_EXPORT bool IsPortAllowedByDefault(int port);
+// Returns true if the port is in the range [0, 1023]. These ports are
+// registered by IANA and typically need root access to listen on.
+bool IsWellKnownPort(int port);
 
-// Checks |port| against a list of ports which are restricted by the FTP
-// protocol.  Returns true if |port| is allowed, false if it is restricted.
-NET_EXPORT_PRIVATE bool IsPortAllowedByFtp(int port);
+enum PortOverrideMode { PORT_OVERRIDES_IGNORED, PORT_OVERRIDES_ALLOWED };
 
-// Check if banned |port| has been overriden by an entry in
-// |explicitly_allowed_ports_|.
-NET_EXPORT_PRIVATE bool IsPortAllowedByOverride(int port);
+// Checks if the port is allowed for the specified scheme.  If PortOverrideMode
+// is PORT_OVERIDES_ALLOWED, then ports set as allowed with
+// SetExplicitlyAllowedPorts() or by using ScopedPortException() will be
+// considered allowed for any scheme.
+NET_EXPORT bool IsPortAllowedForScheme(int port,
+                                       const std::string& url_scheme,
+                                       PortOverrideMode port_override_mode);
 
 // Set socket to non-blocking mode
 NET_EXPORT int SetNonBlocking(int fd);
diff --git a/net/cert/crl_set_storage.cc b/net/cert/crl_set_storage.cc
index 86b246093..99403da 100644
--- a/net/cert/crl_set_storage.cc
+++ b/net/cert/crl_set_storage.cc
@@ -112,11 +112,12 @@
 // updates |data| to remove the header on return. Caller takes ownership of the
 // returned pointer.
 static base::DictionaryValue* ReadHeader(base::StringPiece* data) {
-  if (data->size() < 2)
-    return NULL;
   uint16_t header_len;
-  memcpy(&header_len, data->data(), 2);  // Assumes little-endian.
-  data->remove_prefix(2);
+  if (data->size() < sizeof(header_len))
+    return NULL;
+  // Assumes little-endian.
+  memcpy(&header_len, data->data(), sizeof(header_len));
+  data->remove_prefix(sizeof(header_len));
 
   if (data->size() < header_len)
     return NULL;
@@ -145,16 +146,17 @@
   out_parent_spki_hash->assign(data->data(), crypto::kSHA256Length);
   data->remove_prefix(crypto::kSHA256Length);
 
-  if (data->size() < sizeof(uint32_t))
-    return false;
   uint32_t num_serials;
+  if (data->size() < sizeof(num_serials))
+    return false;
   // Assumes little endian.
-  memcpy(&num_serials, data->data(), sizeof(uint32_t));
+  memcpy(&num_serials, data->data(), sizeof(num_serials));
+  data->remove_prefix(sizeof(num_serials));
+
   if (num_serials > 32 * 1024 * 1024)  // Sanity check.
     return false;
 
   out_serials->reserve(num_serials);
-  data->remove_prefix(sizeof(uint32_t));
 
   for (uint32_t i = 0; i < num_serials; ++i) {
     if (data->size() < sizeof(uint8_t))
@@ -214,13 +216,13 @@
 static bool ReadChanges(base::StringPiece* data,
                         std::vector<uint8_t>* out_changes) {
   uint32_t uncompressed_size, compressed_size;
-  if (data->size() < 2 * sizeof(uint32_t))
+  if (data->size() < sizeof(uncompressed_size) + sizeof(compressed_size))
     return false;
   // Assumes little endian.
-  memcpy(&uncompressed_size, data->data(), sizeof(uint32_t));
-  data->remove_prefix(4);
-  memcpy(&compressed_size, data->data(), sizeof(uint32_t));
-  data->remove_prefix(4);
+  memcpy(&uncompressed_size, data->data(), sizeof(uncompressed_size));
+  data->remove_prefix(sizeof(uncompressed_size));
+  memcpy(&compressed_size, data->data(), sizeof(compressed_size));
+  data->remove_prefix(sizeof(compressed_size));
 
   if (uncompressed_size > kMaxUncompressedChangesLength)
     return false;
@@ -261,10 +263,9 @@
       out_serials->push_back(old_serials[i]);
       i++;
     } else if (*k == SYMBOL_INSERT) {
-      uint8_t serial_length;
       if (data->size() < sizeof(uint8_t))
         return false;
-      memcpy(&serial_length, data->data(), sizeof(uint8_t));
+      uint8_t serial_length = data->data()[0];
       data->remove_prefix(sizeof(uint8_t));
 
       if (data->size() < serial_length)
diff --git a/net/cert/internal/verify_name_match_unittest.cc b/net/cert/internal/verify_name_match_unittest.cc
index 0bdce8a..b7e16ad 100644
--- a/net/cert/internal/verify_name_match_unittest.cc
+++ b/net/cert/internal/verify_name_match_unittest.cc
@@ -11,10 +11,13 @@
 
 TEST(VerifyNameMatchTest, Simple) {
   // TODO(mattm): Use valid Names.
-  EXPECT_TRUE(VerifyNameMatch(der::Input("hello"), der::Input("hello")));
-  EXPECT_FALSE(VerifyNameMatch(der::Input("aello"), der::Input("hello")));
-  EXPECT_FALSE(VerifyNameMatch(der::Input("hello"), der::Input("hello1")));
-  EXPECT_FALSE(VerifyNameMatch(der::Input("hello1"), der::Input("hello")));
+  const uint8_t hello[] = {'h', 'e', 'l', 'l', 'o'};
+  const uint8_t aello[] = {'a', 'e', 'l', 'l', 'o'};
+  const uint8_t hello1[] = {'h', 'e', 'l', 'l', 'o', '1'};
+  EXPECT_TRUE(VerifyNameMatch(der::Input(hello), der::Input(hello)));
+  EXPECT_FALSE(VerifyNameMatch(der::Input(aello), der::Input(hello)));
+  EXPECT_FALSE(VerifyNameMatch(der::Input(hello), der::Input(hello1)));
+  EXPECT_FALSE(VerifyNameMatch(der::Input(hello1), der::Input(hello)));
 }
 
 }  // namespace net
diff --git a/net/cookies/parsed_cookie.cc b/net/cookies/parsed_cookie.cc
index 30afe1087..3f281a6 100644
--- a/net/cookies/parsed_cookie.cc
+++ b/net/cookies/parsed_cookie.cc
@@ -95,8 +95,8 @@
   return *it == end;
 }
 
-// Validate whether |value| is a valid token according to [RFC2616],
-// Section 2.2.
+// Validate whether |value| is a valid token according to [RFC7230],
+// Section 3.2.6.
 bool IsValidToken(const std::string& value) {
   if (value.empty())
     return false;
diff --git a/net/der/input.cc b/net/der/input.cc
index 004034e..45edfdc 100644
--- a/net/der/input.cc
+++ b/net/der/input.cc
@@ -17,10 +17,6 @@
 Input::Input(const uint8_t* data, size_t len) : data_(data), len_(len) {
 }
 
-Input::Input(const std::string& s)
-    : data_(reinterpret_cast<const uint8_t*>(s.data())), len_(s.size()) {
-}
-
 bool Input::Equals(const Input& other) const {
   if (len_ != other.len_)
     return false;
diff --git a/net/der/input.h b/net/der/input.h
index 6731b0c..f8eb467 100644
--- a/net/der/input.h
+++ b/net/der/input.h
@@ -49,9 +49,6 @@
   // Creates an Input from the given |data| and |len|.
   Input(const uint8_t* data, size_t len);
 
-  // Creates an Input from the given string |s|.
-  explicit Input(const std::string& s);
-
   // Returns the length in bytes of an Input's data.
   size_t Length() const { return len_; }
 
diff --git a/net/der/input_unittest.cc b/net/der/input_unittest.cc
index dc58d4b..7d7b720b 100644
--- a/net/der/input_unittest.cc
+++ b/net/der/input_unittest.cc
@@ -17,8 +17,8 @@
   Input test2(kInput, arraysize(kInput));
   EXPECT_TRUE(test.Equals(test2));
 
-  std::string input_copy(reinterpret_cast<const char*>(kInput),
-                         arraysize(kInput));
+  uint8_t input_copy[arraysize(kInput)] = {0};
+  memcpy(input_copy, kInput, arraysize(kInput));
   Input test_copy(input_copy);
   EXPECT_TRUE(test.Equals(test_copy));
 
@@ -85,7 +85,9 @@
 TEST(ByteReaderTest, CantReadToWrongMark) {
   Input out;
   Input in1(kInput, arraysize(kInput));
-  Input in2("test");
+
+  const uint8_t in2_bytes[] = {'t', 'e', 's', 't'};
+  Input in2(in2_bytes);
   ByteReader reader1(in1);
   ByteReader reader2(in2);
   ASSERT_TRUE(reader1.ReadBytes(2, &out));
diff --git a/net/der/parse_values_unittest.cc b/net/der/parse_values_unittest.cc
index 82330424..ea1b5c4 100644
--- a/net/der/parse_values_unittest.cc
+++ b/net/der/parse_values_unittest.cc
@@ -12,6 +12,17 @@
 namespace der {
 namespace test {
 
+namespace {
+
+template <size_t N>
+Input FromStringLiteral(const char(&data)[N]) {
+  // Strings are null-terminated. The null terminating byte shouldn't be
+  // included in the Input, so the size is N - 1 instead of N.
+  return Input(reinterpret_cast<const uint8_t*>(data), N - 1);
+}
+
+}  // namespace
+
 TEST(ParseValuesTest, ParseBool) {
   uint8_t buf[] = {0xFF, 0x00};
   Input value(buf, 1);
@@ -38,117 +49,103 @@
 TEST(ParseValuesTest, ParseTimes) {
   GeneralizedTime out;
 
-  EXPECT_TRUE(ParseUTCTime(Input("140218161200Z"), &out));
+  EXPECT_TRUE(ParseUTCTime(FromStringLiteral("140218161200Z"), &out));
 
   // DER-encoded UTCTime must end with 'Z'.
-  EXPECT_FALSE(ParseUTCTime(Input("140218161200X"), &out));
+  EXPECT_FALSE(ParseUTCTime(FromStringLiteral("140218161200X"), &out));
 
   // Check that a negative number (-4 in this case) doesn't get parsed as
   // a 2-digit number.
-  EXPECT_FALSE(ParseUTCTime(Input("-40218161200Z"), &out));
+  EXPECT_FALSE(ParseUTCTime(FromStringLiteral("-40218161200Z"), &out));
 
   // Check that numbers with a leading 0 don't get parsed in octal by making
   // the second digit an invalid octal digit (e.g. 09).
-  EXPECT_TRUE(ParseUTCTime(Input("090218161200Z"), &out));
+  EXPECT_TRUE(ParseUTCTime(FromStringLiteral("090218161200Z"), &out));
 
   // Check that the length is validated.
-  EXPECT_FALSE(ParseUTCTime(Input("140218161200"), &out));
-  EXPECT_FALSE(ParseUTCTime(Input("140218161200Z0"), &out));
-  EXPECT_FALSE(ParseUTCTimeRelaxed(Input("140218161200"), &out));
-  EXPECT_FALSE(ParseUTCTimeRelaxed(Input("140218161200Z0"), &out));
+  EXPECT_FALSE(ParseUTCTime(FromStringLiteral("140218161200"), &out));
+  EXPECT_FALSE(ParseUTCTime(FromStringLiteral("140218161200Z0"), &out));
+  EXPECT_FALSE(ParseUTCTimeRelaxed(FromStringLiteral("140218161200"), &out));
+  EXPECT_FALSE(ParseUTCTimeRelaxed(FromStringLiteral("140218161200Z0"), &out));
 
   // Check strictness of UTCTime parsers.
-  EXPECT_FALSE(ParseUTCTime(Input("1402181612Z"), &out));
-  EXPECT_TRUE(ParseUTCTimeRelaxed(Input("1402181612Z"), &out));
+  EXPECT_FALSE(ParseUTCTime(FromStringLiteral("1402181612Z"), &out));
+  EXPECT_TRUE(ParseUTCTimeRelaxed(FromStringLiteral("1402181612Z"), &out));
 
   // Check that the time ends in Z.
-  EXPECT_FALSE(ParseUTCTimeRelaxed(Input("1402181612Z0"), &out));
+  EXPECT_FALSE(ParseUTCTimeRelaxed(FromStringLiteral("1402181612Z0"), &out));
 
   // Check format of GeneralizedTime.
 
   // Leap seconds are allowed.
-  EXPECT_TRUE(ParseGeneralizedTime(Input("20140218161260Z"), &out));
+  EXPECT_TRUE(ParseGeneralizedTime(FromStringLiteral("20140218161260Z"), &out));
 
   // But nothing larger than a leap second.
-  EXPECT_FALSE(ParseGeneralizedTime(Input("20140218161261Z"), &out));
+  EXPECT_FALSE(
+      ParseGeneralizedTime(FromStringLiteral("20140218161261Z"), &out));
 
   // Minutes only go up to 59.
-  EXPECT_FALSE(ParseGeneralizedTime(Input("20140218166000Z"), &out));
+  EXPECT_FALSE(
+      ParseGeneralizedTime(FromStringLiteral("20140218166000Z"), &out));
 
   // Hours only go up to 23.
-  EXPECT_FALSE(ParseGeneralizedTime(Input("20140218240000Z"), &out));
+  EXPECT_FALSE(
+      ParseGeneralizedTime(FromStringLiteral("20140218240000Z"), &out));
   // The 0th day of a month is invalid.
-  EXPECT_FALSE(ParseGeneralizedTime(Input("20140200161200Z"), &out));
+  EXPECT_FALSE(
+      ParseGeneralizedTime(FromStringLiteral("20140200161200Z"), &out));
   // The 0th month is invalid.
-  EXPECT_FALSE(ParseGeneralizedTime(Input("20140018161200Z"), &out));
+  EXPECT_FALSE(
+      ParseGeneralizedTime(FromStringLiteral("20140018161200Z"), &out));
   // Months greater than 12 are invalid.
-  EXPECT_FALSE(ParseGeneralizedTime(Input("20141318161200Z"), &out));
+  EXPECT_FALSE(
+      ParseGeneralizedTime(FromStringLiteral("20141318161200Z"), &out));
 
   // Some months have 31 days.
-  EXPECT_TRUE(ParseGeneralizedTime(Input("20140131000000Z"), &out));
+  EXPECT_TRUE(ParseGeneralizedTime(FromStringLiteral("20140131000000Z"), &out));
 
   // September has only 30 days.
-  EXPECT_FALSE(ParseGeneralizedTime(Input("20140931000000Z"), &out));
+  EXPECT_FALSE(
+      ParseGeneralizedTime(FromStringLiteral("20140931000000Z"), &out));
 
   // February has only 28 days...
-  EXPECT_FALSE(ParseGeneralizedTime(Input("20140229000000Z"), &out));
+  EXPECT_FALSE(
+      ParseGeneralizedTime(FromStringLiteral("20140229000000Z"), &out));
 
   // ... unless it's a leap year.
-  EXPECT_TRUE(ParseGeneralizedTime(Input("20160229000000Z"), &out));
+  EXPECT_TRUE(ParseGeneralizedTime(FromStringLiteral("20160229000000Z"), &out));
 
   // There aren't any leap days in years divisible by 100...
-  EXPECT_FALSE(ParseGeneralizedTime(Input("21000229000000Z"), &out));
+  EXPECT_FALSE(
+      ParseGeneralizedTime(FromStringLiteral("21000229000000Z"), &out));
 
   // ...unless it's also divisible by 400.
-  EXPECT_TRUE(ParseGeneralizedTime(Input("20000229000000Z"), &out));
+  EXPECT_TRUE(ParseGeneralizedTime(FromStringLiteral("20000229000000Z"), &out));
 
   // Check more perverse invalid inputs.
 
-  const uint8_t trailing_null_bytes[] = {'2',
-                                         '0',
-                                         '0',
-                                         '0',
-                                         '1',
-                                         '2',
-                                         '3',
-                                         '1',
-                                         '0',
-                                         '1',
-                                         '0',
-                                         '2',
-                                         '0',
-                                         '3',
-                                         'Z',
-                                         '\0'};
-  Input trailing_null(trailing_null_bytes, sizeof(trailing_null_bytes));
-  EXPECT_FALSE(ParseGeneralizedTime(trailing_null, &out));
-  const uint8_t embedded_null_bytes[] = {'2',
-                                         '0',
-                                         '0',
-                                         '\0',
-                                         '1',
-                                         '2',
-                                         '3',
-                                         '1',
-                                         '0',
-                                         '1',
-                                         '0',
-                                         '2',
-                                         '0',
-                                         '3',
-                                         'Z'};
-  Input embedded_null(embedded_null_bytes, sizeof(embedded_null_bytes));
-  EXPECT_FALSE(ParseGeneralizedTime(embedded_null, &out));
+  // Check that trailing null bytes are not ignored.
+  EXPECT_FALSE(
+      ParseGeneralizedTime(FromStringLiteral("20001231010203Z\0"), &out));
+
+  // Check what happens when a null byte is in the middle of the input.
+  EXPECT_FALSE(ParseGeneralizedTime(FromStringLiteral(
+                                        "200\0"
+                                        "1231010203Z"),
+                                    &out));
 
   // The year can't be in hex.
-  EXPECT_FALSE(ParseGeneralizedTime(Input("0x201231000000Z"), &out));
+  EXPECT_FALSE(
+      ParseGeneralizedTime(FromStringLiteral("0x201231000000Z"), &out));
 
   // The last byte must be 'Z'.
-  EXPECT_FALSE(ParseGeneralizedTime(Input("20001231000000X"), &out));
+  EXPECT_FALSE(
+      ParseGeneralizedTime(FromStringLiteral("20001231000000X"), &out));
 
   // Check that the length is validated.
-  EXPECT_FALSE(ParseGeneralizedTime(Input("20140218161200"), &out));
-  EXPECT_FALSE(ParseGeneralizedTime(Input("20140218161200Z0"), &out));
+  EXPECT_FALSE(ParseGeneralizedTime(FromStringLiteral("20140218161200"), &out));
+  EXPECT_FALSE(
+      ParseGeneralizedTime(FromStringLiteral("20140218161200Z0"), &out));
 }
 
 TEST(ParseValuesTest, TimesCompare) {
@@ -156,9 +153,11 @@
   GeneralizedTime time2;
   GeneralizedTime time3;
 
-  ASSERT_TRUE(ParseGeneralizedTime(Input("20140218161200Z"), &time1));
-  ASSERT_TRUE(ParseUTCTime(Input("150218161200Z"), &time2));
-  ASSERT_TRUE(ParseGeneralizedTime(Input("20160218161200Z"), &time3));
+  ASSERT_TRUE(
+      ParseGeneralizedTime(FromStringLiteral("20140218161200Z"), &time1));
+  ASSERT_TRUE(ParseUTCTime(FromStringLiteral("150218161200Z"), &time2));
+  ASSERT_TRUE(
+      ParseGeneralizedTime(FromStringLiteral("20160218161200Z"), &time3));
   EXPECT_TRUE(time1 < time2);
   EXPECT_TRUE(time2 < time3);
   EXPECT_TRUE(time1 < time3);
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index 32905c7..e0d7862 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -3218,11 +3218,6 @@
   BackendKeying();
 }
 
-TEST_F(DiskCacheBackendTest, DISABLED_SimpleCacheSetSize) {
-  SetSimpleCacheMode();
-  BackendSetSize();
-}
-
 // MacOS has a default open file limit of 256 files, which is incompatible with
 // this simple cache test.
 #if defined(OS_MACOSX)
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc
index 228c654..64e79e51 100644
--- a/net/disk_cache/entry_unittest.cc
+++ b/net/disk_cache/entry_unittest.cc
@@ -3528,38 +3528,6 @@
   entry2->Close();
 }
 
-// Checks that reading two entries simultaneously does not discard a CRC check.
-// TODO(pasko): make it work with Simple Cache.
-TEST_F(DiskCacheEntryTest, DISABLED_SimpleCacheMultipleReadersCheckCRC) {
-  SetSimpleCacheMode();
-  InitCache();
-
-  const char key[] = "key";
-
-  int size;
-  ASSERT_TRUE(SimpleCacheMakeBadChecksumEntry(key, &size));
-
-  scoped_refptr<net::IOBuffer> read_buffer1(new net::IOBuffer(size));
-  scoped_refptr<net::IOBuffer> read_buffer2(new net::IOBuffer(size));
-
-  // Advance the first reader a little.
-  disk_cache::Entry* entry = NULL;
-  ASSERT_EQ(net::OK, OpenEntry(key, &entry));
-  EXPECT_EQ(1, ReadData(entry, 0, 0, read_buffer1.get(), 1));
-
-  // Make the second reader pass the point where the first one is, and close.
-  disk_cache::Entry* entry2 = NULL;
-  EXPECT_EQ(net::OK, OpenEntry(key, &entry2));
-  EXPECT_EQ(1, ReadData(entry2, 0, 0, read_buffer2.get(), 1));
-  EXPECT_EQ(1, ReadData(entry2, 0, 1, read_buffer2.get(), 1));
-  entry2->Close();
-
-  // Read the data till the end should produce an error.
-  EXPECT_GT(0, ReadData(entry, 0, 1, read_buffer1.get(), size));
-  entry->Close();
-  DisableIntegrityCheck();
-}
-
 // Checking one more scenario of overlapped reading of a bad entry.
 // Differs from the |SimpleCacheMultipleReadersCheckCRC| only by the order of
 // last two reads.
@@ -4100,12 +4068,6 @@
   GetAvailableRange();
 }
 
-TEST_F(DiskCacheEntryTest, DISABLED_SimpleCacheCouldBeSparse) {
-  SetSimpleCacheMode();
-  InitCache();
-  CouldBeSparse();
-}
-
 TEST_F(DiskCacheEntryTest, SimpleCacheUpdateSparseEntry) {
   SetSimpleCacheMode();
   InitCache();
diff --git a/net/disk_cache/simple/simple_entry_impl.cc b/net/disk_cache/simple/simple_entry_impl.cc
index b7c8524..3910792 100644
--- a/net/disk_cache/simple/simple_entry_impl.cc
+++ b/net/disk_cache/simple/simple_entry_impl.cc
@@ -1192,11 +1192,6 @@
       // entry has a single reader, the normal pattern is to read from start
       // to finish.
 
-      // Other cases are possible. In the case of two readers on the same
-      // entry, one reader can be behind the other. In this case we compute
-      // the crc as the most advanced reader progresses, and check it for
-      // both readers as they read the last byte.
-
       net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CHECKSUM_BEGIN);
 
       scoped_ptr<int> new_result(new int());
diff --git a/net/disk_cache/simple/simple_entry_impl.h b/net/disk_cache/simple/simple_entry_impl.h
index f66c9f0..ba544e3 100644
--- a/net/disk_cache/simple/simple_entry_impl.h
+++ b/net/disk_cache/simple/simple_entry_impl.h
@@ -337,6 +337,10 @@
   // write. For each stream, |crc32s_[index]| is the crc32 of that stream from
   // [0 .. |crc32s_end_offset_|). If |crc32s_end_offset_[index] == 0| then the
   // value of |crc32s_[index]| is undefined.
+  // Note at this can only be done in the current implementation in the case of
+  // a single entry reader that reads serially through the entire file.
+  // Extending this to multiple readers is possible, but isn't currently worth
+  // it; see http://crbug.com/488076#c3 for details.
   int32 crc32s_end_offset_[kSimpleEntryStreamCount];
   uint32 crc32s_[kSimpleEntryStreamCount];
 
diff --git a/net/dns/dns_config_service_unittest.cc b/net/dns/dns_config_service_unittest.cc
index be3cacd9..7d2075fb 100644
--- a/net/dns/dns_config_service_unittest.cc
+++ b/net/dns/dns_config_service_unittest.cc
@@ -332,25 +332,5 @@
   EXPECT_TRUE(last_config_.Equals(bad_config));
 }
 
-#if (defined(OS_POSIX) && !defined(OS_ANDROID)) || defined(OS_WIN)
-// TODO(szym): This is really an integration test and can time out if HOSTS is
-// huge. http://crbug.com/107810
-// On Android the hosts file is not user modifyable, so it's always tiny,
-// however devices used for testing are likely to have no network connectivity
-// and hence no DNS configuration so this test will just fail to find a valid
-// config.
-TEST_F(DnsConfigServiceTest, DISABLED_GetSystemConfig) {
-  service_.reset();
-  scoped_ptr<DnsConfigService> service(DnsConfigService::CreateSystemService());
-
-  service->ReadConfig(base::Bind(&DnsConfigServiceTest::OnConfigChanged,
-                                 base::Unretained(this)));
-  base::TimeDelta kTimeout = TestTimeouts::action_max_timeout();
-  WaitForConfig(kTimeout);
-  ASSERT_TRUE(last_config_.IsValid()) << "Did not receive DnsConfig in " <<
-      kTimeout.InSecondsF() << "s";
-}
-#endif  // OS_POSIX || OS_WIN
-
 }  // namespace net
 
diff --git a/net/dns/host_resolver.cc b/net/dns/host_resolver.cc
index 3b6ea04..06128b5 100644
--- a/net/dns/host_resolver.cc
+++ b/net/dns/host_resolver.cc
@@ -100,10 +100,6 @@
 HostResolver::~HostResolver() {
 }
 
-AddressFamily HostResolver::GetDefaultAddressFamily() const {
-  return ADDRESS_FAMILY_UNSPECIFIED;
-}
-
 void HostResolver::SetDnsClientEnabled(bool enabled) {
 }
 
diff --git a/net/dns/host_resolver.h b/net/dns/host_resolver.h
index 0203dc9..0fe96596 100644
--- a/net/dns/host_resolver.h
+++ b/net/dns/host_resolver.h
@@ -167,13 +167,6 @@
   // has already run or the request was canceled.
   virtual void CancelRequest(RequestHandle req) = 0;
 
-  // Sets the default AddressFamily to use when requests have left it
-  // unspecified. For example, this could be used to restrict resolution
-  // results to AF_INET by passing in ADDRESS_FAMILY_IPV4, or to
-  // AF_INET6 by passing in ADDRESS_FAMILY_IPV6.
-  virtual void SetDefaultAddressFamily(AddressFamily address_family) {}
-  virtual AddressFamily GetDefaultAddressFamily() const;
-
   // Enable or disable the built-in asynchronous DnsClient.
   virtual void SetDnsClientEnabled(bool enabled);
 
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index 4e833471..970ec1f 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -1844,10 +1844,8 @@
     : max_queued_jobs_(0),
       proc_params_(NULL, options.max_retry_attempts),
       net_log_(net_log),
-      default_address_family_(ADDRESS_FAMILY_UNSPECIFIED),
       received_dns_config_(false),
       num_dns_failures_(0),
-      probe_ipv6_support_(true),
       use_local_ipv6_(false),
       last_ipv6_probe_result_(true),
       resolved_known_ipv6_hostname_(false),
@@ -2032,16 +2030,6 @@
   job->CancelRequest(req);
 }
 
-void HostResolverImpl::SetDefaultAddressFamily(AddressFamily address_family) {
-  DCHECK(CalledOnValidThread());
-  default_address_family_ = address_family;
-  probe_ipv6_support_ = false;
-}
-
-AddressFamily HostResolverImpl::GetDefaultAddressFamily() const {
-  return default_address_family_;
-}
-
 void HostResolverImpl::SetDnsClientEnabled(bool enabled) {
   DCHECK(CalledOnValidThread());
 #if defined(ENABLE_BUILT_IN_DNS)
@@ -2088,14 +2076,8 @@
 
   *net_error = OK;
   AddressFamily family = GetAddressFamily(*ip_number);
-  if (family == ADDRESS_FAMILY_IPV6 &&
-      !probe_ipv6_support_ &&
-      default_address_family_ == ADDRESS_FAMILY_IPV4) {
-    // Don't return IPv6 addresses if default address family is set to IPv4,
-    // and probes are disabled.
-    *net_error = ERR_NAME_NOT_RESOLVED;
-  } else if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED &&
-             key.address_family != family) {
+  if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED &&
+      key.address_family != family) {
     // Don't return IPv6 addresses for IPv4 queries, and vice versa.
     *net_error = ERR_NAME_NOT_RESOLVED;
   } else {
@@ -2208,22 +2190,18 @@
   AddressFamily effective_address_family = info.address_family();
 
   if (info.address_family() == ADDRESS_FAMILY_UNSPECIFIED) {
-    if (probe_ipv6_support_ && !use_local_ipv6_ &&
+    if (!use_local_ipv6_ &&
         // When resolving IPv4 literals, there's no need to probe for IPv6.
         // When resolving IPv6 literals, there's no benefit to artificially
         // limiting our resolution based on a probe.  Prior logic ensures
         // that this query is UNSPECIFIED (see info.address_family()
-        // check above) and that |default_address_family_| is UNSPECIFIED
-        // (|prove_ipv6_support_| is false if |default_address_family_| is
-        // set) so the code requesting the resolution should be amenable to
-        // receiving a IPv6 resolution.
+        // check above) so the code requesting the resolution should be amenable
+        // to receiving a IPv6 resolution.
         ip_number == nullptr) {
       if (!IsIPv6Reachable(net_log)) {
         effective_address_family = ADDRESS_FAMILY_IPV4;
         effective_flags |= HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6;
       }
-    } else {
-      effective_address_family = default_address_family_;
     }
   }
 
diff --git a/net/dns/host_resolver_impl.h b/net/dns/host_resolver_impl.h
index e6a7a6d..e3b8ed7 100644
--- a/net/dns/host_resolver_impl.h
+++ b/net/dns/host_resolver_impl.h
@@ -135,8 +135,6 @@
                        AddressList* addresses,
                        const BoundNetLog& source_net_log) override;
   void CancelRequest(RequestHandle req) override;
-  void SetDefaultAddressFamily(AddressFamily address_family) override;
-  AddressFamily GetDefaultAddressFamily() const override;
   void SetDnsClientEnabled(bool enabled) override;
   HostCache* GetHostCache() override;
   base::Value* GetDnsConfigAsValue() const override;
@@ -205,7 +203,7 @@
   // Probes IPv6 support and returns true if IPv6 support is enabled.
   // Results are cached, i.e. when called repeatedly this method returns result
   // from the first probe for some time before probing again.
-  bool IsIPv6Reachable(const BoundNetLog& net_log);
+  virtual bool IsIPv6Reachable(const BoundNetLog& net_log);
 
   // Records the result in cache if cache is present.
   void CacheResult(const Key& key,
@@ -268,9 +266,6 @@
 
   NetLog* net_log_;
 
-  // Address family to use when the request doesn't specify one.
-  AddressFamily default_address_family_;
-
   // If present, used by DnsTask and ServeFromHosts to resolve requests.
   scoped_ptr<DnsClient> dns_client_;
 
@@ -281,10 +276,6 @@
   // Number of consecutive failures of DnsTask, counted when fallback succeeds.
   unsigned num_dns_failures_;
 
-  // True if probing is done for each Request to set address family. When false,
-  // explicit setting in |default_address_family_| is used.
-  bool probe_ipv6_support_;
-
   // True if DnsConfigService detected that system configuration depends on
   // local IPv6 connectivity. Disables probing.
   bool use_local_ipv6_;
diff --git a/net/dns/host_resolver_impl_unittest.cc b/net/dns/host_resolver_impl_unittest.cc
index 91663501..4953022 100644
--- a/net/dns/host_resolver_impl_unittest.cc
+++ b/net/dns/host_resolver_impl_unittest.cc
@@ -416,6 +416,30 @@
   base::ConditionVariable all_done_;
 };
 
+// TestHostResolverImpl's sole purpose is to mock the IPv6 reachability test.
+// By default, this pretends that IPv6 is globally reachable.
+// This class is necessary so unit tests run the same on dual-stack machines as
+// well as IPv4 only machines.
+class TestHostResolverImpl : public HostResolverImpl {
+ public:
+  TestHostResolverImpl(const Options& options, NetLog* net_log)
+      : TestHostResolverImpl(options, net_log, true) {}
+
+  TestHostResolverImpl(const Options& options,
+                       NetLog* net_log,
+                       bool ipv6_reachable)
+      : HostResolverImpl(options, net_log), ipv6_reachable_(ipv6_reachable) {}
+
+  ~TestHostResolverImpl() override {}
+
+ private:
+  const bool ipv6_reachable_;
+
+  bool IsIPv6Reachable(const BoundNetLog& net_log) override {
+    return ipv6_reachable_;
+  }
+};
+
 }  // namespace
 
 class HostResolverImplTest : public testing::Test {
@@ -474,7 +498,7 @@
       const HostResolverImpl::ProcTaskParams& params) {
     HostResolverImpl::Options options = DefaultOptions();
     options.max_concurrent_resolves = max_concurrent_resolves;
-    resolver_.reset(new HostResolverImpl(options, NULL));
+    resolver_.reset(new TestHostResolverImpl(options, NULL));
     resolver_->set_proc_params_for_test(params);
   }
 
@@ -854,7 +878,7 @@
   // Turn off caching for this host resolver.
   HostResolver::Options options = DefaultOptions();
   options.enable_caching = false;
-  resolver_.reset(new HostResolverImpl(options, NULL));
+  resolver_.reset(new TestHostResolverImpl(options, NULL));
   resolver_->set_proc_params_for_test(DefaultParams(proc_.get()));
 
   for (size_t i = 0; i < 4; ++i) {
@@ -1176,100 +1200,6 @@
   }
 }
 
-// Tests that after changing the default AddressFamily to IPV4, requests
-// with UNSPECIFIED address family map to IPV4.
-TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv4) {
-  CreateSerialResolver();  // To guarantee order of resolutions.
-
-  proc_->AddRule("h1", ADDRESS_FAMILY_IPV4, "1.0.0.1");
-  proc_->AddRule("h1", ADDRESS_FAMILY_IPV6, "::2");
-
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
-
-  CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_UNSPECIFIED);
-  CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_IPV4);
-  CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_IPV6);
-
-  // Start all of the requests.
-  for (size_t i = 0; i < requests_.size(); ++i) {
-    EXPECT_EQ(ERR_IO_PENDING, requests_[i]->Resolve()) << i;
-  }
-
-  proc_->SignalMultiple(requests_.size());
-
-  // Wait for all the requests to complete.
-  for (size_t i = 0u; i < requests_.size(); ++i) {
-    EXPECT_EQ(OK, requests_[i]->WaitForResult()) << i;
-  }
-
-  // Since the requests all had the same priority and we limited the thread
-  // count to 1, they should have completed in the same order as they were
-  // requested. Moreover, request0 and request1 will have been serviced by
-  // the same job.
-
-  MockHostResolverProc::CaptureList capture_list = proc_->GetCaptureList();
-  ASSERT_EQ(2u, capture_list.size());
-
-  EXPECT_EQ("h1", capture_list[0].hostname);
-  EXPECT_EQ(ADDRESS_FAMILY_IPV4, capture_list[0].address_family);
-
-  EXPECT_EQ("h1", capture_list[1].hostname);
-  EXPECT_EQ(ADDRESS_FAMILY_IPV6, capture_list[1].address_family);
-
-  // Now check that the correct resolved IP addresses were returned.
-  EXPECT_TRUE(requests_[0]->HasOneAddress("1.0.0.1", 80));
-  EXPECT_TRUE(requests_[1]->HasOneAddress("1.0.0.1", 80));
-  EXPECT_TRUE(requests_[2]->HasOneAddress("::2", 80));
-}
-
-// This is the exact same test as SetDefaultAddressFamily_IPv4, except the
-// default family is set to IPv6 and the family of requests is flipped where
-// specified.
-TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv6) {
-  CreateSerialResolver();  // To guarantee order of resolutions.
-
-  // Don't use IPv6 replacements here since some systems don't support it.
-  proc_->AddRule("h1", ADDRESS_FAMILY_IPV4, "1.0.0.1");
-  proc_->AddRule("h1", ADDRESS_FAMILY_IPV6, "::2");
-
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV6);
-
-  CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_UNSPECIFIED);
-  CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_IPV6);
-  CreateRequest("h1", 80, MEDIUM, ADDRESS_FAMILY_IPV4);
-
-  // Start all of the requests.
-  for (size_t i = 0; i < requests_.size(); ++i) {
-    EXPECT_EQ(ERR_IO_PENDING, requests_[i]->Resolve()) << i;
-  }
-
-  proc_->SignalMultiple(requests_.size());
-
-  // Wait for all the requests to complete.
-  for (size_t i = 0u; i < requests_.size(); ++i) {
-    EXPECT_EQ(OK, requests_[i]->WaitForResult()) << i;
-  }
-
-  // Since the requests all had the same priority and we limited the thread
-  // count to 1, they should have completed in the same order as they were
-  // requested. Moreover, request0 and request1 will have been serviced by
-  // the same job.
-
-  MockHostResolverProc::CaptureList capture_list = proc_->GetCaptureList();
-  ASSERT_EQ(2u, capture_list.size());
-
-  EXPECT_EQ("h1", capture_list[0].hostname);
-  EXPECT_EQ(ADDRESS_FAMILY_IPV6, capture_list[0].address_family);
-
-  EXPECT_EQ("h1", capture_list[1].hostname);
-  EXPECT_EQ(ADDRESS_FAMILY_IPV4, capture_list[1].address_family);
-
-  // Now check that the correct resolved IP addresses were returned.
-  EXPECT_TRUE(requests_[0]->HasOneAddress("::2", 80));
-  EXPECT_TRUE(requests_[1]->HasOneAddress("::2", 80));
-  EXPECT_TRUE(requests_[2]->HasOneAddress("1.0.0.1", 80));
-}
-
 // Make sure that the address family parameter is respected when raw IPs are
 // passed in.
 TEST_F(HostResolverImplTest, AddressFamilyWithRawIPs) {
@@ -1336,7 +1266,7 @@
   // (500ms * 3).
   params.unresponsive_delay = base::TimeDelta::FromMilliseconds(500);
 
-  resolver_.reset(new HostResolverImpl(DefaultOptions(), NULL));
+  resolver_.reset(new TestHostResolverImpl(DefaultOptions(), NULL));
   resolver_->set_proc_params_for_test(params);
 
   // Resolve "host1".
@@ -1403,6 +1333,10 @@
 }
 
 TEST_F(HostResolverImplTest, IsIPv6Reachable) {
+  // The real HostResolverImpl is needed since TestHostResolverImpl will
+  // bypass the IPv6 reachability tests.
+  resolver_.reset(new HostResolverImpl(DefaultOptions(), nullptr));
+
   // Verify that two consecutive calls return the same value.
   TestNetLog net_log;
   BoundNetLog bound_net_log = BoundNetLog::Make(&net_log, NetLog::SOURCE_NONE);
@@ -1492,10 +1426,8 @@
       const HostResolverImpl::ProcTaskParams& params) override {
     HostResolverImpl::Options options = DefaultOptions();
     options.max_concurrent_resolves = max_concurrent_resolves;
-    resolver_.reset(new HostResolverImpl(options, NULL));
+    resolver_.reset(new TestHostResolverImpl(options, NULL));
     resolver_->set_proc_params_for_test(params);
-    // Disable IPv6 support probing.
-    resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
     dns_client_ = new MockDnsClient(DnsConfig(), dns_rules_);
     resolver_->SetDnsClient(scoped_ptr<DnsClient>(dns_client_));
   }
@@ -1525,8 +1457,6 @@
 
 // Test successful and fallback resolutions in HostResolverImpl::DnsTask.
 TEST_F(HostResolverImplDnsTest, DnsTask) {
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
-
   proc_->AddRuleForAllFamilies("nx_succeed", "192.168.1.102");
   // All other hostnames will fail in proc_.
 
@@ -1538,9 +1468,12 @@
 
   ChangeDnsConfig(CreateValidDnsConfig());
 
-  EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok_fail", 80)->Resolve());
-  EXPECT_EQ(ERR_IO_PENDING, CreateRequest("nx_fail", 80)->Resolve());
-  EXPECT_EQ(ERR_IO_PENDING, CreateRequest("nx_succeed", 80)->Resolve());
+  EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok_fail", 80, MEDIUM,
+                                          ADDRESS_FAMILY_IPV4)->Resolve());
+  EXPECT_EQ(ERR_IO_PENDING, CreateRequest("nx_fail", 80, MEDIUM,
+                                          ADDRESS_FAMILY_IPV4)->Resolve());
+  EXPECT_EQ(ERR_IO_PENDING, CreateRequest("nx_succeed", 80, MEDIUM,
+                                          ADDRESS_FAMILY_IPV4)->Resolve());
 
   proc_->SignalMultiple(requests_.size());
 
@@ -1559,7 +1492,6 @@
 // Test successful and failing resolutions in HostResolverImpl::DnsTask when
 // fallback to ProcTask is disabled.
 TEST_F(HostResolverImplDnsTest, NoFallbackToProcTask) {
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
   set_fallback_to_proctask(false);
 
   proc_->AddRuleForAllFamilies("nx_succeed", "192.168.1.102");
@@ -1579,8 +1511,10 @@
 
   ChangeDnsConfig(CreateValidDnsConfig());
 
-  EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok_abort", 80)->Resolve());
-  EXPECT_EQ(ERR_IO_PENDING, CreateRequest("nx_abort", 80)->Resolve());
+  EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok_abort", 80, MEDIUM,
+                                          ADDRESS_FAMILY_IPV4)->Resolve());
+  EXPECT_EQ(ERR_IO_PENDING, CreateRequest("nx_abort", 80, MEDIUM,
+                                          ADDRESS_FAMILY_IPV4)->Resolve());
 
   // Simulate the case when the preference or policy has disabled the DNS client
   // causing AbortDnsTasks.
@@ -1590,8 +1524,10 @@
 
   // First request is resolved by MockDnsClient, others should fail due to
   // disabled fallback to ProcTask.
-  EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok_fail", 80)->Resolve());
-  EXPECT_EQ(ERR_IO_PENDING, CreateRequest("nx_fail", 80)->Resolve());
+  EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok_fail", 80, MEDIUM,
+                                          ADDRESS_FAMILY_IPV4)->Resolve());
+  EXPECT_EQ(ERR_IO_PENDING, CreateRequest("nx_fail", 80, MEDIUM,
+                                          ADDRESS_FAMILY_IPV4)->Resolve());
   proc_->SignalMultiple(requests_.size());
 
   // Aborted due to Network Change.
@@ -1606,7 +1542,6 @@
 
 // Test behavior of OnDnsTaskFailure when Job is aborted.
 TEST_F(HostResolverImplDnsTest, OnDnsTaskFailureAbortedJob) {
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
   ChangeDnsConfig(CreateValidDnsConfig());
   EXPECT_EQ(ERR_IO_PENDING, CreateRequest("nx_abort", 80)->Resolve());
   // Abort all jobs here.
@@ -1618,7 +1553,6 @@
   EXPECT_EQ(ERR_IO_PENDING, requests_[0]->result());
 
   // Repeat test with Fallback to ProcTask disabled
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
   set_fallback_to_proctask(false);
   ChangeDnsConfig(CreateValidDnsConfig());
   EXPECT_EQ(ERR_IO_PENDING, CreateRequest("nx_abort", 80)->Resolve());
@@ -1823,12 +1757,11 @@
 TEST_F(HostResolverImplDnsTest, DualFamilyLocalhost) {
   // Use regular SystemHostResolverCall!
   scoped_refptr<HostResolverProc> proc(new SystemHostResolverProc());
-  resolver_.reset(new HostResolverImpl(DefaultOptions(), NULL));
+  resolver_.reset(new TestHostResolverImpl(DefaultOptions(), NULL, false));
   resolver_->set_proc_params_for_test(DefaultParams(proc.get()));
 
   resolver_->SetDnsClient(
       scoped_ptr<DnsClient>(new MockDnsClient(DnsConfig(), dns_rules_)));
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
 
   // Get the expected output.
   AddressList addrlist;
@@ -1845,13 +1778,15 @@
   if (!saw_ipv4 && !saw_ipv6)
     return;
 
-  HostResolver::RequestInfo info(HostPortPair("localhost", 80));
-  info.set_address_family(ADDRESS_FAMILY_UNSPECIFIED);
-  info.set_host_resolver_flags(HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6);
-
   // Try without DnsClient.
-  ChangeDnsConfig(DnsConfig());
-  Request* req = CreateRequest(info, DEFAULT_PRIORITY);
+  DnsConfig config = CreateValidDnsConfig();
+  config.use_local_ipv6 = false;
+  ChangeDnsConfig(config);
+  HostResolver::RequestInfo info_proc(HostPortPair("localhost", 80));
+  info_proc.set_address_family(ADDRESS_FAMILY_UNSPECIFIED);
+  info_proc.set_host_resolver_flags(HOST_RESOLVER_SYSTEM_ONLY);
+  Request* req = CreateRequest(info_proc, DEFAULT_PRIORITY);
+
   // It is resolved via getaddrinfo, so expect asynchronous result.
   EXPECT_EQ(ERR_IO_PENDING, req->Resolve());
   EXPECT_EQ(OK, req->WaitForResult());
@@ -1860,7 +1795,7 @@
   EXPECT_EQ(saw_ipv6, req->HasAddress("::1", 80));
 
   // Configure DnsClient with dual-host HOSTS file.
-  DnsConfig config = CreateValidDnsConfig();
+  DnsConfig config_hosts = CreateValidDnsConfig();
   DnsHosts hosts;
   IPAddressNumber local_ipv4, local_ipv6;
   ASSERT_TRUE(ParseIPLiteralToNumber("127.0.0.1", &local_ipv4));
@@ -1869,10 +1804,12 @@
     hosts[DnsHostsKey("localhost", ADDRESS_FAMILY_IPV4)] = local_ipv4;
   if (saw_ipv6)
     hosts[DnsHostsKey("localhost", ADDRESS_FAMILY_IPV6)] = local_ipv6;
-  config.hosts = hosts;
+  config_hosts.hosts = hosts;
 
-  ChangeDnsConfig(config);
-  req = CreateRequest(info, DEFAULT_PRIORITY);
+  ChangeDnsConfig(config_hosts);
+  HostResolver::RequestInfo info_hosts(HostPortPair("localhost", 80));
+  info_hosts.set_address_family(ADDRESS_FAMILY_UNSPECIFIED);
+  req = CreateRequest(info_hosts, DEFAULT_PRIORITY);
   // Expect synchronous resolution from DnsHosts.
   EXPECT_EQ(OK, req->Resolve());
 
@@ -1882,10 +1819,10 @@
 
 // Cancel a request with a single DNS transaction active.
 TEST_F(HostResolverImplDnsTest, CancelWithOneTransactionActive) {
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_IPV4);
   ChangeDnsConfig(CreateValidDnsConfig());
 
-  EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
+  EXPECT_EQ(ERR_IO_PENDING,
+            CreateRequest("ok", 80, MEDIUM, ADDRESS_FAMILY_IPV4)->Resolve());
   EXPECT_EQ(1u, num_running_dispatcher_jobs());
   requests_[0]->Cancel();
 
@@ -1895,7 +1832,6 @@
 // Cancel a request with a single DNS transaction active and another pending.
 TEST_F(HostResolverImplDnsTest, CancelWithOneTransactionActiveOnePending) {
   CreateSerialResolver();
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
   ChangeDnsConfig(CreateValidDnsConfig());
 
   EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
@@ -1907,7 +1843,6 @@
 
 // Cancel a request with two DNS transactions active.
 TEST_F(HostResolverImplDnsTest, CancelWithTwoTransactionsActive) {
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
   ChangeDnsConfig(CreateValidDnsConfig());
 
   EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
@@ -1922,7 +1857,6 @@
   // At most 10 Jobs active at once.
   CreateResolverWithLimitsAndParams(10u, DefaultParams(proc_.get()));
 
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
   ChangeDnsConfig(CreateValidDnsConfig());
 
   // First active job is an IPv4 request.
@@ -1943,7 +1877,6 @@
 
 // Cancel a request with only the IPv6 transaction active.
 TEST_F(HostResolverImplDnsTest, CancelWithIPv6TransactionActive) {
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
   ChangeDnsConfig(CreateValidDnsConfig());
 
   EXPECT_EQ(ERR_IO_PENDING, CreateRequest("6slow_ok", 80)->Resolve());
@@ -1960,7 +1893,6 @@
 // Cancel a request with only the IPv4 transaction pending.
 TEST_F(HostResolverImplDnsTest, CancelWithIPv4TransactionPending) {
   set_fallback_to_proctask(false);
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
   ChangeDnsConfig(CreateValidDnsConfig());
 
   EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_ok", 80)->Resolve());
@@ -1976,7 +1908,6 @@
 // Test cases where AAAA completes first.
 TEST_F(HostResolverImplDnsTest, AAAACompletesFirst) {
   set_fallback_to_proctask(false);
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
   ChangeDnsConfig(CreateValidDnsConfig());
 
   EXPECT_EQ(ERR_IO_PENDING, CreateRequest("4slow_ok", 80)->Resolve());
@@ -2014,7 +1945,6 @@
 TEST_F(HostResolverImplDnsTest, SerialResolver) {
   CreateSerialResolver();
   set_fallback_to_proctask(false);
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
   ChangeDnsConfig(CreateValidDnsConfig());
 
   EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80)->Resolve());
@@ -2033,7 +1963,6 @@
 TEST_F(HostResolverImplDnsTest, AAAAStartsAfterOtherJobFinishes) {
   CreateResolverWithLimitsAndParams(2u, DefaultParams(proc_.get()));
   set_fallback_to_proctask(false);
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
   ChangeDnsConfig(CreateValidDnsConfig());
 
   EXPECT_EQ(ERR_IO_PENDING, CreateRequest("ok", 80, MEDIUM,
@@ -2092,7 +2021,6 @@
   // prioritized dispatcher slot.
   CreateResolverWithLimitsAndParams(3u, DefaultParams(proc_.get()));
 
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
   ChangeDnsConfig(CreateValidDnsConfig());
 
   proc_->AddRuleForAllFamilies("slow_nx1", "192.168.0.1");
@@ -2133,7 +2061,6 @@
   for (size_t limit = 1u; limit < 6u; ++limit) {
     CreateResolverWithLimitsAndParams(limit, DefaultParams(proc_.get()));
 
-    resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
     ChangeDnsConfig(CreateValidDnsConfig());
 
     // Queue up enough failures to disable DnsTasks.  These will all fall back
@@ -2180,7 +2107,6 @@
   // prioritized dispatcher slot.
   CreateResolverWithLimitsAndParams(3u, DefaultParams(proc_.get()));
 
-  resolver_->SetDefaultAddressFamily(ADDRESS_FAMILY_UNSPECIFIED);
   ChangeDnsConfig(CreateValidDnsConfig());
 
   proc_->AddRuleForAllFamilies("slow_ok1", "192.168.0.1");
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc
index 3c67114..32ede86 100644
--- a/net/ftp/ftp_network_transaction.cc
+++ b/net/ftp/ftp_network_transaction.cc
@@ -24,6 +24,7 @@
 #include "net/log/net_log.h"
 #include "net/socket/client_socket_factory.h"
 #include "net/socket/stream_socket.h"
+#include "url/url_constants.h"
 
 namespace net {
 
@@ -956,8 +957,11 @@
       int port;
       if (!ExtractPortFromEPSVResponse(response, &port))
         return Stop(ERR_INVALID_RESPONSE);
-      if (port < 1024 || !IsPortAllowedByFtp(port))
+      if (IsWellKnownPort(port) ||
+          !IsPortAllowedForScheme(port, url::kFtpScheme,
+                                  PORT_OVERRIDES_IGNORED)) {
         return Stop(ERR_UNSAFE_PORT);
+      }
       data_connection_port_ = static_cast<uint16>(port);
       next_state_ = STATE_DATA_CONNECT;
       break;
@@ -992,8 +996,11 @@
       int port;
       if (!ExtractPortFromPASVResponse(response, &port))
         return Stop(ERR_INVALID_RESPONSE);
-      if (port < 1024 || !IsPortAllowedByFtp(port))
+      if (IsWellKnownPort(port) ||
+          !IsPortAllowedForScheme(port, url::kFtpScheme,
+                                  PORT_OVERRIDES_IGNORED)) {
         return Stop(ERR_UNSAFE_PORT);
+      }
       data_connection_port_ = static_cast<uint16>(port);
       next_state_ = STATE_DATA_CONNECT;
       break;
diff --git a/net/http/disk_cache_based_quic_server_info_unittest.cc b/net/http/disk_cache_based_quic_server_info_unittest.cc
index d4ddfc25..d51bab7 100644
--- a/net/http/disk_cache_based_quic_server_info_unittest.cc
+++ b/net/http/disk_cache_based_quic_server_info_unittest.cc
@@ -21,33 +21,39 @@
 
 // This is an empty transaction, needed to register the URL and the test mode.
 const MockTransaction kHostInfoTransaction1 = {
-  "quicserverinfo:https://www.google.com:443",
-  "",
-  base::Time(),
-  "",
-  LOAD_NORMAL,
-  "",
-  "",
-  base::Time(),
-  "",
-  TEST_MODE_NORMAL,
-  NULL,
-  0
+    "quicserverinfo:https://www.google.com:443",
+    "",
+    base::Time(),
+    "",
+    LOAD_NORMAL,
+    "",
+    "",
+    base::Time(),
+    "",
+    TEST_MODE_NORMAL,
+    nullptr,
+    nullptr,
+    0,
+    0,
+    OK,
 };
 
 const MockTransaction kHostInfoTransaction2 = {
-  "quicserverinfo:http://www.google.com:80",
-  "",
-  base::Time(),
-  "",
-  LOAD_NORMAL,
-  "",
-  "",
-  base::Time(),
-  "",
-  TEST_MODE_NORMAL,
-  NULL,
-  0
+    "quicserverinfo:http://www.google.com:80",
+    "",
+    base::Time(),
+    "",
+    LOAD_NORMAL,
+    "",
+    "",
+    base::Time(),
+    "",
+    TEST_MODE_NORMAL,
+    nullptr,
+    nullptr,
+    0,
+    0,
+    OK,
 };
 
 class DeleteCacheCompletionCallback : public TestCompletionCallbackBase {
diff --git a/net/http/http_cache.h b/net/http/http_cache.h
index 8e99a98..c730049 100644
--- a/net/http/http_cache.h
+++ b/net/http/http_cache.h
@@ -4,7 +4,7 @@
 
 // This file declares a HttpTransactionFactory implementation that can be
 // layered on top of another HttpTransactionFactory to add HTTP caching.  The
-// caching logic follows RFC 2616 (any exceptions are called out in the code).
+// caching logic follows RFC 7234 (any exceptions are called out in the code).
 //
 // The HttpCache takes a disk_cache::Backend as a parameter, and uses that for
 // the cache storage.
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 1819fd2..e3af3f7b 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -1483,13 +1483,14 @@
 int HttpCache::Transaction::DoUpdateCachedResponse() {
   next_state_ = STATE_UPDATE_CACHED_RESPONSE_COMPLETE;
   int rv = OK;
-  // Update cached response based on headers in new_response.
-  // TODO(wtc): should we update cached certificate (response_.ssl_info), too?
+  // Update the cached response based on the headers and properties of
+  // new_response_.
   response_.headers->Update(*new_response_->headers.get());
   response_.response_time = new_response_->response_time;
   response_.request_time = new_response_->request_time;
   response_.network_accessed = new_response_->network_accessed;
   response_.unused_since_prefetch = new_response_->unused_since_prefetch;
+  response_.ssl_info = new_response_->ssl_info;
   if (new_response_->vary_data.is_valid()) {
     response_.vary_data = new_response_->vary_data;
   } else if (response_.vary_data.is_valid()) {
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 62a3d6ad..ea1b9ddf 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -21,8 +21,10 @@
 #include "net/base/load_timing_info.h"
 #include "net/base/load_timing_info_test_util.h"
 #include "net/base/net_errors.h"
+#include "net/base/test_data_directory.h"
 #include "net/base/upload_bytes_element_reader.h"
 #include "net/cert/cert_status_flags.h"
+#include "net/cert/x509_certificate.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/http/http_byte_range.h"
 #include "net/http/http_cache_transaction.h"
@@ -39,6 +41,8 @@
 #include "net/log/test_net_log_util.h"
 #include "net/socket/client_socket_handle.h"
 #include "net/ssl/ssl_cert_request_info.h"
+#include "net/ssl/ssl_connection_status_flags.h"
+#include "net/test/cert_test_util.h"
 #include "net/websockets/websocket_handshake_stream_base.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -270,6 +274,8 @@
     "<html><body>Google Blah Blah</body></html>",
     TEST_MODE_SYNC_NET_START,
     &FastTransactionServer::FastNoStoreHandler,
+    nullptr,
+    0,
     0,
     OK};
 
@@ -441,6 +447,8 @@
     "rg: 40-49 ",
     TEST_MODE_NORMAL,
     &RangeTransactionServer::RangeHandler,
+    nullptr,
+    0,
     0,
     OK};
 
@@ -7848,4 +7856,113 @@
       "Cache-Control", "no-store"));
   ReadAndVerifyTransaction(second->trans.get(), kSimpleGET_Transaction);
 }
+
+// Tests that serving a response entirely from cache replays the previous
+// SSLInfo.
+TEST(HttpCache, CachePreservesSSLInfo) {
+  static const uint16_t kTLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xc02f;
+  int status = 0;
+  SSLConnectionStatusSetCipherSuite(kTLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+                                    &status);
+  SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_TLS1_2, &status);
+
+  scoped_refptr<X509Certificate> cert =
+      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
+
+  MockHttpCache cache;
+
+  ScopedMockTransaction transaction(kSimpleGET_Transaction);
+  transaction.cert = cert;
+  transaction.ssl_connection_status = status;
+
+  // Fetch the resource.
+  HttpResponseInfo response_info;
+  RunTransactionTestWithResponseInfo(cache.http_cache(), transaction,
+                                     &response_info);
+
+  // The request should have hit the network and a cache entry created.
+  EXPECT_EQ(1, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+  // The expected SSL state was reported.
+  EXPECT_EQ(transaction.ssl_connection_status,
+            response_info.ssl_info.connection_status);
+  EXPECT_TRUE(cert->Equals(response_info.ssl_info.cert.get()));
+
+  // Fetch the resource again.
+  RunTransactionTestWithResponseInfo(cache.http_cache(), transaction,
+                                     &response_info);
+
+  // The request should have been reused without hitting the network.
+  EXPECT_EQ(1, cache.network_layer()->transaction_count());
+  EXPECT_EQ(1, cache.disk_cache()->open_count());
+  EXPECT_EQ(1, cache.disk_cache()->create_count());
+
+  // The SSL state was preserved.
+  EXPECT_EQ(status, response_info.ssl_info.connection_status);
+  EXPECT_TRUE(cert->Equals(response_info.ssl_info.cert.get()));
+}
+
+// Tests that SSLInfo gets updated when revalidating a cached response.
+TEST(HttpCache, RevalidationUpdatesSSLInfo) {
+  static const uint16_t kTLS_RSA_WITH_RC4_128_MD5 = 0x0004;
+  static const uint16_t kTLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xc02f;
+
+  int status1 = 0;
+  SSLConnectionStatusSetCipherSuite(kTLS_RSA_WITH_RC4_128_MD5, &status1);
+  SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_TLS1, &status1);
+  int status2 = 0;
+  SSLConnectionStatusSetCipherSuite(kTLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+                                    &status2);
+  SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_TLS1_2, &status2);
+
+  scoped_refptr<X509Certificate> cert1 =
+      ImportCertFromFile(GetTestCertsDirectory(), "expired_cert.pem");
+  scoped_refptr<X509Certificate> cert2 =
+      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
+
+  MockHttpCache cache;
+
+  ScopedMockTransaction transaction(kTypicalGET_Transaction);
+  transaction.cert = cert1;
+  transaction.ssl_connection_status = status1;
+
+  // Fetch the resource.
+  HttpResponseInfo response_info;
+  RunTransactionTestWithResponseInfo(cache.http_cache(), transaction,
+                                     &response_info);
+
+  // The request should have hit the network and a cache entry created.
+  EXPECT_EQ(1, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(1, cache.disk_cache()->create_count());
+  EXPECT_FALSE(response_info.was_cached);
+
+  // The expected SSL state was reported.
+  EXPECT_EQ(status1, response_info.ssl_info.connection_status);
+  EXPECT_TRUE(cert1->Equals(response_info.ssl_info.cert.get()));
+
+  // The server deploys a more modern configuration but reports 304 on the
+  // revalidation attempt.
+  transaction.status = "HTTP/1.1 304 Not Modified";
+  transaction.cert = cert2;
+  transaction.ssl_connection_status = status2;
+
+  // Fetch the resource again, forcing a revalidation.
+  transaction.request_headers = "Cache-Control: max-age=0\r\n";
+  RunTransactionTestWithResponseInfo(cache.http_cache(), transaction,
+                                     &response_info);
+
+  // The request should have been successfully revalidated.
+  EXPECT_EQ(2, cache.network_layer()->transaction_count());
+  EXPECT_EQ(1, cache.disk_cache()->open_count());
+  EXPECT_EQ(1, cache.disk_cache()->create_count());
+  EXPECT_TRUE(response_info.was_cached);
+
+  // The new SSL state is reported.
+  EXPECT_EQ(status2, response_info.ssl_info.connection_status);
+  EXPECT_TRUE(cert2->Equals(response_info.ssl_info.cert.get()));
+}
+
 }  // namespace net
diff --git a/net/http/http_chunked_decoder.cc b/net/http/http_chunked_decoder.cc
index 0d8be9f..7aa4a96 100644
--- a/net/http/http_chunked_decoder.cc
+++ b/net/http/http_chunked_decoder.cc
@@ -179,7 +179,7 @@
 //
 // Let \X be the character class for a hex digit: [0-9a-fA-F]
 //
-//   RFC 2616: ^\X+$
+//   RFC 7230: ^\X+$
 //        IE7: ^\X+[^\X]*$
 // Safari 3.1: ^[\t\r ]*\X+[\t ]*$
 //  Firefox 3: ^[\t\f\v\r ]*[+]?(0x)?\X+[^\X]*$
diff --git a/net/http/http_chunked_decoder_unittest.cc b/net/http/http_chunked_decoder_unittest.cc
index db32c6f..06dd353c 100644
--- a/net/http/http_chunked_decoder_unittest.cc
+++ b/net/http/http_chunked_decoder_unittest.cc
@@ -113,7 +113,7 @@
 }
 
 TEST(HttpChunkedDecoderTest, LF_InsteadOf_CRLF) {
-  // Compatibility: [RFC 2616 - Invalid]
+  // Compatibility: [RFC 7230 - Invalid]
   // {Firefox3} - Valid
   // {IE7, Safari3.1, Opera9.51} - Invalid
   const char* const inputs[] = {
@@ -166,7 +166,7 @@
 
 TEST(HttpChunkedDecoderTest, InvalidChunkSize_0X) {
   const char* const inputs[] = {
-    // Compatibility [RFC 2616 - Invalid]:
+    // Compatibility [RFC 7230 - Invalid]:
     // {Safari3.1, IE7} - Invalid
     // {Firefox3, Opera 9.51} - Valid
     "0x5\r\nhello\r\n",
@@ -177,7 +177,7 @@
 
 TEST(HttpChunkedDecoderTest, ChunkSize_TrailingSpace) {
   const char* const inputs[] = {
-    // Compatibility [RFC 2616 - Invalid]:
+    // Compatibility [RFC 7230 - Invalid]:
     // {IE7, Safari3.1, Firefox3, Opera 9.51} - Valid
     //
     // At least yahoo.com depends on this being valid.
@@ -189,7 +189,7 @@
 
 TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingTab) {
   const char* const inputs[] = {
-    // Compatibility [RFC 2616 - Invalid]:
+    // Compatibility [RFC 7230 - Invalid]:
     // {IE7, Safari3.1, Firefox3, Opera 9.51} - Valid
     "5\t\r\nhello\r\n",
     "0\r\n\r\n"
@@ -199,7 +199,7 @@
 
 TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingFormFeed) {
   const char* const inputs[] = {
-    // Compatibility [RFC 2616- Invalid]:
+    // Compatibility [RFC 7230- Invalid]:
     // {Safari3.1} - Invalid
     // {IE7, Firefox3, Opera 9.51} - Valid
     "5\f\r\nhello\r\n",
@@ -210,7 +210,7 @@
 
 TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingVerticalTab) {
   const char* const inputs[] = {
-    // Compatibility [RFC 2616 - Invalid]:
+    // Compatibility [RFC 7230 - Invalid]:
     // {Safari 3.1} - Invalid
     // {IE7, Firefox3, Opera 9.51} - Valid
     "5\v\r\nhello\r\n",
@@ -221,7 +221,7 @@
 
 TEST(HttpChunkedDecoderTest, InvalidChunkSize_TrailingNonHexDigit) {
   const char* const inputs[] = {
-    // Compatibility [RFC 2616 - Invalid]:
+    // Compatibility [RFC 7230 - Invalid]:
     // {Safari 3.1} - Invalid
     // {IE7, Firefox3, Opera 9.51} - Valid
     "5H\r\nhello\r\n",
@@ -232,7 +232,7 @@
 
 TEST(HttpChunkedDecoderTest, InvalidChunkSize_LeadingSpace) {
   const char* const inputs[] = {
-    // Compatibility [RFC 2616 - Invalid]:
+    // Compatibility [RFC 7230 - Invalid]:
     // {IE7} - Invalid
     // {Safari 3.1, Firefox3, Opera 9.51} - Valid
     " 5\r\nhello\r\n",
@@ -268,7 +268,7 @@
 
 TEST(HttpChunkedDecoderTest, InvalidChunkSize_Plus) {
   const char* const inputs[] = {
-    // Compatibility [RFC 2616 - Invalid]:
+    // Compatibility [RFC 7230 - Invalid]:
     // {IE7, Safari 3.1} - Invalid
     // {Firefox3, Opera 9.51} - Valid
     "+5\r\nhello\r\n",
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc
index fffb897f..9e736f2 100644
--- a/net/http/http_proxy_client_socket_pool_unittest.cc
+++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -155,10 +155,9 @@
  protected:
   HttpProxyClientSocketPoolTest()
       : session_deps_(GetParam().protocol),
-        transport_socket_pool_(
-            kMaxSockets,
-            kMaxSocketsPerGroup,
-            session_deps_.deterministic_socket_factory.get()),
+        transport_socket_pool_(kMaxSockets,
+                               kMaxSocketsPerGroup,
+                               session_deps_.socket_factory.get()),
         ssl_socket_pool_(kMaxSockets,
                          kMaxSocketsPerGroup,
                          session_deps_.cert_verifier.get(),
@@ -167,7 +166,7 @@
                          NULL /* cert_transparency_verifier */,
                          NULL /* cert_policy_enforcer */,
                          std::string() /* ssl_session_cache_shard */,
-                         session_deps_.deterministic_socket_factory.get(),
+                         session_deps_.socket_factory.get(),
                          &transport_socket_pool_,
                          NULL,
                          NULL,
@@ -255,8 +254,8 @@
     return CreateParams(false, proxy_delegate);
   }
 
-  DeterministicMockClientSocketFactory* socket_factory() {
-    return session_deps_.deterministic_socket_factory.get();
+  MockClientSocketFactory* socket_factory() {
+    return session_deps_.socket_factory.get();
   }
 
   void Initialize(MockRead* reads, size_t reads_count,
@@ -264,15 +263,14 @@
                   MockRead* spdy_reads, size_t spdy_reads_count,
                   MockWrite* spdy_writes, size_t spdy_writes_count) {
     if (GetParam().proxy_type == SPDY) {
-      data_.reset(new DeterministicSocketData(spdy_reads, spdy_reads_count,
-                                              spdy_writes, spdy_writes_count));
+      data_.reset(new SequencedSocketData(spdy_reads, spdy_reads_count,
+                                          spdy_writes, spdy_writes_count));
     } else {
-      data_.reset(new DeterministicSocketData(reads, reads_count, writes,
-                                              writes_count));
+      data_.reset(
+          new SequencedSocketData(reads, reads_count, writes, writes_count));
     }
 
     data_->set_connect_data(MockConnect(SYNCHRONOUS, OK));
-    data_->StopAfter(2);  // Request / Response
 
     socket_factory()->AddSocketDataProvider(data_.get());
 
@@ -290,8 +288,7 @@
   }
 
   HttpNetworkSession* CreateNetworkSession() {
-    return SpdySessionDependencies::SpdyCreateSessionDeterministic(
-        &session_deps_);
+    return SpdySessionDependencies::SpdyCreateSession(&session_deps_);
   }
 
   RequestPriority GetLastTransportRequestPriority() const {
@@ -311,7 +308,7 @@
  protected:
   SpdyTestUtil spdy_util_;
   scoped_ptr<SSLSocketDataProvider> ssl_data_;
-  scoped_ptr<DeterministicSocketData> data_;
+  scoped_ptr<SequencedSocketData> data_;
   HttpProxyClientSocketPool pool_;
   ClientSocketHandle handle_;
   TestCompletionCallback callback_;
@@ -400,14 +397,12 @@
              spdy_reads, arraysize(spdy_reads), spdy_writes,
              arraysize(spdy_writes));
 
-  data_->StopAfter(4);
   int rv = handle_.Init("a", CreateTunnelParams(NULL), LOW,
                         callback_.callback(), &pool_, BoundNetLog());
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_FALSE(handle_.is_initialized());
   EXPECT_FALSE(handle_.socket());
 
-  data_->RunFor(GetParam().proxy_type == SPDY ? 2 : 4);
   rv = callback_.WaitForResult();
   EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, rv);
   EXPECT_TRUE(handle_.is_initialized());
@@ -493,8 +488,9 @@
   };
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   MockRead spdy_reads[] = {
-    CreateMockRead(*resp, 1, ASYNC),
-    MockRead(ASYNC, 0, 2)
+      CreateMockRead(*resp, 1, ASYNC),
+      // Connection stays open.
+      MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2),
   };
 
   Initialize(reads, arraysize(reads), writes, arraysize(writes),
@@ -509,7 +505,6 @@
   EXPECT_FALSE(handle_.is_initialized());
   EXPECT_FALSE(handle_.socket());
 
-  data_->RunFor(2);
   EXPECT_EQ(OK, callback_.WaitForResult());
   EXPECT_TRUE(handle_.is_initialized());
   ASSERT_TRUE(handle_.socket());
@@ -548,13 +543,12 @@
                          callback_.callback(), &pool_, BoundNetLog()));
   EXPECT_EQ(MEDIUM, GetLastTransportRequestPriority());
 
-  data_->RunFor(2);
   EXPECT_EQ(OK, callback_.WaitForResult());
 }
 
 TEST_P(HttpProxyClientSocketPoolTest, TCPError) {
   if (GetParam().proxy_type == SPDY) return;
-  data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
+  data_.reset(new SequencedSocketData(NULL, 0, NULL, 0));
   data_->set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_CLOSED));
 
   socket_factory()->AddSocketDataProvider(data_.get());
@@ -573,7 +567,7 @@
 
 TEST_P(HttpProxyClientSocketPoolTest, SSLError) {
   if (GetParam().proxy_type == HTTP) return;
-  data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
+  data_.reset(new SequencedSocketData(NULL, 0, NULL, 0));
   data_->set_connect_data(MockConnect(ASYNC, OK));
   socket_factory()->AddSocketDataProvider(data_.get());
 
@@ -598,7 +592,7 @@
 
 TEST_P(HttpProxyClientSocketPoolTest, SslClientAuth) {
   if (GetParam().proxy_type == HTTP) return;
-  data_.reset(new DeterministicSocketData(NULL, 0, NULL, 0));
+  data_.reset(new SequencedSocketData(NULL, 0, NULL, 0));
   data_->set_connect_data(MockConnect(ASYNC, OK));
   socket_factory()->AddSocketDataProvider(data_.get());
 
@@ -654,7 +648,6 @@
   EXPECT_FALSE(handle_.is_initialized());
   EXPECT_FALSE(handle_.socket());
 
-  data_->RunFor(3);
   if (GetParam().proxy_type == SPDY) {
     // SPDY cannot process a headers block unless it's complete and so it
     // returns ERR_CONNECTION_CLOSED in this case.
@@ -693,7 +686,6 @@
   EXPECT_FALSE(handle_.is_initialized());
   EXPECT_FALSE(handle_.socket());
 
-  data_->RunFor(2);
   EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, callback_.WaitForResult());
 }
 
@@ -734,8 +726,6 @@
   EXPECT_FALSE(handle_.is_initialized());
   EXPECT_FALSE(handle_.socket());
 
-  data_->RunFor(2);
-
   rv = callback_.WaitForResult();
   // All Proxy CONNECT responses are not trustworthy
   EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv);
@@ -797,8 +787,6 @@
   EXPECT_FALSE(handle_.is_initialized());
   EXPECT_FALSE(handle_.socket());
 
-  data_->RunFor(2);
-
   rv = callback_.WaitForResult();
 
   if (GetParam().proxy_type == HTTP) {
diff --git a/net/http/http_request_headers.h b/net/http/http_request_headers.h
index f3d318a..e6f25eda 100644
--- a/net/http/http_request_headers.h
+++ b/net/http/http_request_headers.h
@@ -110,14 +110,18 @@
   void RemoveHeader(const base::StringPiece& key);
 
   // Parses the header from a string and calls SetHeader() with it.  This string
-  // should not contain any CRLF.  As per RFC2616, the format is:
+  // should not contain any CRLF.  As per RFC7230 Section 3.2, the format is:
   //
-  // message-header = field-name ":" [ field-value ]
+  // header-field   = field-name ":" OWS field-value OWS
+  //
   // field-name     = token
-  // field-value    = *( field-content | LWS )
-  // field-content  = <the OCTETs making up the field-value
-  //                  and consisting of either *TEXT or combinations
-  //                  of token, separators, and quoted-string>
+  // field-value    = *( field-content / obs-fold )
+  // field-content  = field-vchar [ 1*( SP / HTAB ) field-vchar ]
+  // field-vchar    = VCHAR / obs-text
+  //
+  // obs-fold       = CRLF 1*( SP / HTAB )
+  //                ; obsolete line folding
+  //                ; see Section 3.2.4
   //
   // AddHeaderFromString() will trim any LWS surrounding the
   // field-content.
diff --git a/net/http/http_server_properties.h b/net/http/http_server_properties.h
index f7cfa81..4192361 100644
--- a/net/http/http_server_properties.h
+++ b/net/http/http_server_properties.h
@@ -111,7 +111,7 @@
   AlternativeService& operator=(const AlternativeService& alternative_service) =
       default;
 
-  HostPortPair host_port_pair() { return HostPortPair(host, port); }
+  HostPortPair host_port_pair() const { return HostPortPair(host, port); }
 
   bool operator==(const AlternativeService& other) const {
     return protocol == other.protocol && host == other.host &&
@@ -187,6 +187,14 @@
 struct NET_EXPORT ServerNetworkStats {
   ServerNetworkStats() : bandwidth_estimate(QuicBandwidth::Zero()) {}
 
+  bool operator==(const ServerNetworkStats& other) const {
+    return srtt == other.srtt && bandwidth_estimate == other.bandwidth_estimate;
+  }
+
+  bool operator!=(const ServerNetworkStats& other) const {
+    return !this->operator==(other);
+  }
+
   base::TimeDelta srtt;
   QuicBandwidth bandwidth_estimate;
 };
@@ -218,6 +226,9 @@
   // request prioritization.
   virtual bool SupportsRequestPriority(const HostPortPair& server) = 0;
 
+  // Returns the value set by SetSupportsSpdy(). If not set, returns false.
+  virtual bool GetSupportsSpdy(const HostPortPair& server) = 0;
+
   // Add |server| into the persistent store. Should only be called from IO
   // thread.
   virtual void SetSupportsSpdy(const HostPortPair& server,
@@ -275,7 +286,7 @@
   virtual const AlternativeServiceMap& alternative_service_map() const = 0;
 
   // Returns all alternative service mappings as human readable strings.
-  virtual base::Value* GetAlternativeServiceInfoAsValue() const = 0;
+  virtual scoped_ptr<base::Value> GetAlternativeServiceInfoAsValue() const = 0;
 
   // Sets the threshold to be used when evaluating alternative service
   // advertisments. Only advertisements with a probability greater than or equal
@@ -310,6 +321,7 @@
   virtual void SetSupportsQuic(bool used_quic,
                                const IPAddressNumber& last_address) = 0;
 
+  // Sets |stats| for |host_port_pair|.
   virtual void SetServerNetworkStats(const HostPortPair& host_port_pair,
                                      ServerNetworkStats stats) = 0;
 
diff --git a/net/http/http_server_properties_impl.cc b/net/http/http_server_properties_impl.cc
index bbf30c8..d72e488 100644
--- a/net/http/http_server_properties_impl.cc
+++ b/net/http/http_server_properties_impl.cc
@@ -157,9 +157,7 @@
   if (host_port_pair.host().empty())
     return false;
 
-  SpdyServerHostPortMap::iterator spdy_host_port =
-      spdy_servers_map_.Get(host_port_pair.ToString());
-  if (spdy_host_port != spdy_servers_map_.end() && spdy_host_port->second)
+  if (GetSupportsSpdy(host_port_pair))
     return true;
 
   const AlternativeService alternative_service =
@@ -167,6 +165,17 @@
   return alternative_service.protocol == QUIC;
 }
 
+bool HttpServerPropertiesImpl::GetSupportsSpdy(
+    const HostPortPair& host_port_pair) {
+  DCHECK(CalledOnValidThread());
+  if (host_port_pair.host().empty())
+    return false;
+
+  SpdyServerHostPortMap::iterator spdy_host_port =
+      spdy_servers_map_.Get(host_port_pair.ToString());
+  return spdy_host_port != spdy_servers_map_.end() && spdy_host_port->second;
+}
+
 void HttpServerPropertiesImpl::SetSupportsSpdy(
     const HostPortPair& host_port_pair,
     bool support_spdy) {
@@ -395,9 +404,10 @@
   return alternative_service_map_;
 }
 
-base::Value* HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue()
+scoped_ptr<base::Value>
+HttpServerPropertiesImpl::GetAlternativeServiceInfoAsValue()
     const {
-  base::ListValue* dict_list = new base::ListValue();
+  scoped_ptr<base::ListValue> dict_list(new base::ListValue());
   for (const auto& alternative_service_map_item : alternative_service_map_) {
     const HostPortPair& host_port_pair = alternative_service_map_item.first;
     const AlternativeServiceInfo& alternative_service_info =
@@ -417,7 +427,7 @@
     dict->SetString("alternative_service", alternative_service_string);
     dict_list->Append(dict.Pass());
   }
-  return dict_list;
+  return dict_list.Pass();
 }
 
 const SettingsMap& HttpServerPropertiesImpl::GetSpdySettings(
diff --git a/net/http/http_server_properties_impl.h b/net/http/http_server_properties_impl.h
index e9f576fd..3ea0875 100644
--- a/net/http/http_server_properties_impl.h
+++ b/net/http/http_server_properties_impl.h
@@ -81,6 +81,7 @@
   base::WeakPtr<HttpServerProperties> GetWeakPtr() override;
   void Clear() override;
   bool SupportsRequestPriority(const HostPortPair& server) override;
+  bool GetSupportsSpdy(const HostPortPair& server) override;
   void SetSupportsSpdy(const HostPortPair& server, bool support_spdy) override;
   bool RequiresHTTP11(const HostPortPair& server) override;
   void SetHTTP11Required(const HostPortPair& server) override;
@@ -102,7 +103,7 @@
       const AlternativeService& alternative_service) override;
   void ClearAlternativeService(const HostPortPair& origin) override;
   const AlternativeServiceMap& alternative_service_map() const override;
-  base::Value* GetAlternativeServiceInfoAsValue() const override;
+  scoped_ptr<base::Value> GetAlternativeServiceInfoAsValue() const override;
   void SetAlternativeServiceProbabilityThreshold(double threshold) override;
   const SettingsMap& GetSpdySettings(
       const HostPortPair& host_port_pair) override;
diff --git a/net/http/http_server_properties_manager.cc b/net/http/http_server_properties_manager.cc
index c4d1a1a..26ce850d 100644
--- a/net/http/http_server_properties_manager.cc
+++ b/net/http/http_server_properties_manager.cc
@@ -155,12 +155,20 @@
   return http_server_properties_impl_->SupportsRequestPriority(server);
 }
 
+bool HttpServerPropertiesManager::GetSupportsSpdy(const HostPortPair& server) {
+  DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
+  return http_server_properties_impl_->GetSupportsSpdy(server);
+}
+
 void HttpServerPropertiesManager::SetSupportsSpdy(const HostPortPair& server,
                                                   bool support_spdy) {
   DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
 
+  bool old_support_spdy = http_server_properties_impl_->GetSupportsSpdy(server);
   http_server_properties_impl_->SetSupportsSpdy(server, support_spdy);
-  ScheduleUpdatePrefsOnNetworkThread(SUPPORTS_SPDY);
+  bool new_support_spdy = http_server_properties_impl_->GetSupportsSpdy(server);
+  if (old_support_spdy != new_support_spdy)
+    ScheduleUpdatePrefsOnNetworkThread(SUPPORTS_SPDY);
 }
 
 bool HttpServerPropertiesManager::RequiresHTTP11(const HostPortPair& server) {
@@ -237,15 +245,28 @@
 void HttpServerPropertiesManager::ConfirmAlternativeService(
     const AlternativeService& alternative_service) {
   DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
+  bool old_value = http_server_properties_impl_->IsAlternativeServiceBroken(
+      alternative_service);
   http_server_properties_impl_->ConfirmAlternativeService(alternative_service);
-  ScheduleUpdatePrefsOnNetworkThread(CONFIRM_ALTERNATIVE_SERVICE);
+  bool new_value = http_server_properties_impl_->IsAlternativeServiceBroken(
+      alternative_service);
+  // For persisting, we only care about the value returned by
+  // IsAlternativeServiceBroken. If that value changes, then call persist.
+  if (old_value != new_value)
+    ScheduleUpdatePrefsOnNetworkThread(CONFIRM_ALTERNATIVE_SERVICE);
 }
 
 void HttpServerPropertiesManager::ClearAlternativeService(
     const HostPortPair& origin) {
   DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
+  const AlternativeServiceMap& map =
+      http_server_properties_impl_->alternative_service_map();
+  size_t old_size = map.size();
   http_server_properties_impl_->ClearAlternativeService(origin);
-  ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALTERNATIVE_SERVICE);
+  size_t new_size = map.size();
+  // Persist only if we have deleted an entry.
+  if (old_size != new_size)
+    ScheduleUpdatePrefsOnNetworkThread(CLEAR_ALTERNATIVE_SERVICE);
 }
 
 const AlternativeServiceMap&
@@ -254,7 +275,8 @@
   return http_server_properties_impl_->alternative_service_map();
 }
 
-base::Value* HttpServerPropertiesManager::GetAlternativeServiceInfoAsValue()
+scoped_ptr<base::Value>
+HttpServerPropertiesManager::GetAlternativeServiceInfoAsValue()
     const {
   DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
   return http_server_properties_impl_->GetAlternativeServiceInfoAsValue();
@@ -323,8 +345,16 @@
     const HostPortPair& host_port_pair,
     ServerNetworkStats stats) {
   DCHECK(network_task_runner_->RunsTasksOnCurrentThread());
+  ServerNetworkStats old_stats;
+  const ServerNetworkStats* old_stats_ptr =
+      http_server_properties_impl_->GetServerNetworkStats(host_port_pair);
+  if (http_server_properties_impl_->GetServerNetworkStats(host_port_pair))
+    old_stats = *old_stats_ptr;
   http_server_properties_impl_->SetServerNetworkStats(host_port_pair, stats);
-  ScheduleUpdatePrefsOnNetworkThread(SET_SERVER_NETWORK_STATS);
+  ServerNetworkStats new_stats =
+      *(http_server_properties_impl_->GetServerNetworkStats(host_port_pair));
+  if (old_stats != new_stats)
+    ScheduleUpdatePrefsOnNetworkThread(SET_SERVER_NETWORK_STATS);
 }
 
 const ServerNetworkStats* HttpServerPropertiesManager::GetServerNetworkStats(
diff --git a/net/http/http_server_properties_manager.h b/net/http/http_server_properties_manager.h
index ef60d08..a7f0d01 100644
--- a/net/http/http_server_properties_manager.h
+++ b/net/http/http_server_properties_manager.h
@@ -81,6 +81,7 @@
   base::WeakPtr<HttpServerProperties> GetWeakPtr() override;
   void Clear() override;
   bool SupportsRequestPriority(const HostPortPair& server) override;
+  bool GetSupportsSpdy(const HostPortPair& server) override;
   void SetSupportsSpdy(const HostPortPair& server, bool support_spdy) override;
   bool RequiresHTTP11(const HostPortPair& server) override;
   void SetHTTP11Required(const HostPortPair& server) override;
@@ -102,7 +103,7 @@
       const AlternativeService& alternative_service) override;
   void ClearAlternativeService(const HostPortPair& origin) override;
   const AlternativeServiceMap& alternative_service_map() const override;
-  base::Value* GetAlternativeServiceInfoAsValue() const override;
+  scoped_ptr<base::Value> GetAlternativeServiceInfoAsValue() const override;
   void SetAlternativeServiceProbabilityThreshold(double threshold) override;
   const SettingsMap& GetSpdySettings(
       const HostPortPair& host_port_pair) override;
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc
index be17d9a0..77c4768 100644
--- a/net/http/http_server_properties_manager_unittest.cc
+++ b/net/http/http_server_properties_manager_unittest.cc
@@ -390,6 +390,8 @@
   EXPECT_FALSE(
       http_server_props_manager_->SupportsRequestPriority(spdy_server_mail));
   http_server_props_manager_->SetSupportsSpdy(spdy_server_mail, true);
+  // ExpectScheduleUpdatePrefsOnNetworkThread() should be called only once.
+  http_server_props_manager_->SetSupportsSpdy(spdy_server_mail, true);
 
   // Run the task.
   base::RunLoop().RunUntilIdle();
@@ -526,6 +528,73 @@
   EXPECT_EQ(NPN_SPDY_4, alternative_service.protocol);
 }
 
+TEST_F(HttpServerPropertiesManagerTest, ClearAlternativeService) {
+  ExpectPrefsUpdate();
+  ExpectScheduleUpdatePrefsOnNetworkThread();
+
+  HostPortPair spdy_server_mail("mail.google.com", 80);
+  EXPECT_FALSE(HasAlternativeService(spdy_server_mail));
+  AlternativeService alternative_service(NPN_SPDY_4, "mail.google.com", 443);
+  http_server_props_manager_->SetAlternativeService(spdy_server_mail,
+                                                    alternative_service, 1.0);
+  ExpectScheduleUpdatePrefsOnNetworkThread();
+  http_server_props_manager_->ClearAlternativeService(spdy_server_mail);
+  // ExpectScheduleUpdatePrefsOnNetworkThread() should be called only once.
+  http_server_props_manager_->ClearAlternativeService(spdy_server_mail);
+
+  // Run the task.
+  base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClearExpectations(http_server_props_manager_.get());
+
+  EXPECT_FALSE(HasAlternativeService(spdy_server_mail));
+}
+
+TEST_F(HttpServerPropertiesManagerTest, ConfirmAlternativeService) {
+  ExpectPrefsUpdate();
+
+  HostPortPair spdy_server_mail("mail.google.com", 80);
+  EXPECT_FALSE(HasAlternativeService(spdy_server_mail));
+  AlternativeService alternative_service(NPN_SPDY_4, "mail.google.com", 443);
+
+  ExpectScheduleUpdatePrefsOnNetworkThread();
+  http_server_props_manager_->SetAlternativeService(spdy_server_mail,
+                                                    alternative_service, 1.0);
+
+  EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
+      alternative_service));
+  EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
+      alternative_service));
+
+  ExpectScheduleUpdatePrefsOnNetworkThread();
+  http_server_props_manager_->MarkAlternativeServiceBroken(alternative_service);
+  EXPECT_TRUE(http_server_props_manager_->IsAlternativeServiceBroken(
+      alternative_service));
+  EXPECT_TRUE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
+      alternative_service));
+
+  ExpectScheduleUpdatePrefsOnNetworkThread();
+  http_server_props_manager_->ConfirmAlternativeService(alternative_service);
+  EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
+      alternative_service));
+  EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
+      alternative_service));
+  // ExpectScheduleUpdatePrefsOnNetworkThread() should be called only once.
+  http_server_props_manager_->ConfirmAlternativeService(alternative_service);
+  EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
+      alternative_service));
+  EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
+      alternative_service));
+
+  // Run the task.
+  base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClearExpectations(http_server_props_manager_.get());
+
+  EXPECT_FALSE(http_server_props_manager_->IsAlternativeServiceBroken(
+      alternative_service));
+  EXPECT_FALSE(http_server_props_manager_->WasAlternativeServiceRecentlyBroken(
+      alternative_service));
+}
+
 TEST_F(HttpServerPropertiesManagerTest, SupportsQuic) {
   ExpectPrefsUpdate();
   ExpectScheduleUpdatePrefsOnNetworkThread();
@@ -556,6 +625,8 @@
   ServerNetworkStats stats1;
   stats1.srtt = base::TimeDelta::FromMicroseconds(10);
   http_server_props_manager_->SetServerNetworkStats(mail_server, stats1);
+  // ExpectScheduleUpdatePrefsOnNetworkThread() should be called only once.
+  http_server_props_manager_->SetServerNetworkStats(mail_server, stats1);
 
   // Run the task.
   base::RunLoop().RunUntilIdle();
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc
index a8a9418..3f90078 100644
--- a/net/http/http_stream_factory_impl.cc
+++ b/net/http/http_stream_factory_impl.cc
@@ -99,22 +99,21 @@
     // Never share connection with other jobs for FTP requests.
     DCHECK(!request_info.url.SchemeIs("ftp"));
 
-    Job* alternate_job =
+    Job* alternative_job =
         new Job(this, session_, request_info, priority, server_ssl_config,
-                proxy_ssl_config, net_log.net_log());
-    request->AttachJob(alternate_job);
-    alternate_job->MarkAsAlternate(alternative_service);
+                proxy_ssl_config, alternative_service, net_log.net_log());
+    request->AttachJob(alternative_job);
 
-    job->WaitFor(alternate_job);
+    job->WaitFor(alternative_job);
     // Make sure to wait until we call WaitFor(), before starting
-    // |alternate_job|, otherwise |alternate_job| will not notify |job|
+    // |alternative_job|, otherwise |alternative_job| will not notify |job|
     // appropriately.
-    alternate_job->Start(request);
+    alternative_job->Start(request);
   }
 
-  // Even if |alternate_job| has already finished, it won't have notified the
-  // request yet, since we defer that to the next iteration of the MessageLoop,
-  // so starting |job| is always safe.
+  // Even if |alternative_job| has already finished, it will not have notified
+  // the request yet, since we defer that to the next iteration of the
+  // MessageLoop, so starting |job| is always safe.
   job->Start(request);
   return request;
 }
@@ -128,11 +127,9 @@
   DCHECK(!for_websockets_);
   AlternativeService alternative_service =
       GetAlternativeServiceFor(request_info.url);
-  Job* job = new Job(this, session_, request_info, priority, server_ssl_config,
-                     proxy_ssl_config, session_->net_log());
-  if (alternative_service.protocol != UNINITIALIZED_ALTERNATE_PROTOCOL) {
-    job->MarkAsAlternate(alternative_service);
-  }
+  Job* job =
+      new Job(this, session_, request_info, priority, server_ssl_config,
+              proxy_ssl_config, alternative_service, session_->net_log());
   preconnect_job_set_.insert(job);
   job->Preconnect(num_streams);
 }
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index c5a5f11..2ec9401 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -80,6 +80,24 @@
                                 const SSLConfig& server_ssl_config,
                                 const SSLConfig& proxy_ssl_config,
                                 NetLog* net_log)
+    : Job(stream_factory,
+          session,
+          request_info,
+          priority,
+          server_ssl_config,
+          proxy_ssl_config,
+          AlternativeService(),
+          net_log) {
+}
+
+HttpStreamFactoryImpl::Job::Job(HttpStreamFactoryImpl* stream_factory,
+                                HttpNetworkSession* session,
+                                const HttpRequestInfo& request_info,
+                                RequestPriority priority,
+                                const SSLConfig& server_ssl_config,
+                                const SSLConfig& proxy_ssl_config,
+                                AlternativeService alternative_service,
+                                NetLog* net_log)
     : request_(NULL),
       request_info_(request_info),
       priority_(priority),
@@ -92,6 +110,7 @@
       stream_factory_(stream_factory),
       next_state_(STATE_NONE),
       pac_request_(NULL),
+      alternative_service_(alternative_service),
       blocking_job_(NULL),
       waiting_job_(NULL),
       using_ssl_(false),
@@ -110,6 +129,10 @@
       ptr_factory_(this) {
   DCHECK(stream_factory);
   DCHECK(session);
+  if (IsQuicAlternative()) {
+    DCHECK(session_->params().enable_quic);
+    using_quic_ = true;
+  }
 }
 
 HttpStreamFactoryImpl::Job::~Job() {
@@ -171,21 +194,15 @@
   }
 }
 
-void HttpStreamFactoryImpl::Job::MarkAsAlternate(
-    AlternativeService alternative_service) {
-  DCHECK(!IsAlternate());
-  alternative_service_ = alternative_service;
-  if (alternative_service.protocol == QUIC) {
-    DCHECK(session_->params().enable_quic);
-    using_quic_ = true;
-  }
-}
-
 void HttpStreamFactoryImpl::Job::WaitFor(Job* job) {
   DCHECK_EQ(STATE_NONE, next_state_);
   DCHECK_EQ(STATE_NONE, job->next_state_);
   DCHECK(!blocking_job_);
   DCHECK(!job->waiting_job_);
+
+  // Never share connection with other jobs for FTP requests.
+  DCHECK(!request_info_.url.SchemeIs("ftp"));
+
   blocking_job_ = job;
   job->waiting_job_ = this;
 }
@@ -289,7 +306,7 @@
   // TODO(ricea): Add "wss" back to this list when SPDY WebSocket support is
   // working.
   return origin_url_.SchemeIs("https") ||
-         proxy_info_.proxy_server().is_https() || IsSpdyAlternate();
+         proxy_info_.proxy_server().is_https() || IsSpdyAlternative();
 }
 
 void HttpStreamFactoryImpl::Job::OnStreamReadyCallback() {
@@ -555,7 +572,7 @@
 
     default:
       DCHECK(result != ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN ||
-             IsAlternate());
+             IsSpdyAlternative() || IsQuicAlternative());
       if (job_status_ != STATUS_BROKEN) {
         DCHECK_EQ(STATUS_RUNNING, job_status_);
         job_status_ = STATUS_FAILED;
@@ -639,7 +656,7 @@
 }
 
 int HttpStreamFactoryImpl::Job::DoStart() {
-  if (IsAlternate()) {
+  if (IsSpdyAlternative() || IsQuicAlternative()) {
     server_ = alternative_service_.host_port_pair();
   } else {
     server_ = HostPortPair::FromURL(request_info_.url);
@@ -647,7 +664,7 @@
   origin_url_ =
       stream_factory_->ApplyHostMappingRules(request_info_.url, &server_);
   valid_spdy_session_pool_.reset(new ValidSpdySessionPool(
-      session_->spdy_session_pool(), origin_url_, IsSpdyAlternate()));
+      session_->spdy_session_pool(), origin_url_, IsSpdyAlternative()));
 
   net_log_.BeginEvent(
       NetLog::TYPE_HTTP_STREAM_JOB,
@@ -655,14 +672,8 @@
                  &alternative_service_, priority_));
 
   // Don't connect to restricted ports.
-  bool is_port_allowed = IsPortAllowedByDefault(server_.port());
-  if (request_info_.url.SchemeIs("ftp")) {
-    // Never share connection with other jobs for FTP requests.
-    DCHECK(!waiting_job_);
-
-    is_port_allowed = IsPortAllowedByFtp(server_.port());
-  }
-  if (!is_port_allowed && !IsPortAllowedByOverride(server_.port())) {
+  if (!IsPortAllowedForScheme(server_.port(), request_info_.url.scheme(),
+                              PORT_OVERRIDES_ALLOWED)) {
     if (waiting_job_) {
       waiting_job_->Resume(this);
       waiting_job_ = NULL;
@@ -691,7 +702,7 @@
   // https://<alternative host>:<alternative port>/...
   // so the proxy resolution works with the actual destination, and so
   // that the correct socket pool is used.
-  if (IsSpdyAlternate()) {
+  if (IsSpdyAlternative()) {
     // TODO(rch):  Figure out how to make QUIC iteract with PAC
     // scripts.  By not re-writing the URL, we will query the PAC script
     // for the proxy to use to reach the original URL via TCP.  But
@@ -732,7 +743,7 @@
     } else if (using_quic_ &&
                (!proxy_info_.is_quic() && !proxy_info_.is_direct())) {
       // QUIC can not be spoken to non-QUIC proxies.  This error should not be
-      // user visible, because the non-alternate job should be resumed.
+      // user visible, because the non-alternative Job should be resumed.
       result = ERR_NO_SUPPORTED_PROXIES;
     }
   }
@@ -782,7 +793,7 @@
   next_state_ = STATE_INIT_CONNECTION_COMPLETE;
 
   using_ssl_ = origin_url_.SchemeIs("https") || origin_url_.SchemeIs("wss") ||
-               IsSpdyAlternate();
+               IsSpdyAlternative();
   using_spdy_ = false;
 
   if (ShouldForceQuic())
@@ -857,8 +868,7 @@
   if (proxy_info_.is_http() || proxy_info_.is_https())
     establishing_tunnel_ = using_ssl_;
 
-  // TODO(bnc): s/want_spdy_over_npn/expect_spdy_over_npn/
-  bool want_spdy_over_npn = IsAlternate();
+  const bool expect_spdy = IsSpdyAlternative();
 
   if (proxy_info_.is_https()) {
     InitSSLConfig(proxy_info_.proxy_server().host_port_pair(),
@@ -886,9 +896,9 @@
     DCHECK(!stream_factory_->for_websockets_);
     return PreconnectSocketsForHttpRequest(
         GetSocketGroup(), server_, request_info_.extra_headers,
-        request_info_.load_flags, priority_, session_, proxy_info_,
-        want_spdy_over_npn, server_ssl_config_, proxy_ssl_config_,
-        request_info_.privacy_mode, net_log_, num_streams_);
+        request_info_.load_flags, priority_, session_, proxy_info_, expect_spdy,
+        server_ssl_config_, proxy_ssl_config_, request_info_.privacy_mode,
+        net_log_, num_streams_);
   }
 
   // If we can't use a SPDY session, don't bother checking for one after
@@ -904,18 +914,17 @@
     websocket_server_ssl_config.next_protos.clear();
     return InitSocketHandleForWebSocketRequest(
         GetSocketGroup(), server_, request_info_.extra_headers,
-        request_info_.load_flags, priority_, session_, proxy_info_,
-        want_spdy_over_npn, websocket_server_ssl_config, proxy_ssl_config_,
+        request_info_.load_flags, priority_, session_, proxy_info_, expect_spdy,
+        websocket_server_ssl_config, proxy_ssl_config_,
         request_info_.privacy_mode, net_log_, connection_.get(),
         resolution_callback, io_callback_);
   }
 
   return InitSocketHandleForHttpRequest(
       GetSocketGroup(), server_, request_info_.extra_headers,
-      request_info_.load_flags, priority_, session_, proxy_info_,
-      want_spdy_over_npn, server_ssl_config_, proxy_ssl_config_,
-      request_info_.privacy_mode, net_log_, connection_.get(),
-      resolution_callback, io_callback_);
+      request_info_.load_flags, priority_, session_, proxy_info_, expect_spdy,
+      server_ssl_config_, proxy_ssl_config_, request_info_.privacy_mode,
+      net_log_, connection_.get(), resolution_callback, io_callback_);
 }
 
 int HttpStreamFactoryImpl::Job::DoInitConnectionComplete(int result) {
@@ -1014,13 +1023,14 @@
     return result;
   }
 
-  if (IsSpdyAlternate() && !using_spdy_) {
+  if (IsSpdyAlternative() && !using_spdy_) {
     job_status_ = STATUS_BROKEN;
     MaybeMarkAlternativeServiceBroken();
     return ERR_NPN_NEGOTIATION_FAILED;
   }
 
-  if (!ssl_started && result < 0 && IsAlternate()) {
+  if (!ssl_started && result < 0 &&
+      (IsSpdyAlternative() || IsQuicAlternative())) {
     job_status_ = STATUS_BROKEN;
     // TODO(bnc): if (result == ERR_ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN), then
     // instead of marking alternative service broken, mark (origin, alternative
@@ -1056,7 +1066,7 @@
   if (using_ssl_) {
     DCHECK(ssl_started);
     if (IsCertificateError(result)) {
-      if (using_spdy_ && IsAlternate() && origin_url_.SchemeIs("http")) {
+      if (IsSpdyAlternative() && origin_url_.SchemeIs("http")) {
         // We ignore certificate errors for http over spdy.
         spdy_certificate_error_ = result;
         result = OK;
@@ -1107,8 +1117,7 @@
       FROM_HERE_WITH_EXPLICIT_FUNCTION(
           "462811 HttpStreamFactoryImpl::Job::DoCreateStream"));
   DCHECK(connection_->socket() || existing_spdy_session_.get() || using_quic_);
-  if (IsAlternate())
-    DCHECK(IsSpdyAlternate());
+  DCHECK(!IsQuicAlternative());
 
   next_state_ = STATE_CREATE_STREAM_COMPLETE;
 
@@ -1119,7 +1128,7 @@
     SetSocketMotivation();
 
   if (!using_spdy_) {
-    DCHECK(!IsSpdyAlternate());
+    DCHECK(!IsSpdyAlternative());
     // We may get ftp scheme when fetching ftp resources through proxy.
     bool using_proxy = (proxy_info_.is_http() || proxy_info_.is_https()) &&
                        (request_info_.url.SchemeIs("http") ||
@@ -1249,7 +1258,7 @@
 bool HttpStreamFactoryImpl::Job::IsHttpsProxyAndHttpUrl() const {
   if (!proxy_info_.is_https())
     return false;
-  if (IsAlternate()) {
+  if (IsSpdyAlternative() || IsQuicAlternative()) {
     // We currently only support Alternate-Protocol where the original scheme
     // is http.
     DCHECK(origin_url_.SchemeIs("http"));
@@ -1258,15 +1267,15 @@
   return request_info_.url.SchemeIs("http");
 }
 
-bool HttpStreamFactoryImpl::Job::IsAlternate() const {
-  return alternative_service_.protocol != UNINITIALIZED_ALTERNATE_PROTOCOL;
-}
-
-bool HttpStreamFactoryImpl::Job::IsSpdyAlternate() const {
+bool HttpStreamFactoryImpl::Job::IsSpdyAlternative() const {
   return alternative_service_.protocol >= NPN_SPDY_MINIMUM_VERSION &&
          alternative_service_.protocol <= NPN_SPDY_MAXIMUM_VERSION;
 }
 
+bool HttpStreamFactoryImpl::Job::IsQuicAlternative() const {
+  return alternative_service_.protocol == QUIC;
+}
+
 void HttpStreamFactoryImpl::Job::InitSSLConfig(const HostPortPair& server,
                                                SSLConfig* ssl_config,
                                                bool is_proxy) const {
@@ -1437,12 +1446,11 @@
     // If an existing session was used, then no TCP connection was
     // started.
     HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_NO_RACE);
-  } else if (IsAlternate()) {
-    // This job was the alternate protocol job, and hence won the race.
+  } else if (IsSpdyAlternative() || IsQuicAlternative()) {
+    // This Job was the alternative Job, and hence won the race.
     HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_WON_RACE);
   } else {
-    // This job was the normal job, and hence the alternate protocol job lost
-    // the race.
+    // This Job was the normal Job, and hence the alternative Job lost the race.
     HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_LOST_RACE);
   }
 }
@@ -1458,7 +1466,7 @@
   if (job_status_ == STATUS_RUNNING || other_job_status_ == STATUS_RUNNING)
     return;
 
-  if (IsAlternate()) {
+  if (IsSpdyAlternative() || IsQuicAlternative()) {
     if (job_status_ == STATUS_BROKEN && other_job_status_ == STATUS_SUCCEEDED) {
       HistogramBrokenAlternateProtocolLocation(
           BROKEN_ALTERNATE_PROTOCOL_LOCATION_HTTP_STREAM_FACTORY_IMPL_JOB_ALT);
@@ -1479,10 +1487,10 @@
 HttpStreamFactoryImpl::Job::ValidSpdySessionPool::ValidSpdySessionPool(
     SpdySessionPool* spdy_session_pool,
     GURL& origin_url,
-    bool is_spdy_alternate)
+    bool is_spdy_alternative)
     : spdy_session_pool_(spdy_session_pool),
       origin_url_(origin_url),
-      is_spdy_alternate_(is_spdy_alternate) {
+      is_spdy_alternative_(is_spdy_alternative) {
 }
 
 int HttpStreamFactoryImpl::Job::ValidSpdySessionPool::FindAvailableSession(
@@ -1508,10 +1516,10 @@
 int HttpStreamFactoryImpl::Job::ValidSpdySessionPool::
     CheckAlternativeServiceValidityForOrigin(
         base::WeakPtr<SpdySession> spdy_session) {
-  // For a SPDY alternate Job, server_.host() might be different than
+  // For an alternative Job, server_.host() might be different than
   // origin_url_.host(), therefore it needs to be verified that the former
   // provides a certificate that is valid for the latter.
-  if (!is_spdy_alternate_ || !spdy_session ||
+  if (!is_spdy_alternative_ || !spdy_session ||
       spdy_session->VerifyDomainAuthentication(origin_url_.host())) {
     return OK;
   }
@@ -1521,7 +1529,7 @@
 ClientSocketPoolManager::SocketGroupType
 HttpStreamFactoryImpl::Job::GetSocketGroup() const {
   std::string scheme = origin_url_.scheme();
-  if (scheme == "https" || scheme == "wss" || IsSpdyAlternate())
+  if (scheme == "https" || scheme == "wss" || IsSpdyAlternative())
     return ClientSocketPoolManager::SSL_GROUP;
 
   if (scheme == "ftp")
diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h
index f7285be3..637e3b1d 100644
--- a/net/http/http_stream_factory_impl_job.h
+++ b/net/http/http_stream_factory_impl_job.h
@@ -36,6 +36,7 @@
 // created for the StreamFactory.
 class HttpStreamFactoryImpl::Job {
  public:
+  // Constructor for non-alternative Job.
   Job(HttpStreamFactoryImpl* stream_factory,
       HttpNetworkSession* session,
       const HttpRequestInfo& request_info,
@@ -43,6 +44,15 @@
       const SSLConfig& server_ssl_config,
       const SSLConfig& proxy_ssl_config,
       NetLog* net_log);
+  // Constructor for alternative Job.
+  Job(HttpStreamFactoryImpl* stream_factory,
+      HttpNetworkSession* session,
+      const HttpRequestInfo& request_info,
+      RequestPriority priority,
+      const SSLConfig& server_ssl_config,
+      const SSLConfig& proxy_ssl_config,
+      AlternativeService alternative_service,
+      NetLog* net_log);
   ~Job();
 
   // Start initiates the process of creating a new HttpStream. |request| will be
@@ -56,10 +66,6 @@
   int RestartTunnelWithProxyAuth(const AuthCredentials& credentials);
   LoadState GetLoadState() const;
 
-  // Marks this Job as the "alternate" job, from Alternate-Protocol or Alt-Svc
-  // using the specified alternate service.
-  void MarkAsAlternate(AlternativeService alternative_service);
-
   // Tells |this| to wait for |job| to resume it.
   void WaitFor(Job* job);
 
@@ -146,13 +152,14 @@
    public:
     ValidSpdySessionPool(SpdySessionPool* spdy_session_pool,
                          GURL& origin_url,
-                         bool is_spdy_alternate);
+                         bool is_spdy_alternative);
 
     // Returns OK if a SpdySession was not found (in which case |spdy_session|
     // is set to nullptr), or if one was found (in which case |spdy_session| is
     // set to it) and it has an associated SSL certificate with is valid for
     // |origin_url_|, or if this requirement does not apply because the Job is
-    // not a SPDY alternate job.  Returns the appropriate error code otherwise,
+    // not a SPDY alternative job.  Returns the appropriate error code
+    // otherwise,
     // in which case |spdy_session| should not be used.
     int FindAvailableSession(const SpdySessionKey& key,
                              const BoundNetLog& net_log,
@@ -160,7 +167,7 @@
 
     // Creates a SpdySession and sets |spdy_session| to point to it.  Returns OK
     // if the associated SSL certificate is valid for |origin_url_|, or if this
-    // requirement does not apply because the Job is not a SPDY alternate job.
+    // requirement does not apply because the Job is not a SPDY alternative job.
     // Returns the appropriate error code otherwise, in which case
     // |spdy_session| should not be used.
     int CreateAvailableSessionFromSocket(
@@ -174,14 +181,14 @@
    private:
     // Returns OK if |spdy_session| has an associated SSL certificate with is
     // valid for |origin_url_|, or if this requirement does not apply because
-    // the Job is not a SPDY alternate job, or if |spdy_session| is null.
+    // the Job is not a SPDY alternative job, or if |spdy_session| is null.
     // Returns appropriate error code otherwise.
     int CheckAlternativeServiceValidityForOrigin(
         base::WeakPtr<SpdySession> spdy_session);
 
     SpdySessionPool* const spdy_session_pool_;
     const GURL origin_url_;
-    const bool is_spdy_alternate_;
+    const bool is_spdy_alternative_;
   };
 
   void OnStreamReadyCallback();
@@ -231,12 +238,9 @@
 
   bool IsHttpsProxyAndHttpUrl() const;
 
-  // Returns true iff this Job is an alternate, that is, iff MarkAsAlternate has
-  // been called.
-  bool IsAlternate() const;
-
-  // Returns true if this Job is a SPDY alternate job.
-  bool IsSpdyAlternate() const;
+  // Is this a SPDY or QUIC alternative Job?
+  bool IsSpdyAlternative() const;
+  bool IsQuicAlternative() const;
 
   // Sets several fields of |ssl_config| for |server| based on the proxy info
   // and other factors.
@@ -319,10 +323,10 @@
   // original request when host mapping rules are set-up.
   GURL origin_url_;
 
-  // AlternateProtocol for this job if this is an alternate job.
-  AlternativeService alternative_service_;
+  // AlternativeService for this Job if this is an alternative Job.
+  const AlternativeService alternative_service_;
 
-  // AlternateProtocol for the other job if this is not an alternate job.
+  // AlternativeService for the other Job if this is not an alternative Job.
   AlternativeService other_job_alternative_service_;
 
   // This is the Job we're dependent on. It will notify us if/when it's OK to
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc
index 6b20b9a7..df8db288 100644
--- a/net/http/http_stream_factory_impl_unittest.cc
+++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -552,8 +552,7 @@
 // Verify that preconnects to unsafe ports are cancelled before they reach
 // the SocketPool.
 TEST_P(HttpStreamFactoryTest, PreconnectUnsafePort) {
-  ASSERT_FALSE(IsPortAllowedByDefault(7));
-  ASSERT_FALSE(IsPortAllowedByOverride(7));
+  ASSERT_FALSE(IsPortAllowedForScheme(7, "http", PORT_OVERRIDES_ALLOWED));
 
   SpdySessionDependencies session_deps(
       GetParam(), ProxyService::CreateDirect());
@@ -570,7 +569,6 @@
   peer.SetClientSocketPoolManager(mock_pool_manager.Pass());
 
   PreconnectHelperForURL(1, GURL("http://www.google.com:7"), session.get());
-
   EXPECT_EQ(-1, transport_conn_pool->last_num_streams());
 }
 
@@ -1111,20 +1109,17 @@
                                        ProxyService::CreateDirect());
 
   MockRead mock_read(ASYNC, OK);
-  DeterministicSocketData socket_data(&mock_read, 1, nullptr, 0);
+  SequencedSocketData socket_data(&mock_read, 1, nullptr, 0);
   socket_data.set_connect_data(MockConnect(ASYNC, OK));
-  session_deps.deterministic_socket_factory->AddSocketDataProvider(
-      &socket_data);
+  session_deps.socket_factory->AddSocketDataProvider(&socket_data);
 
   SSLSocketDataProvider ssl_socket_data(ASYNC, OK);
   ssl_socket_data.SetNextProto(GetParam());
-  session_deps.deterministic_socket_factory->AddSSLSocketDataProvider(
-      &ssl_socket_data);
+  session_deps.socket_factory->AddSSLSocketDataProvider(&ssl_socket_data);
 
   HostPortPair host_port_pair("www.google.com", 443);
-  scoped_refptr<HttpNetworkSession>
-      session(SpdySessionDependencies::SpdyCreateSessionDeterministic(
-          &session_deps));
+  scoped_refptr<HttpNetworkSession> session(
+      SpdySessionDependencies::SpdyCreateSession(&session_deps));
 
   // Now request a stream.
   HttpRequestInfo request_info;
@@ -1296,25 +1291,21 @@
   session_deps.use_alternate_protocols = true;
 
   MockRead mock_read(ASYNC, OK);
-  DeterministicSocketData socket_data(&mock_read, 1, nullptr, 0);
+  SequencedSocketData socket_data(&mock_read, 1, nullptr, 0);
   socket_data.set_connect_data(MockConnect(ASYNC, OK));
-  session_deps.deterministic_socket_factory->AddSocketDataProvider(
-      &socket_data);
+  session_deps.socket_factory->AddSocketDataProvider(&socket_data);
 
   MockRead mock_read2(ASYNC, OK);
-  DeterministicSocketData socket_data2(&mock_read2, 1, nullptr, 0);
+  SequencedSocketData socket_data2(&mock_read2, 1, nullptr, 0);
   socket_data2.set_connect_data(MockConnect(ASYNC, ERR_IO_PENDING));
-  session_deps.deterministic_socket_factory->AddSocketDataProvider(
-      &socket_data2);
+  session_deps.socket_factory->AddSocketDataProvider(&socket_data2);
 
   SSLSocketDataProvider ssl_socket_data(ASYNC, OK);
   ssl_socket_data.SetNextProto(GetParam());
-  session_deps.deterministic_socket_factory->AddSSLSocketDataProvider(
-      &ssl_socket_data);
+  session_deps.socket_factory->AddSSLSocketDataProvider(&ssl_socket_data);
 
-  scoped_refptr<HttpNetworkSession>
-      session(SpdySessionDependencies::SpdyCreateSessionDeterministic(
-          &session_deps));
+  scoped_refptr<HttpNetworkSession> session(
+      SpdySessionDependencies::SpdyCreateSession(&session_deps));
 
   // Now request a stream.
   HttpRequestInfo request_info;
diff --git a/net/http/http_stream_parser.cc b/net/http/http_stream_parser.cc
index 46a17026..3c3b88d 100644
--- a/net/http/http_stream_parser.cc
+++ b/net/http/http_stream_parser.cc
@@ -963,16 +963,25 @@
   // Figure how to determine EOF:
 
   // For certain responses, we know the content length is always 0. From
-  // RFC 2616 Section 4.3 Message Body:
+  // RFC 7230 Section 3.3 Message Body:
   //
-  // For response messages, whether or not a message-body is included with
-  // a message is dependent on both the request method and the response
-  // status code (section 6.1.1). All responses to the HEAD request method
-  // MUST NOT include a message-body, even though the presence of entity-
-  // header fields might lead one to believe they do. All 1xx
-  // (informational), 204 (no content), and 304 (not modified) responses
-  // MUST NOT include a message-body. All other responses do include a
-  // message-body, although it MAY be of zero length.
+  // The presence of a message body in a response depends on both the
+  // request method to which it is responding and the response status code
+  // (Section 3.1.2).  Responses to the HEAD request method (Section 4.3.2
+  // of [RFC7231]) never include a message body because the associated
+  // response header fields (e.g., Transfer-Encoding, Content-Length,
+  // etc.), if present, indicate only what their values would have been if
+  // the request method had been GET (Section 4.3.1 of [RFC7231]). 2xx
+  // (Successful) responses to a CONNECT request method (Section 4.3.6 of
+  // [RFC7231]) switch to tunnel mode instead of having a message body.
+  // All 1xx (Informational), 204 (No Content), and 304 (Not Modified)
+  // responses do not include a message body.  All other responses do
+  // include a message body, although the body might be of zero length.
+  //
+  // From RFC 7231 Section 6.3.6 205 Reset Content:
+  //
+  // Since the 205 status code implies that no additional content will be
+  // provided, a server MUST NOT generate a payload in a 205 response.
   if (response_->headers->response_code() / 100 == 1) {
     response_body_length_ = 0;
   } else {
diff --git a/net/http/http_stream_parser_unittest.cc b/net/http/http_stream_parser_unittest.cc
index a30cb00..8590bb45 100644
--- a/net/http/http_stream_parser_unittest.cc
+++ b/net/http/http_stream_parser_unittest.cc
@@ -43,18 +43,18 @@
 // Helper method to create a connected ClientSocketHandle using |data|.
 // Modifies |data|.
 scoped_ptr<ClientSocketHandle> CreateConnectedSocketHandle(
-    DeterministicSocketData* data) {
+    SequencedSocketData* data) {
   data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
 
-  scoped_ptr<DeterministicMockTCPClientSocket> transport(
-      new DeterministicMockTCPClientSocket(nullptr, data));
-  data->set_delegate(transport->AsWeakPtr());
+  scoped_ptr<MockTCPClientSocket> socket(
+      new MockTCPClientSocket(net::AddressList(), nullptr, data));
+  data->set_socket(socket.get());
 
   TestCompletionCallback callback;
-  EXPECT_EQ(OK, transport->Connect(callback.callback()));
+  EXPECT_EQ(OK, socket->Connect(callback.callback()));
 
   scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
-  socket_handle->SetSocket(transport.Pass());
+  socket_handle->SetSocket(socket.Pass());
   return socket_handle.Pass();
 }
 
@@ -229,8 +229,7 @@
   ChunkedUploadDataStream upload_stream(0);
   ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
 
-  DeterministicSocketData data(reads, arraysize(reads), writes,
-                               arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   scoped_ptr<ClientSocketHandle> socket_handle =
       CreateConnectedSocketHandle(&data);
 
@@ -254,25 +253,16 @@
             parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
                                &response_info, callback.callback()));
 
-  // Complete the initial request write.
-  data.RunFor(1);
+  // Complete the initial request write.  Callback should not have been invoked.
+  base::RunLoop().RunUntilIdle();
   ASSERT_FALSE(callback.have_result());
 
-  // Now append the only chunk.
+  // Now append the only chunk and wait for the callback.
   upload_stream.AppendData(kChunk, arraysize(kChunk) - 1, true);
-  // Write the chunk.
-  data.RunFor(1);
-  ASSERT_FALSE(callback.have_result());
-
-  // Write the trailer.
-  data.RunFor(1);
-  ASSERT_TRUE(callback.have_result());
   ASSERT_EQ(OK, callback.WaitForResult());
 
   // Attempt to read the response status and the response headers.
   ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
-  data.RunFor(2);
-  ASSERT_TRUE(callback.have_result());
   ASSERT_GT(callback.WaitForResult(), 0);
 
   // Finally, attempt to read the response body.
@@ -280,8 +270,6 @@
   ASSERT_EQ(ERR_IO_PENDING,
             parser.ReadResponseBody(body_buffer.get(), kBodySize,
                                     callback.callback()));
-  data.RunFor(1);
-  ASSERT_TRUE(callback.have_result());
   ASSERT_EQ(kBodySize, callback.WaitForResult());
 }
 
@@ -315,8 +303,7 @@
   // Append the only chunk.
   upload_stream.AppendData(kChunk, arraysize(kChunk) - 1, true);
 
-  DeterministicSocketData data(reads, arraysize(reads), writes,
-                               arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   scoped_ptr<ClientSocketHandle> socket_handle =
       CreateConnectedSocketHandle(&data);
 
@@ -339,19 +326,10 @@
   ASSERT_EQ(ERR_IO_PENDING,
             parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
                                &response_info, callback.callback()));
-
-  // Write the request and the only chunk.
-  data.RunFor(2);
-
-  // Write the trailer.
-  data.RunFor(1);
-  ASSERT_TRUE(callback.have_result());
   ASSERT_EQ(OK, callback.WaitForResult());
 
   // Attempt to read the response status and the response headers.
   ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
-  data.RunFor(2);
-  ASSERT_TRUE(callback.have_result());
   ASSERT_GT(callback.WaitForResult(), 0);
 
   // Finally, attempt to read the response body.
@@ -359,8 +337,6 @@
   ASSERT_EQ(ERR_IO_PENDING,
             parser.ReadResponseBody(body_buffer.get(), kBodySize,
                                     callback.callback()));
-  data.RunFor(1);
-  ASSERT_TRUE(callback.have_result());
   ASSERT_EQ(kBodySize, callback.WaitForResult());
 }
 
@@ -401,8 +377,7 @@
   upload_stream.AppendData(kChunk1, arraysize(kChunk1) - 1, false);
   ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
 
-  DeterministicSocketData data(reads, arraysize(reads), writes,
-                               arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   scoped_ptr<ClientSocketHandle> socket_handle =
       CreateConnectedSocketHandle(&data);
 
@@ -425,47 +400,26 @@
   ASSERT_EQ(ERR_IO_PENDING,
             parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
                                &response_info, callback.callback()));
-
-  // Complete the initial request write. Additionally, this should enqueue the
-  // first chunk.
-  data.RunFor(1);
   ASSERT_FALSE(callback.have_result());
 
-  // Now append another chunk (while the first write is still pending), which
-  // should not confuse the state machine.
+  // Sending the request and the first chunk completes.
+  base::RunLoop().RunUntilIdle();
+  ASSERT_FALSE(callback.have_result());
+
+  // Now append another chunk.
   upload_stream.AppendData(kChunk2, arraysize(kChunk2) - 1, false);
   ASSERT_FALSE(callback.have_result());
 
-  // Complete writing the first chunk, which should then enqueue the second
-  // chunk for writing and return, because it is set to complete
-  // asynchronously.
-  data.RunFor(1);
-  ASSERT_FALSE(callback.have_result());
-
-  // Complete writing the second chunk. However, because no chunks are
-  // available yet, no further writes should be called until a new chunk is
-  // added.
-  data.RunFor(1);
-  ASSERT_FALSE(callback.have_result());
-
-  // Add the final chunk. This will enqueue another write, but it will not
-  // complete due to the async nature.
+  // Add the final chunk, while the write for the second is still pending,
+  // which should not confuse the state machine.
   upload_stream.AppendData(kChunk3, arraysize(kChunk3) - 1, true);
   ASSERT_FALSE(callback.have_result());
 
-  // Finalize writing the last chunk, which will enqueue the trailer.
-  data.RunFor(1);
-  ASSERT_FALSE(callback.have_result());
-
-  // Finalize writing the trailer.
-  data.RunFor(1);
-  ASSERT_TRUE(callback.have_result());
+  // Wait for writes to complete.
   ASSERT_EQ(OK, callback.WaitForResult());
 
   // Attempt to read the response status and the response headers.
   ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
-  data.RunFor(2);
-  ASSERT_TRUE(callback.have_result());
   ASSERT_GT(callback.WaitForResult(), 0);
 
   // Finally, attempt to read the response body.
@@ -473,8 +427,6 @@
   ASSERT_EQ(ERR_IO_PENDING,
             parser.ReadResponseBody(body_buffer.get(), kBodySize,
                                     callback.callback()));
-  data.RunFor(1);
-  ASSERT_TRUE(callback.have_result());
   ASSERT_EQ(kBodySize, callback.WaitForResult());
 }
 
@@ -503,8 +455,7 @@
   ChunkedUploadDataStream upload_stream(0);
   ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
 
-  DeterministicSocketData data(reads, arraysize(reads), writes,
-                               arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   scoped_ptr<ClientSocketHandle> socket_handle =
       CreateConnectedSocketHandle(&data);
 
@@ -528,23 +479,14 @@
             parser.SendRequest("GET /one.html HTTP/1.1\r\n", request_headers,
                                &response_info, callback.callback()));
 
-  // Complete writing the request headers.
-  data.RunFor(1);
-  ASSERT_FALSE(callback.have_result());
-
   // Now append the terminal 0-byte "chunk".
   upload_stream.AppendData(nullptr, 0, true);
   ASSERT_FALSE(callback.have_result());
 
-  // Finalize writing the trailer.
-  data.RunFor(1);
-  ASSERT_TRUE(callback.have_result());
   ASSERT_EQ(OK, callback.WaitForResult());
 
   // Attempt to read the response status and the response headers.
   ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
-  data.RunFor(2);
-  ASSERT_TRUE(callback.have_result());
   ASSERT_GT(callback.WaitForResult(), 0);
 
   // Finally, attempt to read the response body.
@@ -552,8 +494,6 @@
   ASSERT_EQ(ERR_IO_PENDING,
             parser.ReadResponseBody(body_buffer.get(), kBodySize,
                                     callback.callback()));
-  data.RunFor(1);
-  ASSERT_TRUE(callback.have_result());
   ASSERT_EQ(kBodySize, callback.WaitForResult());
 }
 
@@ -584,8 +524,7 @@
   // Append final empty chunk.
   upload_stream.AppendData(nullptr, 0, true);
 
-  DeterministicSocketData data(reads, arraysize(reads), writes,
-                               arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   scoped_ptr<ClientSocketHandle> socket_handle =
       CreateConnectedSocketHandle(&data);
 
@@ -610,14 +549,10 @@
                                &response_info, callback.callback()));
 
   // Complete writing the request headers and body.
-  data.RunFor(2);
-  ASSERT_TRUE(callback.have_result());
   ASSERT_EQ(OK, callback.WaitForResult());
 
   // Attempt to read the response status and the response headers.
   ASSERT_EQ(ERR_IO_PENDING, parser.ReadResponseHeaders(callback.callback()));
-  data.RunFor(2);
-  ASSERT_TRUE(callback.have_result());
   ASSERT_GT(callback.WaitForResult(), 0);
 
   // Finally, attempt to read the response body.
@@ -625,8 +560,6 @@
   ASSERT_EQ(ERR_IO_PENDING,
             parser.ReadResponseBody(body_buffer.get(), kBodySize,
                                     callback.callback()));
-  data.RunFor(1);
-  ASSERT_TRUE(callback.have_result());
   ASSERT_EQ(kBodySize, callback.WaitForResult());
 }
 
@@ -685,20 +618,9 @@
 
     for (size_t i = 0; i < arraysize(reads); i++) {
       SCOPED_TRACE(i);
-      DeterministicSocketData data(reads[i], 2, writes, arraysize(writes));
-      data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
-      data.SetStop(3);
-
-      scoped_ptr<DeterministicMockTCPClientSocket> transport(
-          new DeterministicMockTCPClientSocket(NULL, &data));
-      data.set_delegate(transport->AsWeakPtr());
-
-      TestCompletionCallback callback;
-      int rv = transport->Connect(callback.callback());
-      ASSERT_EQ(OK, rv);
-
-      scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
-      socket_handle->SetSocket(transport.Pass());
+      SequencedSocketData data(reads[i], 2, writes, arraysize(writes));
+      scoped_ptr<ClientSocketHandle> socket_handle(
+          CreateConnectedSocketHandle(&data));
 
       HttpRequestInfo request_info;
       request_info.method = "GET";
@@ -715,11 +637,11 @@
 
       HttpRequestHeaders request_headers;
       HttpResponseInfo response_info;
-      rv = parser.SendRequest("GET / HTTP/1.1\r\n", request_headers,
-                              &response_info, callback.callback());
-      ASSERT_EQ(OK, rv);
+      TestCompletionCallback callback;
+      ASSERT_EQ(OK, parser.SendRequest("GET / HTTP/1.1\r\n", request_headers,
+                                       &response_info, callback.callback()));
 
-      rv = parser.ReadResponseHeaders(callback.callback());
+      int rv = parser.ReadResponseHeaders(callback.callback());
       if (i == arraysize(reads) - 1) {
         EXPECT_EQ(OK, rv);
         EXPECT_TRUE(response_info.headers.get());
@@ -752,21 +674,9 @@
     MockWrite(SYNCHRONOUS, 0, "GET / HTTP/1.1\r\n\r\n"),
   };
 
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
-  data.SetStop(2);
-
-  scoped_ptr<DeterministicMockTCPClientSocket> transport(
-      new DeterministicMockTCPClientSocket(NULL, &data));
-  data.set_delegate(transport->AsWeakPtr());
-
-  TestCompletionCallback callback;
-  int rv = transport->Connect(callback.callback());
-  ASSERT_EQ(OK, rv);
-
-  scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
-  socket_handle->SetSocket(transport.Pass());
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  scoped_ptr<ClientSocketHandle> socket_handle =
+      CreateConnectedSocketHandle(&data);
 
   HttpRequestInfo request_info;
   request_info.method = "GET";
@@ -779,12 +689,11 @@
 
   HttpRequestHeaders request_headers;
   HttpResponseInfo response_info;
-  rv = parser.SendRequest("GET / HTTP/1.1\r\n", request_headers,
-                          &response_info, callback.callback());
-  ASSERT_EQ(OK, rv);
+  TestCompletionCallback callback;
+  ASSERT_EQ(OK, parser.SendRequest("GET / HTTP/1.1\r\n", request_headers,
+                                   &response_info, callback.callback()));
 
-  rv = parser.ReadResponseHeaders(callback.callback());
-  EXPECT_EQ(OK, rv);
+  EXPECT_EQ(OK, parser.ReadResponseHeaders(callback.callback()));
   ASSERT_TRUE(response_info.headers.get());
   EXPECT_EQ(101, response_info.headers->response_code());
   EXPECT_TRUE(response_info.headers->HasHeaderValue("Connection", "Upgrade"));
@@ -822,21 +731,9 @@
   void SetupParserAndSendRequest() {
     reads_.push_back(MockRead(SYNCHRONOUS, 0, sequence_number_++));  // EOF
 
-    socket_handle_.reset(new ClientSocketHandle);
-    data_.reset(new DeterministicSocketData(
-        &reads_.front(), reads_.size(), &writes_.front(), writes_.size()));
-    data_->set_connect_data(MockConnect(SYNCHRONOUS, OK));
-    data_->SetStop(reads_.size() + writes_.size());
-
-    transport_.reset(new DeterministicMockTCPClientSocket(NULL, data_.get()));
-    data_->set_delegate(transport_->AsWeakPtr());
-
-    TestCompletionCallback callback;
-    int rv = transport_->Connect(callback.callback());
-    rv = callback.GetResult(rv);
-    ASSERT_EQ(OK, rv);
-
-    socket_handle_->SetSocket(transport_.Pass());
+    data_.reset(new SequencedSocketData(&reads_.front(), reads_.size(),
+                                        &writes_.front(), writes_.size()));
+    socket_handle_ = CreateConnectedSocketHandle(data_.get());
 
     request_info_.method = "GET";
     request_info_.url = GURL("http://localhost");
@@ -845,9 +742,9 @@
     parser_.reset(new HttpStreamParser(
         socket_handle_.get(), &request_info_, read_buffer(), BoundNetLog()));
 
-    rv = parser_->SendRequest("GET / HTTP/1.1\r\n", request_headers_,
-                              &response_info_, callback.callback());
-    ASSERT_EQ(OK, rv);
+    TestCompletionCallback callback;
+    ASSERT_EQ(OK, parser_->SendRequest("GET / HTTP/1.1\r\n", request_headers_,
+                                       &response_info_, callback.callback()));
   }
 
   void ReadHeaders() {
@@ -878,8 +775,7 @@
   std::vector<MockRead> reads_;
   std::vector<MockWrite> writes_;
   scoped_ptr<ClientSocketHandle> socket_handle_;
-  scoped_ptr<DeterministicSocketData> data_;
-  scoped_ptr<DeterministicMockTCPClientSocket> transport_;
+  scoped_ptr<SequencedSocketData> data_;
   scoped_ptr<HttpStreamParser> parser_;
   int sequence_number_;
 };
@@ -1118,30 +1014,20 @@
   MockWrite writes[] = {
     MockWrite(SYNCHRONOUS, 0,
               "GET /foo.html HTTP/1.1\r\n\r\n"),
-    MockWrite(SYNCHRONOUS, 1, "1"),
   };
 
   const int kBodySize = 1;
   MockRead reads[] = {
-    MockRead(SYNCHRONOUS, 5, "HTTP/1.1 200 OK\r\n"),
-    MockRead(SYNCHRONOUS, 6, "Content-Length: 1\r\n\r\n"),
-    MockRead(SYNCHRONOUS, 6, "Connection: Keep-Alive\r\n\r\n"),
-    MockRead(SYNCHRONOUS, 7, "1"),
-    MockRead(SYNCHRONOUS, 0, 8),  // EOF
+      MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n"),
+      MockRead(SYNCHRONOUS, 2, "Content-Length: 1\r\n\r\n"),
+      MockRead(SYNCHRONOUS, 3, "Connection: Keep-Alive\r\n\r\n"),
+      MockRead(SYNCHRONOUS, 4, "1"),
+      MockRead(SYNCHRONOUS, 0, 5),  // EOF
   };
 
-  StaticSocketDataProvider data(reads, arraysize(reads), writes,
-                                arraysize(writes));
-  data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
-
-  scoped_ptr<MockTCPClientSocket> transport(
-      new MockTCPClientSocket(AddressList(), NULL, &data));
-
-  TestCompletionCallback callback;
-  ASSERT_EQ(OK, transport->Connect(callback.callback()));
-
-  scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
-  socket_handle->SetSocket(transport.Pass());
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  scoped_ptr<ClientSocketHandle> socket_handle =
+      CreateConnectedSocketHandle(&data);
 
   scoped_ptr<HttpRequestInfo> request_info(new HttpRequestInfo());
   request_info->method = "GET";
@@ -1153,6 +1039,7 @@
 
   scoped_ptr<HttpRequestHeaders> request_headers(new HttpRequestHeaders());
   scoped_ptr<HttpResponseInfo> response_info(new HttpResponseInfo());
+  TestCompletionCallback callback;
   ASSERT_EQ(OK, parser.SendRequest("GET /foo.html HTTP/1.1\r\n",
             *request_headers, response_info.get(), callback.callback()));
   ASSERT_EQ(OK, parser.ReadResponseHeaders(callback.callback()));
diff --git a/net/http/http_transaction_test_util.cc b/net/http/http_transaction_test_util.cc
index d6daf0e..d4fa2de6 100644
--- a/net/http/http_transaction_test_util.cc
+++ b/net/http/http_transaction_test_util.cc
@@ -14,6 +14,7 @@
 #include "net/base/load_flags.h"
 #include "net/base/load_timing_info.h"
 #include "net/base/net_errors.h"
+#include "net/cert/x509_certificate.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/http/http_cache.h"
 #include "net/http/http_request_info.h"
@@ -42,7 +43,9 @@
     base::Time(),
     "<html><body>Google Blah Blah</body></html>",
     TEST_MODE_NORMAL,
-    NULL,
+    nullptr,
+    nullptr,
+    0,
     0,
     OK};
 
@@ -57,7 +60,9 @@
     base::Time(),
     "<html><body>Google Blah Blah</body></html>",
     TEST_MODE_NORMAL,
-    NULL,
+    nullptr,
+    nullptr,
+    0,
     0,
     OK};
 
@@ -73,7 +78,9 @@
     base::Time(),
     "<html><body>Google Blah Blah</body></html>",
     TEST_MODE_NORMAL,
-    NULL,
+    nullptr,
+    nullptr,
+    0,
     0,
     OK};
 
@@ -89,7 +96,9 @@
     base::Time(),
     "<html><body>Google Blah Blah</body></html>",
     TEST_MODE_NORMAL,
-    NULL,
+    nullptr,
+    nullptr,
+    0,
     0,
     OK};
 
@@ -104,7 +113,9 @@
     base::Time(),
     "<html><body>Google Blah Blah</body></html>",
     TEST_MODE_NORMAL,
-    NULL,
+    nullptr,
+    nullptr,
+    0,
     0,
     OK};
 
@@ -410,7 +421,9 @@
 
   response_.headers = new HttpResponseHeaders(header_data);
   response_.vary_data.Init(*request, *response_.headers.get());
+  response_.ssl_info.cert = t->cert;
   response_.ssl_info.cert_status = t->cert_status;
+  response_.ssl_info.connection_status = t->ssl_connection_status;
   data_ = resp_data;
 
   if (net_log.net_log())
diff --git a/net/http/http_transaction_test_util.h b/net/http/http_transaction_test_util.h
index 163b0424..52b38e84 100644
--- a/net/http/http_transaction_test_util.h
+++ b/net/http/http_transaction_test_util.h
@@ -30,6 +30,7 @@
 
 class HttpRequestHeaders;
 class IOBuffer;
+class X509Certificate;
 struct HttpRequestInfo;
 
 //-----------------------------------------------------------------------------
@@ -68,7 +69,9 @@
   const char* data;
   int test_mode;
   MockTransactionHandler handler;
+  scoped_refptr<X509Certificate> cert;
   CertStatus cert_status;
+  int ssl_connection_status;
   // Value returned by MockNetworkTransaction::Start (potentially
   // asynchronously if |!(test_mode & TEST_MODE_SYNC_NET_START)|.)
   Error return_code;
diff --git a/net/http/proxy_client_socket.cc b/net/http/proxy_client_socket.cc
index ab072d106..a07253d 100644
--- a/net/http/proxy_client_socket.cc
+++ b/net/http/proxy_client_socket.cc
@@ -38,9 +38,10 @@
     const std::string& user_agent,
     std::string* request_line,
     HttpRequestHeaders* request_headers) {
-  // RFC 2616 Section 9 says the Host request-header field MUST accompany all
-  // HTTP/1.1 requests.  Add "Proxy-Connection: keep-alive" for compat with
-  // HTTP/1.0 proxies such as Squid (required for NTLM authentication).
+  // RFC 7230 Section 5.4 says a client MUST send a Host header field in all
+  // HTTP/1.1 request messages, and Host SHOULD be the first header field
+  // following the request-line.  Add "Proxy-Connection: keep-alive" for compat
+  // with HTTP/1.0 proxies such as Squid (required for NTLM authentication).
   std::string host_and_port = endpoint.ToString();
   *request_line =
       base::StringPrintf("CONNECT %s HTTP/1.1\r\n", host_and_port.c_str());
diff --git a/net/http/transport_security_state_static.h b/net/http/transport_security_state_static.h
index fc91bfe..733477cd 100644
--- a/net/http/transport_security_state_static.h
+++ b/net/http/transport_security_state_static.h
@@ -266,6 +266,8 @@
   DOMAIN_SPIDEROAK_COM,
   DOMAIN_BLOGGER_COM,
   DOMAIN_CHROME_COM,
+  DOMAIN_GVT3_COM,
+  DOMAIN_GVT2_COM,
   // Boundary value for UMA_HISTOGRAM_ENUMERATION.
   DOMAIN_NUM_EVENTS,
 };
@@ -680,1868 +682,2048 @@
 // value has the MSB set then it represents a literal leaf value. Otherwise
 // it's a pointer to the n'th element of the array.
 static const uint8 kHSTSHuffmanTree[] = {
-    0xf0, 0xe4, 0x00, 0xe9, 0xb9, 0xb8, 0x02, 0xb1, 0xb7, 0xb6, 0x04, 0xb5,
-    0xb2, 0x05, 0x03, 0x06, 0x07, 0xea, 0xfa, 0x08, 0xe6, 0x09, 0x0a, 0xed,
-    0xf2, 0x0b, 0x01, 0x0c, 0xeb, 0xf7, 0x0e, 0xe3, 0xe1, 0x0f, 0x80, 0x10,
-    0x0d, 0x11, 0xb0, 0xf1, 0xb3, 0xb4, 0x13, 0x14, 0x15, 0xf8, 0xf6, 0x16,
-    0x17, 0xe2, 0xe7, 0x18, 0xef, 0x19, 0xff, 0x1a, 0xae, 0xe8, 0xf3, 0x1c,
+    0xf0, 0xe4, 0x00, 0xf2, 0x01, 0x80, 0xb9, 0xb8, 0x03, 0xb1, 0xb7, 0xb6,
+    0x05, 0xb5, 0xb0, 0x06, 0x04, 0x07, 0x08, 0xea, 0xfa, 0x09, 0xe6, 0x0a,
+    0x0b, 0xed, 0xe9, 0x0c, 0xeb, 0xf7, 0x0e, 0xe3, 0x0f, 0xe1, 0x0d, 0x10,
+    0x02, 0x11, 0xb3, 0xb2, 0xf1, 0xb4, 0x13, 0x14, 0x15, 0xf8, 0xf6, 0x16,
+    0xae, 0x17, 0xe7, 0x18, 0xef, 0x19, 0xff, 0x1a, 0xe2, 0xe8, 0xf3, 0x1c,
     0xe5, 0x1d, 0xee, 0xec, 0xad, 0xf9, 0x20, 0xf5, 0xf4, 0x21, 0x1f, 0x22,
     0x1e, 0x23, 0x1b, 0x24, 0x12, 0x25,
 };
 
 static const uint8 kPreloadedHSTSData[] = {
-    0xfe, 0xdb, 0x3b, 0x6a, 0xab, 0x2a, 0x22, 0x59, 0xcf, 0x23, 0x75, 0xa6,
-    0xdf, 0xcb, 0x4f, 0xff, 0x37, 0x19, 0xe5, 0x46, 0x6e, 0xf6, 0xcf, 0x2d,
-    0x35, 0x69, 0x68, 0x79, 0xfd, 0x04, 0x5c, 0x53, 0xa7, 0xff, 0x6b, 0xf3,
-    0xf0, 0xb3, 0x7f, 0x15, 0x71, 0x69, 0xd5, 0x56, 0x54, 0x45, 0xb0, 0xf3,
-    0xf1, 0xb2, 0x54, 0xdd, 0xd2, 0xd1, 0xd3, 0x71, 0xa2, 0x29, 0xfe, 0x74,
-    0x87, 0x42, 0x5b, 0xbd, 0x69, 0xc1, 0x1b, 0xd6, 0x81, 0x3d, 0x4a, 0x38,
-    0x9f, 0xfc, 0xd6, 0xeb, 0x18, 0xc5, 0xe3, 0x62, 0x6c, 0x4d, 0x95, 0xa7,
-    0xff, 0x09, 0x13, 0x6f, 0xf7, 0x3b, 0xac, 0x75, 0x69, 0xb3, 0x74, 0xa4,
-    0xc9, 0x48, 0x1d, 0x34, 0xa0, 0x16, 0x9f, 0xde, 0xce, 0x80, 0xe3, 0xa4,
-    0xb6, 0x34, 0xf3, 0xf3, 0xf8, 0x37, 0x31, 0xc5, 0xa1, 0x8f, 0xca, 0x90,
-    0xe7, 0xee, 0x0d, 0x98, 0xe2, 0xb4, 0xfe, 0x60, 0x5f, 0x4f, 0x63, 0x75,
-    0xa4, 0x4c, 0x7c, 0x04, 0x57, 0x2d, 0x8d, 0x82, 0xe0, 0x5b, 0x42, 0x63,
-    0x21, 0xaf, 0xc7, 0x52, 0x20, 0xd2, 0xd5, 0xdc, 0x61, 0x1f, 0x61, 0x01,
-    0x3f, 0xff, 0xf5, 0x1f, 0x61, 0xef, 0x7f, 0xef, 0x58, 0xb0, 0xc1, 0xe7,
-    0x33, 0xea, 0xd3, 0xee, 0xda, 0xaa, 0xca, 0x8a, 0x8a, 0x7f, 0xfd, 0x4f,
-    0x26, 0xd6, 0x6f, 0x62, 0xac, 0xde, 0xcb, 0x4b, 0x6c, 0x44, 0x35, 0xc3,
-    0x39, 0xff, 0x07, 0x0f, 0xb5, 0xde, 0x10, 0xf9, 0x69, 0xfd, 0x99, 0x78,
-    0x5b, 0x02, 0xb4, 0xd5, 0xfa, 0xd3, 0xdc, 0x1e, 0x6c, 0x61, 0xe3, 0xba,
-    0x63, 0x3e, 0xed, 0xaa, 0xac, 0xa8, 0xaf, 0x67, 0xc2, 0x6a, 0xdf, 0xde,
-    0xb4, 0xcc, 0x05, 0xa5, 0xb6, 0x1f, 0x9f, 0x4c, 0xc0, 0x57, 0x3f, 0xf6,
-    0xd4, 0xfd, 0xb3, 0xb6, 0xaa, 0xb2, 0xa2, 0x46, 0x9f, 0xfd, 0xb1, 0xe9,
-    0xfb, 0x67, 0x6d, 0x55, 0x65, 0x44, 0xf1, 0x3f, 0xfb, 0x63, 0xd3, 0xf6,
-    0xce, 0xda, 0xaa, 0xca, 0x89, 0xfe, 0x7f, 0xf6, 0xc7, 0xa7, 0xed, 0x9d,
-    0xb5, 0x55, 0x95, 0x14, 0x34, 0xff, 0xc7, 0xa7, 0xed, 0x9d, 0xb5, 0x55,
-    0x95, 0x14, 0x44, 0xff, 0x9f, 0xb7, 0xfa, 0xf8, 0xda, 0x67, 0xad, 0x1b,
-    0x22, 0x49, 0x94, 0x27, 0xdd, 0xb5, 0x55, 0x95, 0x14, 0x8c, 0xff, 0x33,
-    0xdb, 0xb7, 0xb7, 0x6f, 0x5a, 0x75, 0x3f, 0x6c, 0x3e, 0xc2, 0x33, 0x9f,
-    0xff, 0xb0, 0x3c, 0x6f, 0xbb, 0x78, 0xa8, 0x1a, 0xd3, 0x01, 0x29, 0x6c,
-    0x74, 0x47, 0x5d, 0x99, 0x4f, 0xfd, 0xb5, 0x3f, 0x6c, 0xed, 0xaa, 0xac,
-    0xa8, 0x94, 0x22, 0xf6, 0x57, 0xab, 0xe7, 0x12, 0x83, 0x09, 0x8b, 0x43,
-    0xe8, 0x4a, 0xcd, 0xe1, 0x0f, 0xd8, 0x57, 0x9c, 0xd7, 0x8a, 0x20, 0x57,
-    0xba, 0x55, 0xf5, 0x0e, 0x9f, 0xe3, 0x1d, 0x34, 0x5b, 0x3f, 0xfb, 0x63,
-    0xd3, 0xf6, 0xce, 0xda, 0xaa, 0xca, 0x89, 0xce, 0x7f, 0xf6, 0xc7, 0xa7,
-    0xed, 0x9d, 0xb5, 0x55, 0x95, 0x14, 0x4c, 0xfc, 0x3a, 0x71, 0xe2, 0x05,
-    0xa7, 0xf3, 0x5f, 0xf6, 0xee, 0x88, 0x0b, 0x4e, 0xeb, 0xf6, 0xe1, 0xf2,
-    0x7d, 0x2d, 0x8e, 0xa6, 0x93, 0xa5, 0x7f, 0xe1, 0x77, 0x3f, 0xb6, 0xce,
-    0xda, 0xaa, 0xca, 0x88, 0x72, 0x7f, 0x9b, 0xb9, 0x6e, 0x36, 0xef, 0x5a,
-    0x7a, 0xd5, 0x56, 0x54, 0x45, 0xf3, 0xec, 0x71, 0xf5, 0xa5, 0xa3, 0xa7,
-    0xa9, 0xf4, 0xb6, 0x7f, 0x6b, 0x03, 0xcc, 0x05, 0x2d, 0x31, 0x5e, 0xb4,
-    0xff, 0x78, 0x98, 0xff, 0x43, 0xc6, 0x5a, 0x18, 0xf3, 0xc4, 0x5a, 0x6d,
-    0x6e, 0xb4, 0xf7, 0x9e, 0xc6, 0x25, 0x07, 0x37, 0x34, 0x2f, 0x3e, 0xab,
-    0xfd, 0x9c, 0x5a, 0x5b, 0x5e, 0x9e, 0x86, 0x42, 0x31, 0xc2, 0x4e, 0x42,
-    0x00, 0x96, 0x6e, 0xc8, 0x27, 0xff, 0x6c, 0x7a, 0x7e, 0xd9, 0xdb, 0x55,
-    0x59, 0x51, 0x32, 0x4f, 0xed, 0xb3, 0xb6, 0xaa, 0xb2, 0xa2, 0xde, 0x9f,
-    0xfd, 0xb1, 0xe9, 0xfb, 0x67, 0x6d, 0x55, 0x65, 0x45, 0x27, 0x35, 0xd1,
-    0x75, 0x2d, 0x3f, 0x6e, 0x0f, 0xbd, 0xa0, 0x2d, 0x37, 0x36, 0x36, 0x8f,
-    0x42, 0x88, 0x21, 0x95, 0xf5, 0xbe, 0x50, 0x7e, 0x36, 0x69, 0x5e, 0xe1,
-    0xff, 0xd8, 0x53, 0xcf, 0xed, 0xb3, 0xb6, 0xaa, 0xb2, 0xa2, 0x1d, 0x9f,
-    0xfd, 0xb1, 0xe9, 0xfb, 0x67, 0x6d, 0x55, 0x65, 0x44, 0xb1, 0x3f, 0xb6,
-    0xce, 0xda, 0xaa, 0xca, 0x88, 0xc2, 0x7b, 0x67, 0xe6, 0x96, 0x9f, 0xfc,
-    0xde, 0x10, 0x33, 0xc3, 0xc6, 0x2b, 0x2d, 0x3e, 0xed, 0xaa, 0xac, 0xa8,
-    0x8f, 0x67, 0xb5, 0x5b, 0xdc, 0x5a, 0x67, 0xed, 0x87, 0xaf, 0xe3, 0x39,
-    0x6d, 0xd4, 0x66, 0x54, 0x27, 0xa7, 0xdd, 0xb5, 0x55, 0x95, 0x16, 0x1c,
-    0xfe, 0x79, 0x36, 0x6b, 0x09, 0x69, 0x6d, 0x87, 0xc5, 0xb9, 0x9c, 0xfe,
-    0xdb, 0x3b, 0x6a, 0xab, 0x2a, 0x2e, 0x78, 0x65, 0x57, 0x77, 0x9f, 0xbd,
-    0x5e, 0xc7, 0xe3, 0x0e, 0xe3, 0xc2, 0x43, 0xc5, 0x33, 0xfb, 0x6c, 0xed,
-    0xaa, 0xac, 0xa8, 0x87, 0xa7, 0xdd, 0xb5, 0x55, 0x95, 0x11, 0x34, 0xff,
-    0xde, 0xae, 0x71, 0xae, 0x3f, 0x3a, 0xcb, 0x4f, 0xf0, 0xf8, 0x7d, 0x80,
-    0x6e, 0xad, 0x18, 0x7f, 0x54, 0x89, 0x37, 0x8e, 0xb4, 0xff, 0xec, 0xe7,
-    0xdb, 0xf4, 0xc3, 0xbf, 0x98, 0xeb, 0x46, 0xe7, 0xc5, 0xc1, 0x69, 0xef,
-    0x7f, 0x5f, 0x55, 0x10, 0xbc, 0xfc, 0x1e, 0x65, 0xff, 0x92, 0xd2, 0xdb,
-    0x13, 0xb1, 0xe4, 0x2b, 0x75, 0x08, 0x2f, 0xc8, 0xee, 0x18, 0xcd, 0xff,
-    0x16, 0x9e, 0x0e, 0x13, 0x8b, 0x4c, 0x3e, 0x5a, 0x5e, 0x13, 0x6d, 0xc2,
-    0x19, 0xff, 0xff, 0xb9, 0xf8, 0x47, 0x3a, 0xe1, 0x65, 0xce, 0x60, 0x5b,
-    0x5a, 0x63, 0x16, 0x9f, 0xfc, 0x2e, 0x3f, 0x37, 0x7f, 0xc3, 0xd5, 0x12,
-    0xd3, 0x51, 0xa5, 0xa4, 0x6d, 0x62, 0x3f, 0x2c, 0x4d, 0xc7, 0x4a, 0x4b,
-    0x9a, 0xec, 0xc5, 0xa7, 0xdc, 0xaf, 0x53, 0xd6, 0x9f, 0xcf, 0xd3, 0x68,
-    0xdb, 0x2e, 0x8b, 0xa1, 0x69, 0xe1, 0xd0, 0x81, 0x69, 0xce, 0xba, 0xea,
-    0x53, 0xea, 0x2f, 0x73, 0x12, 0xd8, 0xbf, 0x9f, 0x57, 0x9c, 0xcf, 0x2d,
-    0x01, 0x44, 0xd8, 0x0f, 0xc8, 0xd6, 0x7b, 0x95, 0x54, 0xb4, 0xff, 0xc0,
-    0x17, 0x3e, 0x71, 0x87, 0xbf, 0x9b, 0xad, 0x3f, 0xe1, 0x31, 0x89, 0xb4,
-    0xc2, 0x75, 0xa7, 0xec, 0xb9, 0xfb, 0xf3, 0x4b, 0x4f, 0x60, 0x72, 0xf5,
-    0xa7, 0x8d, 0xfe, 0x31, 0xb2, 0xb4, 0xdd, 0x65, 0xa3, 0x15, 0x34, 0x6e,
-    0x4c, 0x30, 0xdf, 0x37, 0x2f, 0x70, 0x7f, 0x89, 0x44, 0x77, 0xe2, 0xfb,
-    0x84, 0x26, 0x8a, 0xe7, 0xec, 0x75, 0xb0, 0x22, 0xb4, 0xe6, 0xfc, 0x0b,
-    0x4f, 0xff, 0xfe, 0x22, 0xdd, 0x8c, 0x2c, 0x0f, 0x05, 0xcf, 0x9a, 0xcd,
-    0xdf, 0xdc, 0x75, 0x69, 0xf0, 0xfb, 0xf6, 0xbd, 0x69, 0xff, 0xfd, 0x9b,
-    0xbf, 0x47, 0xc2, 0xf8, 0x68, 0x79, 0x78, 0xe7, 0x56, 0x9f, 0xff, 0xf3,
-    0xbf, 0x0b, 0x2d, 0xc1, 0x2c, 0xff, 0x7f, 0x7c, 0xa7, 0x70, 0xc5, 0xa7,
-    0xf6, 0xef, 0xd1, 0x9f, 0xb6, 0xeb, 0x4f, 0xea, 0x77, 0xf7, 0x1b, 0xd4,
-    0xb4, 0x32, 0x37, 0x45, 0xc8, 0x8d, 0xe7, 0x81, 0xe1, 0xbd, 0x69, 0xfd,
-    0xee, 0x09, 0x03, 0xe9, 0xd6, 0x9f, 0xd7, 0xb1, 0xc9, 0xb7, 0x02, 0xd2,
-    0x67, 0x9f, 0x3d, 0x1a, 0x43, 0x2a, 0xc0, 0xc7, 0xb1, 0x28, 0xec, 0x68,
-    0x34, 0x5a, 0x50, 0x89, 0x9f, 0xfe, 0xe8, 0xff, 0x74, 0xb7, 0xcd, 0x7e,
-    0x03, 0xe7, 0x96, 0x9b, 0xf7, 0xad, 0x3e, 0x60, 0x6a, 0xff, 0x2d, 0x3a,
-    0xbd, 0xa5, 0xa6, 0xfe, 0xf5, 0xa7, 0x17, 0x9c, 0x79, 0xb3, 0xe8, 0xdc,
-    0xfd, 0xfd, 0xbe, 0x07, 0x77, 0x56, 0x86, 0x3e, 0x61, 0x33, 0x9f, 0xff,
-    0x7e, 0xde, 0xf8, 0x5f, 0x9a, 0xf9, 0x9e, 0xbb, 0xcf, 0x2d, 0x3f, 0xf7,
-    0x18, 0xcf, 0x9e, 0x2a, 0xf3, 0x79, 0x69, 0xfd, 0xf3, 0x77, 0x8f, 0x3f,
-    0x3a, 0xd0, 0x03, 0xfc, 0x24, 0x59, 0xff, 0x75, 0xcf, 0x9a, 0x61, 0xbe,
-    0xbc, 0xb4, 0x31, 0xf1, 0x7e, 0x43, 0x3f, 0xff, 0xfd, 0xf9, 0x6b, 0xa4,
-    0xce, 0x7c, 0xfb, 0xe1, 0x7e, 0x6f, 0xec, 0xb8, 0x59, 0xa5, 0xa1, 0x69,
-    0x9c, 0x7a, 0xd0, 0xc6, 0x87, 0xa1, 0x53, 0xf5, 0x74, 0x74, 0xdb, 0xad,
-    0x3f, 0xea, 0x77, 0xac, 0x5e, 0xe6, 0x1a, 0x5a, 0x1e, 0x7d, 0x7d, 0x2c,
-    0x9f, 0xee, 0x0f, 0x5c, 0xe5, 0x67, 0x56, 0x9f, 0xff, 0xff, 0x81, 0xa2,
-    0xca, 0xdf, 0xe0, 0x79, 0xff, 0xc2, 0xcd, 0xdf, 0x9f, 0xde, 0x59, 0x5b,
-    0xad, 0x16, 0x46, 0x38, 0x9c, 0x4e, 0xaa, 0xb2, 0xa2, 0x98, 0x8c, 0x3c,
-    0x9b, 0x11, 0x4f, 0xfb, 0x0b, 0x77, 0xeb, 0xcd, 0xd7, 0x16, 0x9d, 0x82,
-    0x05, 0xa5, 0x8b, 0x4e, 0xdc, 0xb0, 0x06, 0xa6, 0xe0, 0xd4, 0x0a, 0x27,
-    0x29, 0xa2, 0x7f, 0xfc, 0x01, 0xd7, 0xce, 0x56, 0xbc, 0xce, 0x6b, 0x98,
-    0xb4, 0xe7, 0xb6, 0xeb, 0x4f, 0xe3, 0x87, 0x8d, 0x7e, 0x3a, 0xb4, 0x6e,
-    0x7a, 0x14, 0x39, 0x3f, 0xff, 0x8b, 0x2d, 0xef, 0x37, 0xb4, 0xe1, 0x63,
-    0xbf, 0x18, 0xd9, 0x5a, 0x7f, 0xd6, 0x63, 0xf3, 0x35, 0x82, 0x4b, 0x43,
-    0x22, 0x8b, 0x8c, 0xf3, 0xee, 0xb5, 0xc6, 0xea, 0xd3, 0xf5, 0x17, 0xc0,
-    0xb1, 0x2d, 0x18, 0x7e, 0xc2, 0x45, 0xf9, 0x44, 0x32, 0xff, 0xed, 0xeb,
-    0x0f, 0x17, 0x0c, 0x30, 0x4c, 0x20, 0xb4, 0x67, 0xbb, 0x91, 0x0c, 0x29,
-    0x1c, 0x84, 0x5f, 0x63, 0x32, 0x3c, 0x2f, 0x40, 0x42, 0x50, 0xa7, 0xf4,
-    0x67, 0x53, 0xfd, 0xda, 0x77, 0xe5, 0x06, 0xaf, 0x5a, 0x7f, 0x99, 0xce,
-    0x0b, 0x1e, 0x82, 0xb4, 0x18, 0x7e, 0x5f, 0x9d, 0xcf, 0x61, 0x18, 0x6e,
-    0xb4, 0xff, 0xff, 0xfb, 0x83, 0xee, 0x67, 0x5a, 0xe7, 0xc3, 0xfe, 0x6b,
-    0xe6, 0x6e, 0xfc, 0xfc, 0x81, 0xa5, 0xa5, 0xe1, 0x45, 0x8e, 0x89, 0x27,
-    0xfc, 0xd6, 0xf8, 0x55, 0xa3, 0xb1, 0x2d, 0x3f, 0xfe, 0xcc, 0xe0, 0xdb,
-    0x99, 0xf3, 0x5f, 0xf1, 0x8d, 0xd6, 0x9f, 0xfe, 0xf7, 0x30, 0x1f, 0x0e,
-    0xd9, 0xe0, 0xe1, 0x2d, 0x3f, 0xdb, 0xfc, 0x3b, 0x61, 0x7a, 0xed, 0x69,
-    0x6b, 0x11, 0x19, 0x49, 0xf2, 0x13, 0xa6, 0x92, 0x47, 0xbe, 0x87, 0x2c,
-    0xf9, 0xed, 0xbb, 0xf4, 0xb4, 0xff, 0xff, 0xff, 0xb0, 0x8c, 0xf8, 0x3c,
-    0xff, 0x67, 0x07, 0xcc, 0x72, 0xa3, 0x38, 0x3b, 0x67, 0x37, 0x03, 0x05,
-    0x29, 0xff, 0xff, 0xac, 0x2e, 0x87, 0xfe, 0xfc, 0xfd, 0xaf, 0xd5, 0xb9,
-    0xff, 0x37, 0xa7, 0x56, 0x9b, 0xfb, 0xf7, 0x4d, 0x0c, 0x4a, 0x35, 0x09,
-    0xf8, 0x65, 0x66, 0x5c, 0x8d, 0xc4, 0xa3, 0x7d, 0x9f, 0xd4, 0xfc, 0x3d,
-    0x10, 0x16, 0x9e, 0xce, 0x33, 0x8b, 0x4e, 0x3d, 0xbe, 0x70, 0xf4, 0x68,
-    0xc2, 0x7f, 0xff, 0xfb, 0x3b, 0x62, 0xcb, 0x9f, 0x34, 0x38, 0x40, 0xf8,
-    0x59, 0x70, 0xb3, 0x57, 0x16, 0x9f, 0xff, 0x09, 0x7b, 0x98, 0x6b, 0xce,
-    0x61, 0xbd, 0x10, 0x16, 0x9f, 0x33, 0xbf, 0x34, 0xe2, 0xd3, 0xff, 0x31,
-    0x5e, 0x59, 0x73, 0x5f, 0xb6, 0xeb, 0x40, 0xa6, 0x97, 0xa8, 0x41, 0x79,
-    0x63, 0xf2, 0xb9, 0xec, 0xf6, 0x5d, 0x2b, 0x4e, 0xbb, 0xce, 0x2d, 0x36,
-    0x05, 0x68, 0xbd, 0x50, 0xdb, 0xe3, 0x80, 0xd2, 0x1f, 0x89, 0x6e, 0x0f,
-    0x4f, 0x87, 0xda, 0xc0, 0x2d, 0x3f, 0x05, 0x8b, 0x94, 0xf5, 0xa7, 0x30,
-    0x59, 0x69, 0xf9, 0xf9, 0xed, 0x53, 0x9f, 0x0f, 0x14, 0xe5, 0x73, 0xff,
-    0xee, 0xff, 0xde, 0xb1, 0x61, 0x83, 0xce, 0x67, 0xd5, 0xa7, 0xbf, 0xad,
-    0xfc, 0xb4, 0x3d, 0x32, 0xc7, 0x1a, 0xfa, 0x8f, 0xc5, 0x78, 0x5a, 0x7e,
-    0xd5, 0xad, 0x44, 0x62, 0xd0, 0x6c, 0x4d, 0xbf, 0x82, 0xa6, 0xbf, 0x75,
-    0xa7, 0xdc, 0xa3, 0x76, 0x02, 0xd1, 0x47, 0x82, 0x68, 0x62, 0x7f, 0x75,
-    0xc2, 0xce, 0x57, 0x96, 0x86, 0x45, 0xee, 0x34, 0x09, 0x1c, 0xf8, 0x19,
-    0xef, 0xb7, 0xad, 0x3f, 0x9d, 0xf6, 0x73, 0xe6, 0xfa, 0x5a, 0x18, 0xf8,
-    0x68, 0xaa, 0x1e, 0x8a, 0xe2, 0x84, 0x74, 0xff, 0x7b, 0x98, 0xfa, 0x2c,
-    0xdd, 0x69, 0xff, 0xfe, 0x2a, 0x06, 0xaf, 0xc1, 0x2f, 0x16, 0x5c, 0xf9,
-    0xa7, 0x49, 0x68, 0x24, 0x4f, 0xf8, 0xde, 0x7f, 0xc3, 0x8e, 0x7c, 0xd3,
-    0x72, 0x8d, 0xd6, 0x9f, 0xed, 0xf1, 0xb7, 0x70, 0x98, 0xeb, 0x4f, 0xea,
-    0xdf, 0x5c, 0xca, 0xea, 0xd0, 0x14, 0x56, 0xf1, 0x0b, 0xc7, 0x33, 0xfd,
-    0x9d, 0xbd, 0x87, 0xb8, 0x4b, 0x48, 0xeb, 0x7c, 0x36, 0xd3, 0x8b, 0x02,
-    0xb4, 0x31, 0xbc, 0xdc, 0x8a, 0x7e, 0xdf, 0x59, 0x84, 0x62, 0xd3, 0xc7,
-    0xfa, 0xc0, 0x5a, 0x30, 0xf4, 0x04, 0xb6, 0x7f, 0x57, 0xb9, 0x4e, 0x7d,
-    0x3a, 0xd3, 0xbf, 0xdc, 0x0b, 0x43, 0x2a, 0x55, 0xc8, 0x67, 0x8c, 0x28,
-    0xba, 0xe3, 0x44, 0x04, 0x6b, 0x3f, 0xbc, 0x37, 0xe7, 0x3f, 0xf2, 0xd2,
-    0x71, 0x69, 0xfb, 0x3f, 0xce, 0x5a, 0xf5, 0xa6, 0xcd, 0xd8, 0xdf, 0xe8,
-    0x46, 0x7e, 0xe5, 0x3c, 0xfd, 0x15, 0xa7, 0xff, 0x31, 0x86, 0x57, 0xb5,
-    0xe2, 0x6d, 0xde, 0xb4, 0xc3, 0xa5, 0xa7, 0x77, 0x37, 0x5a, 0x02, 0x6c,
-    0x40, 0x2b, 0x3e, 0x1d, 0x69, 0x8e, 0xb4, 0x09, 0xe3, 0xdc, 0x21, 0x83,
-    0x13, 0xb1, 0x17, 0x30, 0x16, 0x11, 0x67, 0xf0, 0xc3, 0x9f, 0x04, 0x4a,
-    0x82, 0xb4, 0xff, 0xf9, 0xfc, 0xc7, 0x38, 0xc4, 0x61, 0x67, 0xb9, 0xfa,
-    0xd0, 0x27, 0xf7, 0xd2, 0x59, 0xff, 0xfc, 0x39, 0xbb, 0xf5, 0xee, 0x31,
-    0xd8, 0x43, 0xf1, 0x8d, 0x95, 0xa7, 0xf5, 0x17, 0xcb, 0x68, 0x01, 0x5a,
-    0x7f, 0xdf, 0xeb, 0xe1, 0xfe, 0xf2, 0xb8, 0xcb, 0x4f, 0xf3, 0x39, 0xf3,
-    0x3d, 0xfe, 0x6e, 0xb4, 0x11, 0xff, 0xfe, 0x87, 0x3f, 0xff, 0xfe, 0xfc,
-    0xbe, 0x3b, 0x5b, 0xbf, 0xb4, 0x0f, 0x9a, 0xfd, 0xb7, 0xe6, 0x09, 0x61,
-    0x8b, 0x4f, 0xff, 0xbf, 0xef, 0x73, 0xda, 0xe0, 0xe7, 0xce, 0x01, 0x96,
-    0x8c, 0x47, 0x0f, 0x21, 0x15, 0x3f, 0xfc, 0xf3, 0x5c, 0xc6, 0x27, 0x0b,
-    0x3d, 0xaa, 0x5a, 0x7f, 0xfc, 0x1c, 0x3f, 0xc3, 0x5e, 0x6d, 0x38, 0xfa,
-    0xed, 0xeb, 0x4f, 0xff, 0xde, 0x1b, 0xf0, 0x3f, 0x0f, 0x4f, 0xe8, 0xdf,
-    0x47, 0x5a, 0x7f, 0x5f, 0x47, 0x26, 0xeb, 0x8b, 0x4f, 0xf6, 0xf8, 0x60,
-    0x0f, 0x9f, 0x3b, 0x88, 0x90, 0x15, 0xd9, 0xfe, 0xc2, 0xbf, 0xe0, 0x2a,
-    0x9c, 0x5a, 0x7f, 0xbb, 0x7b, 0x5f, 0x7f, 0xfd, 0xbd, 0x69, 0xfe, 0xfc,
-    0xbe, 0x6b, 0xfb, 0xbf, 0xfa, 0xb4, 0x31, 0xff, 0xe8, 0xfa, 0x7f, 0xf5,
-    0xff, 0x35, 0xcf, 0xfe, 0x7b, 0x5a, 0x6e, 0xad, 0x3f, 0xff, 0xec, 0xdf,
-    0x43, 0x8e, 0xfc, 0xe6, 0x7b, 0x59, 0x7f, 0xcc, 0x10, 0xad, 0x18, 0x8c,
-    0x11, 0x51, 0x8b, 0xd7, 0x63, 0x02, 0xcc, 0x64, 0x2c, 0xed, 0x18, 0x1e,
-    0xe4, 0xe2, 0x9f, 0xd8, 0x75, 0x9d, 0x4f, 0x50, 0xb9, 0xf4, 0x38, 0xa7,
-    0xf7, 0x8b, 0x3d, 0xcc, 0xbd, 0x69, 0xff, 0x57, 0x79, 0x9e, 0x62, 0x10,
-    0x2d, 0x3c, 0xff, 0x0d, 0xeb, 0x4f, 0xf6, 0x3b, 0xbb, 0xf5, 0xf3, 0xc2,
-    0xb4, 0xff, 0xff, 0x9a, 0xcc, 0x7f, 0x8e, 0x70, 0x48, 0x3f, 0x3e, 0xd8,
-    0xb3, 0x98, 0xb4, 0x32, 0x67, 0x76, 0x32, 0xa3, 0xb2, 0x22, 0x34, 0x79,
-    0x3c, 0x3e, 0x16, 0x5a, 0x7f, 0xff, 0xf1, 0x09, 0x9c, 0xa7, 0x3e, 0x17,
-    0xe6, 0xbe, 0x66, 0xef, 0xcf, 0xc8, 0x1a, 0x5a, 0x7d, 0xc1, 0x62, 0xbd,
-    0x69, 0xbc, 0xc7, 0x45, 0x35, 0xc8, 0x40, 0x43, 0xd1, 0xf4, 0x30, 0xc5,
-    0x86, 0x64, 0x7e, 0xe4, 0xed, 0x68, 0xc7, 0xcb, 0x51, 0xa2, 0x4f, 0x98,
-    0xbc, 0x37, 0x16, 0x9e, 0xf6, 0xa8, 0x0b, 0x4f, 0xfd, 0xc1, 0xf8, 0x3d,
-    0xfe, 0xfa, 0xed, 0x96, 0x9e, 0x1e, 0x55, 0xeb, 0x4f, 0x5c, 0x6f, 0x32,
-    0xd3, 0xef, 0xee, 0x92, 0xaf, 0x2d, 0x3f, 0x72, 0xaf, 0xf8, 0xff, 0x2d,
-    0x3e, 0xfa, 0x4f, 0x79, 0xd6, 0x9f, 0x57, 0x4b, 0x71, 0x5a, 0x19, 0x15,
-    0x62, 0x58, 0x03, 0x0f, 0x14, 0xc0, 0x53, 0xb8, 0xc2, 0x73, 0x08, 0x6c,
-    0x8e, 0x24, 0x3e, 0x86, 0x6c, 0xfe, 0xe3, 0x09, 0x57, 0x4c, 0x5a, 0x7e,
-    0x61, 0x2a, 0xe9, 0x8b, 0x4f, 0xe0, 0x50, 0x3b, 0xd1, 0xef, 0xc3, 0xdc,
-    0xe1, 0x8c, 0xfc, 0xdd, 0xbd, 0xbb, 0x7a, 0xd3, 0xbf, 0xad, 0x2d, 0x0f,
-    0x3c, 0xaf, 0xa5, 0xd3, 0xff, 0xf0, 0xf7, 0xe6, 0x0e, 0x11, 0x9c, 0x1c,
-    0x3e, 0x59, 0x69, 0xff, 0xfe, 0x1b, 0xfa, 0xc7, 0xd7, 0xed, 0xf1, 0xba,
-    0xc1, 0xe3, 0x1d, 0x68, 0xc4, 0x60, 0xf5, 0x66, 0x7f, 0xdd, 0xcd, 0xf9,
-    0xbb, 0x1e, 0xf6, 0x5a, 0x7f, 0xff, 0xf7, 0x7a, 0x37, 0xfc, 0xe6, 0x78,
-    0x99, 0xce, 0x65, 0xed, 0xbf, 0xbf, 0xb2, 0xd3, 0xff, 0xff, 0x31, 0x9c,
-    0x6f, 0x85, 0x9f, 0x99, 0xf3, 0x77, 0xe8, 0x4b, 0xeb, 0x5e, 0xb4, 0xfb,
-    0x7d, 0x0e, 0x12, 0xd1, 0x88, 0xa0, 0xfd, 0xea, 0x05, 0x34, 0x0e, 0x46,
-    0x3b, 0x3f, 0xf3, 0xf4, 0x26, 0x71, 0x86, 0xf6, 0x31, 0x69, 0xfe, 0x2f,
-    0xdc, 0x2c, 0xe5, 0x79, 0x69, 0xfe, 0x0f, 0x19, 0xd0, 0xf2, 0x8e, 0xb4,
-    0xff, 0xff, 0x57, 0x79, 0x9e, 0x1c, 0x2b, 0xf4, 0xd8, 0x41, 0xe3, 0x2d,
-    0x3d, 0xef, 0x97, 0xf5, 0x68, 0xdd, 0x10, 0xf4, 0xc5, 0x3f, 0xff, 0xed,
-    0xf2, 0xff, 0xcd, 0x7c, 0xdd, 0xfe, 0x67, 0x7e, 0x67, 0x40, 0x06, 0x5a,
-    0x7f, 0xf3, 0xb4, 0x57, 0x9f, 0xf1, 0x08, 0x90, 0xad, 0x3f, 0x39, 0xbb,
-    0xff, 0x6f, 0x2d, 0x3f, 0xdc, 0xa3, 0x96, 0x72, 0xbc, 0xb4, 0xf6, 0x74,
-    0x0e, 0xad, 0x0c, 0x88, 0x8d, 0x18, 0x78, 0xda, 0x7e, 0xcf, 0x77, 0xb8,
-    0xf5, 0xa7, 0xe2, 0xce, 0x16, 0x59, 0x69, 0xe2, 0xcd, 0x7c, 0x70, 0xf5,
-    0xbc, 0x59, 0x3f, 0xd8, 0x7e, 0x30, 0xf7, 0xf3, 0x75, 0xa0, 0x2b, 0xad,
-    0xc6, 0x11, 0x5a, 0x38, 0x0d, 0xca, 0x45, 0x17, 0xa7, 0x1c, 0x86, 0x05,
-    0x11, 0xe9, 0xdf, 0xd0, 0xd1, 0xb9, 0x08, 0x5f, 0xa7, 0x73, 0xfe, 0x2c,
-    0xf9, 0xdc, 0xe1, 0x63, 0x8b, 0x4f, 0xff, 0xee, 0x50, 0x35, 0xf0, 0xb2,
-    0xe1, 0x66, 0xb0, 0xed, 0x65, 0xa0, 0x91, 0x3f, 0xa3, 0xe8, 0x65, 0xfd,
-    0x5c, 0x9e, 0x53, 0xa8, 0xd8, 0x27, 0xee, 0x61, 0x78, 0x1f, 0xad, 0x3e,
-    0x26, 0x3d, 0x05, 0x69, 0xfd, 0x8e, 0x73, 0x3c, 0xc1, 0x5a, 0x7f, 0x31,
-    0x7a, 0x8e, 0x3e, 0x5a, 0x71, 0x59, 0x96, 0x9f, 0xff, 0xfe, 0xe6, 0x7b,
-    0x54, 0xe7, 0xc2, 0xcd, 0xdf, 0x9f, 0xde, 0x58, 0x1e, 0x0b, 0x8b, 0x4d,
-    0xf9, 0x8b, 0x40, 0xa2, 0xcf, 0xa3, 0x5e, 0x84, 0x0c, 0xfd, 0x97, 0x96,
-    0x6f, 0xa5, 0xa7, 0xff, 0x77, 0x77, 0xeb, 0x0f, 0xbb, 0x73, 0x8c, 0xb4,
-    0xb4, 0xb4, 0x7e, 0x7b, 0x7f, 0x52, 0xe7, 0xf3, 0x1c, 0xb3, 0x95, 0xe5,
-    0xa7, 0xbe, 0x5a, 0xf7, 0x56, 0x9f, 0xff, 0xf7, 0x89, 0x81, 0xbb, 0xf5,
-    0xfb, 0x78, 0xb0, 0x23, 0x9d, 0x71, 0x68, 0x0a, 0xb0, 0xa1, 0x2d, 0x70,
-    0x97, 0x86, 0x55, 0x0e, 0x32, 0x34, 0xd4, 0x22, 0x3f, 0x25, 0xb8, 0x61,
-    0xf4, 0x9a, 0x7c, 0xf1, 0xee, 0x6e, 0xb4, 0xed, 0x73, 0x16, 0x9f, 0x66,
-    0xaf, 0xc7, 0x56, 0x8d, 0xcf, 0xa9, 0xc2, 0x7e, 0x0d, 0xcf, 0xff, 0x86,
-    0xfc, 0xb0, 0x78, 0x38, 0x67, 0xc3, 0x3f, 0x65, 0xa7, 0x8d, 0x7b, 0x38,
-    0xb4, 0xc2, 0x75, 0xa7, 0xff, 0xfd, 0xbb, 0xeb, 0x7f, 0x85, 0xf9, 0xaf,
-    0x99, 0xbb, 0xf3, 0xf2, 0x06, 0x96, 0x83, 0xa2, 0x2c, 0xd0, 0xac, 0x5e,
-    0x8d, 0x3c, 0x85, 0x74, 0xff, 0xff, 0xf9, 0xb7, 0xd7, 0xed, 0xbf, 0xce,
-    0x60, 0x7e, 0x16, 0x7e, 0x67, 0xcd, 0x00, 0x03, 0xe5, 0xa7, 0xcc, 0x5b,
-    0xd5, 0xeb, 0x4f, 0xff, 0xff, 0xfc, 0x7c, 0xb3, 0x71, 0x8f, 0xec, 0xd6,
-    0x9b, 0xbd, 0x62, 0xcb, 0xf3, 0xfd, 0x7e, 0xe1, 0x31, 0xd6, 0x9f, 0x50,
-    0x3e, 0xd5, 0xeb, 0x46, 0x23, 0x20, 0x61, 0x3f, 0x3f, 0x04, 0xb3, 0x95,
-    0xe5, 0xa7, 0xde, 0xdd, 0xe3, 0xd5, 0xa4, 0x0c, 0x3d, 0x3d, 0x15, 0xcf,
-    0xeb, 0xff, 0x6f, 0x1c, 0x7c, 0xb4, 0xff, 0x98, 0xc3, 0x5f, 0xe1, 0x39,
-    0xf4, 0xeb, 0x46, 0x1f, 0xc6, 0xe6, 0x93, 0xfe, 0xcc, 0x06, 0xbe, 0x77,
-    0x41, 0xd2, 0xd3, 0xfb, 0xb9, 0x6e, 0x0f, 0x5c, 0x5a, 0x6c, 0xf0, 0x4f,
-    0xcf, 0x10, 0x27, 0xaf, 0x12, 0xf2, 0xd0, 0xcb, 0x9f, 0x78, 0x62, 0x31,
-    0x96, 0x74, 0xa0, 0xf0, 0x8d, 0xe4, 0x3b, 0xe9, 0xe4, 0xa1, 0x3f, 0xa8,
-    0x4a, 0xfe, 0x59, 0x3a, 0xad, 0x8b, 0x4f, 0xf9, 0xcf, 0x9e, 0x2c, 0x77,
-    0x07, 0x4b, 0x45, 0xd6, 0x7b, 0x4c, 0x35, 0x38, 0x3f, 0x1c, 0x5a, 0x7f,
-    0xfb, 0x77, 0x93, 0x7c, 0x39, 0x31, 0x9e, 0x1b, 0xd6, 0x8c, 0x3f, 0x11,
-    0x1f, 0x9f, 0x9b, 0xbf, 0x0a, 0xe3, 0xab, 0x4f, 0xd7, 0xb8, 0xfb, 0xaf,
-    0xb7, 0xad, 0x3e, 0x38, 0x87, 0x02, 0xb4, 0x9c, 0x5a, 0x66, 0x3a, 0xd2,
-    0xf2, 0xd1, 0xd3, 0x4b, 0x42, 0xb0, 0x13, 0xd6, 0xe1, 0xb4, 0xf7, 0xb5,
-    0x5b, 0xad, 0x33, 0x94, 0xb4, 0xfe, 0xe0, 0xf7, 0x77, 0x93, 0x2d, 0x17,
-    0x42, 0x67, 0xcc, 0x6d, 0x8f, 0x82, 0x44, 0x72, 0x2f, 0xc5, 0xa7, 0xf3,
-    0xb8, 0xf2, 0xfe, 0xb4, 0xb4, 0xfe, 0xd0, 0xee, 0xed, 0x10, 0x16, 0x9f,
-    0xff, 0x98, 0xe5, 0x96, 0xdf, 0xc5, 0x5c, 0x3b, 0x67, 0x96, 0x9f, 0xff,
-    0x37, 0x5a, 0xd8, 0x76, 0xb3, 0xc7, 0x5f, 0x9d, 0x68, 0x64, 0xc4, 0x9c,
-    0x33, 0xe1, 0x9d, 0xda, 0xc4, 0xfd, 0xdc, 0x63, 0x18, 0x96, 0x9c, 0x54,
-    0x75, 0xa6, 0x03, 0x2d, 0x0f, 0x3d, 0xa1, 0x2b, 0x21, 0xa8, 0xba, 0x9f,
-    0x10, 0xee, 0xeb, 0x8d, 0x24, 0xdb, 0xa3, 0x34, 0xa8, 0x2b, 0xe1, 0x30,
-    0xf2, 0xb0, 0xca, 0xdc, 0xca, 0x42, 0xe1, 0x91, 0xb0, 0x5a, 0x70, 0x1f,
-    0x79, 0x55, 0x03, 0x1c, 0x0b, 0x91, 0xf0, 0xf6, 0x58, 0xd9, 0xe5, 0x07,
-    0xf2, 0x93, 0x91, 0x52, 0x82, 0x41, 0x0b, 0x82, 0xa4, 0x35, 0xea, 0x5a,
-    0x47, 0xa7, 0x7f, 0xff, 0x87, 0xf5, 0xc8, 0x4b, 0xba, 0x41, 0x77, 0x1b,
-    0x7f, 0xd8, 0xdb, 0x4d, 0x42, 0x6e, 0x7f, 0xfe, 0xfe, 0xdb, 0x6f, 0xee,
-    0xb6, 0x6f, 0x75, 0x86, 0xa8, 0xc5, 0xa3, 0x65, 0x50, 0xc3, 0x28, 0x8a,
-    0x7f, 0x6d, 0x9d, 0xb5, 0x55, 0x95, 0x14, 0xec, 0xfb, 0xb6, 0xaa, 0xb2,
-    0xa2, 0xa3, 0x9f, 0xf5, 0x3f, 0x6c, 0xed, 0xaa, 0xac, 0xa8, 0x9a, 0x23,
-    0x0f, 0xf4, 0xe6, 0x73, 0xfb, 0xed, 0x5c, 0xdb, 0xc3, 0x7a, 0xd1, 0xb1,
-    0xec, 0xb1, 0x0c, 0xfb, 0xb6, 0xaa, 0xb2, 0xa2, 0xaf, 0x9f, 0xb2, 0xe3,
-    0x17, 0x3f, 0x5a, 0x5b, 0x61, 0xf0, 0xf4, 0xce, 0x7d, 0xdb, 0x55, 0x59,
-    0x51, 0x5b, 0x4f, 0xf3, 0xf6, 0xce, 0xda, 0xaa, 0xca, 0x89, 0x06, 0x5b,
-    0x61, 0xfc, 0x51, 0x9c, 0xff, 0xdb, 0x53, 0xf6, 0xce, 0xda, 0xaa, 0xca,
-    0x89, 0x0e, 0x7f, 0xcf, 0xe3, 0x7b, 0x46, 0xce, 0xae, 0xa2, 0x5a, 0x7f,
-    0xf1, 0xb0, 0x36, 0x06, 0xcf, 0x18, 0xe5, 0x5c, 0x1e, 0xad, 0x2d, 0xd6,
-    0x98, 0x49, 0x68, 0x09, 0xa5, 0x70, 0x46, 0x7d, 0x98, 0x40, 0xd2, 0xd3,
-    0xfe, 0xef, 0xbe, 0x95, 0x5b, 0x0a, 0xcb, 0x4f, 0x5a, 0xaa, 0xca, 0x8b,
-    0x12, 0x77, 0xe4, 0xf5, 0xa3, 0x11, 0x0f, 0xd3, 0xef, 0x16, 0xcf, 0xb3,
-    0xac, 0x46, 0x2d, 0x3e, 0xfb, 0x77, 0x9d, 0x65, 0xa7, 0x69, 0x89, 0x69,
-    0x71, 0x8f, 0x14, 0x4a, 0xe7, 0xfe, 0x6c, 0xd6, 0x10, 0x44, 0x0c, 0x4b,
-    0x4e, 0x26, 0xbd, 0x69, 0x3c, 0x8f, 0x6b, 0xf3, 0xf9, 0xd7, 0x62, 0x05,
-    0xa7, 0xc3, 0x73, 0xfa, 0xd2, 0xd3, 0xfc, 0x1e, 0x61, 0xf2, 0xbb, 0x7a,
-    0xd3, 0xef, 0x7a, 0x9f, 0xa5, 0xa7, 0xfd, 0xfe, 0x6e, 0x1b, 0x9c, 0xca,
-    0x71, 0x68, 0xdc, 0xfa, 0x6e, 0x13, 0xcc, 0xcf, 0x5a, 0x19, 0x1b, 0x79,
-    0x0a, 0x1e, 0x92, 0xcf, 0xf3, 0x6b, 0xee, 0x77, 0x31, 0xc5, 0xa7, 0xf6,
-    0x75, 0xe0, 0xcc, 0x71, 0x69, 0xe7, 0xfd, 0xe3, 0x2d, 0x3b, 0xac, 0xf5,
-    0xa2, 0x8d, 0xf5, 0xc2, 0x39, 0xf9, 0x8f, 0x83, 0xd7, 0x16, 0x9f, 0x60,
-    0x78, 0xdc, 0x5a, 0x7b, 0xa2, 0xe9, 0xba, 0xd2, 0xd1, 0x1e, 0x5e, 0x89,
-    0xa1, 0x93, 0x30, 0x17, 0x0e, 0x11, 0x53, 0xbc, 0xff, 0xf3, 0xd8, 0xec,
-    0xf0, 0x93, 0x72, 0xb3, 0xab, 0x4f, 0xeb, 0x16, 0x5c, 0x2c, 0xd2, 0xd1,
-    0xb9, 0xff, 0x71, 0x32, 0x7f, 0x01, 0xb3, 0xc2, 0x4e, 0xa5, 0x3f, 0xf7,
-    0x28, 0x7c, 0xfc, 0x30, 0xb0, 0x0b, 0x4f, 0xb3, 0x9b, 0xd1, 0xba, 0xd3,
-    0xc0, 0xd3, 0x12, 0xd3, 0xfb, 0xbc, 0xa1, 0xd0, 0xdc, 0x5a, 0x18, 0xf4,
-    0xf0, 0x82, 0x05, 0x1b, 0xe4, 0x85, 0xa7, 0xd9, 0xf9, 0xd6, 0xef, 0x69,
-    0xc5, 0xa7, 0xd7, 0xf9, 0xb7, 0x7a, 0xd0, 0xc7, 0xaf, 0x45, 0xd3, 0x16,
-    0x2d, 0x3f, 0xe2, 0x61, 0x0f, 0x8a, 0xb7, 0xd2, 0xd1, 0x75, 0x32, 0x1d,
-    0x4d, 0xb1, 0x21, 0x9f, 0x82, 0x45, 0x90, 0xac, 0x30, 0xbe, 0xcd, 0x7b,
-    0xc2, 0x00, 0x4a, 0x1c, 0x1e, 0xec, 0x60, 0x87, 0x33, 0xe4, 0x6d, 0x35,
-    0x0b, 0x90, 0x11, 0xea, 0x31, 0x0f, 0x42, 0x17, 0xf2, 0x0f, 0xa2, 0x93,
-    0xff, 0x70, 0x5b, 0xdc, 0xa3, 0x30, 0x80, 0xb4, 0xff, 0xf6, 0x6e, 0xff,
-    0x7f, 0x7e, 0xdc, 0xa3, 0x8e, 0x96, 0x9f, 0xef, 0xeb, 0x02, 0x3b, 0x95,
-    0x2d, 0x3b, 0xc4, 0xcb, 0x4d, 0xcd, 0xb1, 0x1c, 0xc4, 0x85, 0xa5, 0x3f,
-    0xa6, 0xf1, 0xb2, 0xa6, 0x86, 0x94, 0x3d, 0x3f, 0x67, 0x6d, 0x55, 0x65,
-    0x45, 0x9b, 0x3e, 0x35, 0xb7, 0x1b, 0x8b, 0x46, 0xc7, 0xc5, 0x47, 0x13,
-    0x60, 0x56, 0x9f, 0xf5, 0x3f, 0x6c, 0xed, 0xaa, 0xac, 0xa8, 0xa0, 0x27,
-    0xf0, 0x9d, 0x8d, 0xf9, 0x97, 0xad, 0x2d, 0xb1, 0x12, 0x87, 0x15, 0xe2,
-    0x54, 0xfd, 0x5e, 0xd3, 0xc4, 0x0b, 0x4f, 0xcf, 0xdb, 0x1c, 0x67, 0xad,
-    0x1b, 0x1e, 0xd3, 0x16, 0x4d, 0xff, 0x16, 0x9f, 0xb4, 0xc7, 0x26, 0x71,
-    0x69, 0x71, 0x69, 0xdf, 0x49, 0xc5, 0xa6, 0xcf, 0x61, 0xae, 0x00, 0x84,
-    0x01, 0x10, 0xa4, 0xb5, 0x37, 0xcd, 0x2d, 0x3f, 0xb3, 0xbe, 0x26, 0x3e,
-    0x96, 0x95, 0xda, 0xd1, 0xc3, 0xc4, 0x01, 0x8c, 0xf5, 0xaa, 0xac, 0xa8,
-    0xb7, 0xe7, 0xef, 0xbe, 0xab, 0x57, 0x56, 0x8e, 0x9e, 0xd8, 0x0b, 0x67,
-    0xb0, 0x85, 0xc5, 0xa7, 0xde, 0x7e, 0xbe, 0xe9, 0x69, 0xda, 0xe0, 0x56,
-    0x9f, 0x7d, 0xf1, 0x30, 0x16, 0x83, 0x9e, 0x25, 0xc1, 0xc9, 0xff, 0xbd,
-    0xa1, 0xd3, 0x16, 0x7b, 0x82, 0xb4, 0xe2, 0xce, 0x2d, 0x07, 0x3d, 0xbb,
-    0x88, 0x33, 0xe0, 0xb1, 0xbf, 0xe7, 0x5a, 0x19, 0x19, 0xd8, 0xfe, 0x24,
-    0x93, 0xd4, 0x25, 0xe5, 0xa7, 0x75, 0xbc, 0xb4, 0xfc, 0xe5, 0x07, 0x82,
-    0x75, 0xa7, 0xef, 0x0e, 0x05, 0x8e, 0xb4, 0x78, 0xf6, 0x1d, 0x2d, 0x9b,
-    0x44, 0xb4, 0xfd, 0xbe, 0x9a, 0xd8, 0x75, 0xa3, 0xa8, 0xd8, 0xa7, 0x3d,
-    0x11, 0xfe, 0x2b, 0x3d, 0xc3, 0x02, 0x75, 0xa6, 0xc7, 0xad, 0x18, 0x6e,
-    0x08, 0x8e, 0x2e, 0xa5, 0xcc, 0xd6, 0x84, 0xe3, 0xc8, 0x82, 0xb9, 0x8f,
-    0xa2, 0x45, 0xd2, 0x0e, 0x46, 0x78, 0x02, 0xd2, 0x87, 0xbf, 0x9d, 0x67,
-    0xea, 0xdf, 0x63, 0xd7, 0x96, 0x8d, 0x91, 0xb4, 0x50, 0xac, 0x9f, 0xf0,
-    0xea, 0xfc, 0x77, 0x63, 0x66, 0xe8, 0xba, 0x96, 0x9f, 0xf5, 0x3f, 0x6c,
-    0xed, 0xaa, 0xac, 0xa8, 0xa5, 0x27, 0xf9, 0xfb, 0x67, 0x6d, 0x55, 0x65,
-    0x44, 0x9d, 0x2d, 0x8e, 0x88, 0xfa, 0x4a, 0x86, 0x7d, 0xf9, 0x5b, 0xe3,
-    0xf0, 0x0d, 0xe3, 0x8f, 0xe1, 0x65, 0xa3, 0x15, 0x18, 0x41, 0x9b, 0xc2,
-    0x81, 0xc2, 0x73, 0xd2, 0xcb, 0xb9, 0x08, 0xe0, 0x42, 0xd8, 0xa1, 0x21,
-    0xa9, 0xdc, 0x9f, 0x14, 0x5c, 0x86, 0xfc, 0xfb, 0xb6, 0xaa, 0xb2, 0xa2,
-    0x1f, 0x9f, 0xf5, 0x3f, 0x6c, 0xed, 0xaa, 0xac, 0xa8, 0x94, 0xe5, 0xb6,
-    0x1f, 0xe9, 0xcc, 0xe7, 0xf6, 0xd9, 0xdb, 0x55, 0x59, 0x51, 0x13, 0xcf,
-    0xce, 0x0f, 0xb5, 0xf9, 0xd6, 0x9f, 0x76, 0xd5, 0x56, 0x54, 0x46, 0x32,
-    0xd9, 0x8f, 0x8b, 0x0b, 0xe7, 0xff, 0x6c, 0x7a, 0x7e, 0xd9, 0xdb, 0x55,
-    0x59, 0x51, 0x3c, 0xcf, 0xdb, 0x01, 0x89, 0xfa, 0x5a, 0x19, 0x37, 0x4b,
-    0xca, 0x1f, 0x0a, 0x1e, 0x13, 0xf9, 0x5e, 0x7d, 0xdb, 0x55, 0x59, 0x51,
-    0x10, 0x4f, 0xfa, 0x9f, 0xb6, 0x76, 0xd5, 0x56, 0x54, 0x4a, 0x92, 0xdb,
-    0x0f, 0xf4, 0xe6, 0x73, 0xfb, 0x6c, 0xed, 0xaa, 0xac, 0xa8, 0x8a, 0x27,
-    0xf6, 0xd9, 0xdb, 0x55, 0x59, 0x51, 0x19, 0x4f, 0xfe, 0xd8, 0xf4, 0xfd,
-    0xb3, 0xb6, 0xaa, 0xb2, 0xa2, 0x65, 0x9f, 0xdb, 0x67, 0x6d, 0x55, 0x65,
-    0x45, 0x49, 0x3f, 0xb6, 0xce, 0xda, 0xaa, 0xca, 0x8a, 0xea, 0x7f, 0x6d,
-    0x9d, 0xb5, 0x55, 0x95, 0x16, 0x2c, 0xff, 0xc7, 0xa7, 0xed, 0x9d, 0xb5,
-    0x55, 0x95, 0x13, 0xd4, 0xff, 0x3b, 0xb5, 0x30, 0xdd, 0x89, 0xa5, 0xa7,
-    0xfd, 0xfe, 0xb9, 0x4f, 0xda, 0xea, 0xd7, 0x96, 0x9f, 0xf5, 0x6f, 0xb1,
-    0x67, 0xb4, 0x27, 0x5a, 0x5e, 0xea, 0x21, 0x34, 0x8d, 0x1b, 0x26, 0x74,
-    0xca, 0x03, 0x0c, 0x19, 0xf6, 0x78, 0x7f, 0xd2, 0xd3, 0x1b, 0x26, 0xd8,
-    0xb4, 0x1b, 0x61, 0xe4, 0x9b, 0x12, 0x79, 0xfe, 0xba, 0xfe, 0x96, 0x77,
-    0xad, 0x65, 0xa7, 0xba, 0x7f, 0x6e, 0xb4, 0xeb, 0x67, 0x12, 0x9c, 0x76,
-    0xd2, 0xd3, 0xff, 0xf7, 0x0a, 0x8c, 0x1e, 0xb3, 0xdf, 0x9a, 0x00, 0x19,
-    0x69, 0xff, 0xfb, 0xa2, 0x6a, 0x8f, 0xb3, 0x77, 0xa2, 0x6a, 0xdf, 0xde,
-    0xb4, 0xf0, 0xf3, 0xe9, 0xd6, 0x9f, 0xfc, 0x26, 0x7c, 0xc2, 0xad, 0xf4,
-    0x61, 0x94, 0xb4, 0x58, 0xfc, 0x08, 0x8e, 0x7f, 0xf5, 0x68, 0xb0, 0x1b,
-    0x70, 0x6d, 0x5d, 0x5a, 0x7e, 0x0e, 0x19, 0xec, 0xb2, 0xd3, 0xdc, 0x63,
-    0xd9, 0x68, 0xa3, 0xce, 0xf1, 0x6c, 0xff, 0xe2, 0xf8, 0xcc, 0x4c, 0x7f,
-    0x9f, 0x39, 0x76, 0xb4, 0xd5, 0xba, 0xd3, 0xfa, 0xb5, 0x5c, 0xfc, 0xaf,
-    0x5a, 0x08, 0xf2, 0x7f, 0x16, 0x8b, 0xd5, 0x6c, 0x08, 0xdf, 0x56, 0x4f,
-    0x0d, 0x1e, 0x10, 0x94, 0x25, 0xbc, 0x42, 0x6a, 0x13, 0x33, 0x8a, 0xbc,
-    0xb4, 0xe2, 0x1d, 0x2d, 0x27, 0x4d, 0xa3, 0x68, 0xc3, 0x53, 0xdd, 0xb9,
-    0x47, 0x5a, 0x7c, 0x72, 0xaf, 0x69, 0x69, 0xf3, 0xf8, 0xd9, 0xd5, 0xa3,
-    0x73, 0xcc, 0xe9, 0x34, 0x62, 0x2f, 0x84, 0xb3, 0xf6, 0xf9, 0xfe, 0xe5,
-    0x79, 0x9c, 0xd0, 0x9d, 0x69, 0xfc, 0xcf, 0x2c, 0xdf, 0xd8, 0xb4, 0xee,
-    0x7e, 0x75, 0xa0, 0x51, 0x0d, 0xd3, 0x8f, 0xcc, 0x67, 0xc4, 0x60, 0xe6,
-    0x96, 0x9f, 0x3b, 0x5e, 0xab, 0x2d, 0x3f, 0xf6, 0x3b, 0x40, 0xcb, 0x72,
-    0x81, 0xa5, 0xa7, 0xfd, 0xaa, 0xdd, 0x8a, 0x83, 0x86, 0x2d, 0x02, 0x8c,
-    0xde, 0x13, 0x11, 0x3f, 0x90, 0xe7, 0x1d, 0xb8, 0xb4, 0xf1, 0x07, 0xe1,
-    0x8b, 0x4f, 0xd9, 0xa7, 0x68, 0xaf, 0x5a, 0x30, 0xfb, 0x28, 0x6c, 0x89,
-    0x27, 0xdf, 0x99, 0xa0, 0xb2, 0xd3, 0xf3, 0x6e, 0xfd, 0x09, 0x2d, 0x18,
-    0x99, 0x40, 0xc2, 0x9f, 0x85, 0x84, 0x53, 0x3f, 0xff, 0xfb, 0x8c, 0x3d,
-    0xeb, 0x7d, 0xf0, 0x97, 0xef, 0xcd, 0x07, 0xfa, 0xeb, 0xd6, 0x9f, 0x5e,
-    0x1e, 0x8b, 0xab, 0x4f, 0xc1, 0xae, 0x82, 0xef, 0x16, 0x9e, 0x7f, 0x3e,
-    0xdc, 0x5a, 0x7f, 0xc4, 0x2f, 0xf7, 0x33, 0xa3, 0xa5, 0xa7, 0xfd, 0x58,
-    0x06, 0x2a, 0x0e, 0x18, 0xb4, 0x3c, 0xfd, 0xc0, 0x79, 0x3f, 0xab, 0x7d,
-    0x7b, 0xd8, 0x6e, 0xb4, 0xff, 0xe6, 0xcd, 0xfd, 0xc6, 0xf1, 0x30, 0x34,
-    0xb4, 0xed, 0x70, 0xeb, 0x47, 0x8f, 0x93, 0xf4, 0x89, 0xfb, 0xfd, 0x7b,
-    0x59, 0xe5, 0xa7, 0x3a, 0xeb, 0xa9, 0x4f, 0xfe, 0xf0, 0xfb, 0x5c, 0x1b,
-    0xbf, 0xbd, 0x67, 0xa5, 0xb1, 0x7f, 0x02, 0x8a, 0xbf, 0xd3, 0x67, 0xff,
-    0xf8, 0x7c, 0xf6, 0x2c, 0xf7, 0x07, 0x3c, 0xc7, 0x1e, 0xbd, 0x68, 0x7a,
-    0xb7, 0xdc, 0x79, 0x12, 0x97, 0x0b, 0xfb, 0x09, 0xd3, 0x91, 0x14, 0x26,
-    0xbd, 0x0c, 0xeb, 0x84, 0x73, 0xfd, 0xbb, 0xf5, 0xac, 0x0d, 0x79, 0x69,
-    0x62, 0xd0, 0xc7, 0x90, 0x61, 0xcc, 0xdb, 0xd2, 0xd3, 0xff, 0xf5, 0x78,
-    0x79, 0x47, 0xf9, 0x9a, 0x6c, 0xee, 0x12, 0xd2, 0x1e, 0x9f, 0x71, 0x0b,
-    0x4f, 0x79, 0xb7, 0x75, 0x68, 0xe1, 0xe4, 0xba, 0x4d, 0x33, 0xbc, 0x5a,
-    0x7f, 0xf3, 0x15, 0xbe, 0xf6, 0x80, 0x3e, 0xe3, 0x2d, 0x3f, 0x85, 0xdd,
-    0x66, 0x15, 0xeb, 0x4f, 0x36, 0x9a, 0xe2, 0xd3, 0xff, 0x31, 0x57, 0x9e,
-    0xc6, 0x53, 0xbe, 0x5a, 0x38, 0x7c, 0xbf, 0x91, 0x45, 0x93, 0x1a, 0x00,
-    0xbe, 0x92, 0x7d, 0x09, 0x79, 0xe3, 0xfd, 0x62, 0x5a, 0x7e, 0x74, 0xca,
-    0xa2, 0x02, 0xd3, 0x7e, 0x75, 0xa0, 0x4f, 0x13, 0x85, 0xb3, 0xf9, 0xab,
-    0xbc, 0x76, 0x82, 0x94, 0xce, 0xba, 0x94, 0x04, 0xf2, 0x9d, 0x32, 0x9d,
-    0xe1, 0x37, 0x4b, 0x63, 0x47, 0x3f, 0x6f, 0x61, 0xd7, 0x05, 0x69, 0xef,
-    0xdf, 0xff, 0x96, 0x81, 0x4d, 0xd1, 0xc6, 0x6d, 0x42, 0x3b, 0xc5, 0xf7,
-    0x65, 0xb3, 0x3b, 0xa5, 0xa5, 0x8b, 0x4b, 0x7c, 0x34, 0xde, 0x17, 0x9f,
-    0xfb, 0x5a, 0x09, 0x30, 0x78, 0xde, 0xd2, 0xd0, 0xc7, 0xd5, 0xf9, 0x3c,
-    0xff, 0xbc, 0x3d, 0xa0, 0x1a, 0xf6, 0x71, 0x69, 0xfe, 0x17, 0x4b, 0x3c,
-    0x3f, 0x81, 0x69, 0xfd, 0x5d, 0xf6, 0x88, 0x4c, 0x5a, 0x7f, 0xf6, 0xb0,
-    0xcc, 0xff, 0xb4, 0x16, 0xe3, 0x2d, 0x0f, 0x4c, 0x50, 0x48, 0x8d, 0xcf,
-    0xe8, 0xe3, 0x46, 0x53, 0xb0, 0x7a, 0xb4, 0xfe, 0x78, 0x9f, 0x9b, 0xd1,
-    0xba, 0xd3, 0xd5, 0xd6, 0x7a, 0xd1, 0x79, 0xf8, 0x6e, 0x34, 0x73, 0x69,
-    0xfe, 0x63, 0xe7, 0xce, 0x1b, 0x89, 0xd6, 0x9f, 0xf3, 0x6f, 0xc6, 0x3d,
-    0xb8, 0x2e, 0x2d, 0x18, 0x8a, 0xc1, 0x31, 0xe9, 0xe4, 0xfd, 0xe6, 0xe8,
-    0x70, 0x96, 0x9f, 0xc1, 0xe3, 0x13, 0xb5, 0xba, 0xd3, 0xff, 0x08, 0x78,
-    0xd6, 0x60, 0x51, 0x01, 0x69, 0xff, 0xfe, 0x3d, 0x16, 0xef, 0xd9, 0xdc,
-    0x1b, 0x98, 0x58, 0x1a, 0x7a, 0xe2, 0xf5, 0x9e, 0xf1, 0x7f, 0x7a, 0xd0,
-    0x28, 0x97, 0x27, 0x48, 0x64, 0xd5, 0xe8, 0xaf, 0x46, 0x7f, 0xc3, 0x62,
-    0x79, 0xf7, 0x59, 0xb3, 0x75, 0x2d, 0x3e, 0x08, 0x95, 0x05, 0x68, 0xdc,
-    0xf5, 0x84, 0xc6, 0x7f, 0xfb, 0x3d, 0xac, 0x73, 0x8d, 0x73, 0x39, 0xc6,
-    0x5a, 0x7f, 0xff, 0xfc, 0x39, 0xbe, 0x87, 0x1d, 0xf9, 0x9b, 0xbf, 0x43,
-    0xed, 0x0e, 0xe1, 0x0f, 0xf7, 0xad, 0x3f, 0xfe, 0x12, 0x0f, 0xcf, 0xbe,
-    0x1d, 0x50, 0x97, 0xef, 0x5a, 0x09, 0x33, 0x0f, 0x28, 0x5c, 0x84, 0x4c,
-    0xfe, 0xbe, 0xbc, 0x0f, 0xa4, 0xf5, 0xa7, 0x19, 0x81, 0x5a, 0x7e, 0xe5,
-    0x76, 0xcd, 0xe5, 0xa6, 0xa0, 0xad, 0x3f, 0x76, 0xb5, 0xca, 0x7a, 0xd2,
-    0xdd, 0x69, 0x85, 0xd5, 0xa6, 0xfa, 0x05, 0xa1, 0xc3, 0x5c, 0x01, 0x69,
-    0xcf, 0xa0, 0xad, 0x33, 0xae, 0xad, 0x0f, 0x46, 0xae, 0x0a, 0xd8, 0xb0,
-    0x4f, 0xf4, 0x44, 0xe8, 0xdc, 0xef, 0x7d, 0x02, 0x5b, 0x1e, 0xb4, 0xff,
-    0xff, 0xef, 0x30, 0x79, 0xfd, 0x18, 0x7a, 0x0e, 0x61, 0x19, 0xad, 0x61,
-    0x01, 0x68, 0x7a, 0xa1, 0xa0, 0x8e, 0x6f, 0x1a, 0xb8, 0x98, 0x4f, 0xf6,
-    0x7b, 0x8d, 0xdf, 0x65, 0x96, 0x9c, 0xdd, 0x71, 0x68, 0x65, 0xc7, 0x0c,
-    0x8d, 0x48, 0x4d, 0xea, 0x52, 0x79, 0x22, 0xdd, 0x9b, 0xce, 0xd5, 0x38,
-    0xb4, 0xf6, 0x7a, 0x8d, 0x2d, 0x1b, 0x9b, 0xe2, 0x1c, 0x9f, 0xf5, 0x10,
-    0x70, 0xbf, 0x7e, 0x69, 0x69, 0xe6, 0xcf, 0xa1, 0x5a, 0x7f, 0x18, 0x3e,
-    0xae, 0x3a, 0x6e, 0xb4, 0xff, 0x77, 0x1c, 0xe6, 0x6a, 0x89, 0x69, 0xff,
-    0xfc, 0x25, 0x9b, 0xf8, 0xca, 0xf7, 0x1b, 0x99, 0x72, 0x9e, 0xb4, 0xb2,
-    0xc8, 0xf1, 0x12, 0x2e, 0x9b, 0xdc, 0x37, 0x9c, 0xc5, 0xe5, 0xa7, 0xab,
-    0xac, 0xf5, 0xa7, 0xff, 0xe1, 0x2a, 0x12, 0x07, 0x5b, 0x94, 0x3e, 0x6e,
-    0x2d, 0x04, 0x7e, 0xbe, 0x20, 0x9f, 0x0f, 0xb5, 0xfd, 0xeb, 0x4f, 0xff,
-    0x31, 0x08, 0x3d, 0xbd, 0x87, 0xbf, 0x58, 0x2b, 0x40, 0xa2, 0x68, 0xe4,
-    0x3e, 0x29, 0x9f, 0x77, 0xfb, 0x71, 0x96, 0x9f, 0xba, 0xe3, 0xc7, 0xda,
-    0x5a, 0x44, 0xc7, 0xad, 0x85, 0x13, 0xe1, 0x33, 0x94, 0xf5, 0xa7, 0xe1,
-    0x63, 0xdf, 0x8e, 0xad, 0x33, 0xae, 0xad, 0x16, 0x3e, 0xce, 0x93, 0xba,
-    0x5b, 0x3f, 0xd8, 0xe5, 0x39, 0x5b, 0xbf, 0x49, 0x6c, 0x6c, 0x27, 0xf6,
-    0x5f, 0x85, 0x7e, 0x3a, 0xb4, 0xfe, 0xfc, 0xa8, 0xc6, 0x3b, 0x2d, 0x38,
-    0xdc, 0x6e, 0x2d, 0x38, 0x2c, 0x75, 0xa7, 0xf6, 0x03, 0x1c, 0x6d, 0xf4,
-    0xb4, 0x31, 0xe7, 0x60, 0xdc, 0xfd, 0xca, 0x7b, 0x69, 0xeb, 0x4f, 0xf6,
-    0x70, 0x77, 0xd7, 0x3f, 0xd2, 0xd3, 0x61, 0x58, 0xf9, 0x80, 0x59, 0x3f,
-    0x15, 0x00, 0x38, 0x4b, 0x4f, 0xc7, 0x1b, 0xbc, 0xe9, 0x8b, 0x4e, 0x75,
-    0xd7, 0x52, 0x9f, 0xf9, 0xba, 0x5f, 0xd7, 0xdc, 0x71, 0x8e, 0xb6, 0xc5,
-    0xfc, 0x32, 0xe8, 0x6e, 0x46, 0x52, 0x6f, 0x08, 0x57, 0x21, 0x83, 0xd4,
-    0xb3, 0x99, 0xd1, 0x91, 0x37, 0x6a, 0x10, 0xde, 0x2c, 0xfc, 0xa9, 0xd4,
-    0xf9, 0xfd, 0x6e, 0x09, 0xa3, 0x5f, 0x98, 0xb4, 0xae, 0x95, 0xa4, 0x2b,
-    0x4f, 0xf7, 0x9b, 0xba, 0xe3, 0x17, 0x96, 0x95, 0xd2, 0xb4, 0xff, 0x79,
-    0xbb, 0xae, 0x31, 0x79, 0x69, 0xb4, 0xcb, 0x4e, 0x38, 0x59, 0x69, 0xfc,
-    0x5e, 0xa7, 0x34, 0xde, 0x5a, 0x04, 0xf3, 0x68, 0x6e, 0x78, 0x6b, 0x2c,
-    0xb4, 0xff, 0xb2, 0xe1, 0x66, 0x9c, 0x26, 0x0a, 0xd3, 0xd6, 0x0b, 0x5e,
-    0xb4, 0xc0, 0x65, 0xa7, 0x68, 0x7a, 0xb4, 0x61, 0xe9, 0x00, 0x8b, 0xc2,
-    0xb3, 0xf9, 0xf8, 0x42, 0x1c, 0x25, 0xa7, 0x7b, 0x5b, 0x32, 0x7b, 0x58,
-    0x2a, 0xe1, 0xbf, 0x18, 0x80, 0x40, 0x43, 0xfa, 0x84, 0x87, 0x8b, 0xa6,
-    0xd3, 0x2d, 0x38, 0xe1, 0x65, 0xa7, 0xf1, 0x7a, 0x9c, 0xd3, 0x79, 0x68,
-    0x13, 0xcd, 0xa1, 0xb9, 0xe1, 0xac, 0xb2, 0xd3, 0xfe, 0xcb, 0x85, 0x9a,
-    0x70, 0x98, 0x2b, 0x4f, 0x58, 0x2d, 0x7a, 0xd3, 0xf3, 0x80, 0x13, 0x7a,
-    0x71, 0x69, 0x80, 0xcb, 0x4e, 0xd0, 0xf5, 0x68, 0xc4, 0x41, 0xd8, 0x88,
-    0x06, 0x3e, 0x15, 0x9f, 0xcf, 0xc2, 0x10, 0xe1, 0x2d, 0x3f, 0x15, 0x07,
-    0x0c, 0xd9, 0x97, 0x22, 0x82, 0x2b, 0x81, 0xf6, 0x94, 0x22, 0xe4, 0x22,
-    0x38, 0xc4, 0x02, 0x02, 0x1f, 0xd4, 0x30, 0x7c, 0x79, 0x3f, 0xfe, 0xa0,
-    0xe6, 0x11, 0x9f, 0x49, 0x8a, 0xf1, 0xea, 0xd3, 0xab, 0xb7, 0xae, 0x41,
-    0x29, 0xe7, 0xe6, 0xef, 0x5c, 0x82, 0x53, 0xb4, 0x21, 0x5c, 0x82, 0x53,
-    0x3a, 0xea, 0xe4, 0x12, 0x8b, 0x22, 0x95, 0xc2, 0x9f, 0x17, 0xba, 0x51,
-    0x35, 0x79, 0x32, 0x09, 0x36, 0x37, 0xf3, 0xf6, 0x73, 0x30, 0x8c, 0x5a,
-    0x75, 0x10, 0x3e, 0x2f, 0x8d, 0x34, 0xe6, 0x19, 0xe1, 0x80, 0x51, 0x9c,
-    0x78, 0xd2, 0x7a, 0xef, 0x2b, 0x8b, 0x4b, 0x0d, 0xd1, 0x26, 0x07, 0x09,
-    0x3d, 0x69, 0xfc, 0xe3, 0xff, 0xbf, 0xc3, 0x7a, 0x53, 0xf8, 0x5f, 0xfd,
-    0x6b, 0x82, 0xb4, 0xfd, 0x97, 0x28, 0xf9, 0xc5, 0xa4, 0xf4, 0xa7, 0x57,
-    0x6f, 0x4a, 0x12, 0x86, 0x36, 0xd6, 0x10, 0x38, 0xe4, 0xe6, 0x05, 0x92,
-    0xd8, 0xd6, 0xc1, 0xd1, 0x78, 0x50, 0x90, 0x86, 0x4c, 0x57, 0x21, 0xdd,
-    0x3d, 0xfd, 0x75, 0xeb, 0x48, 0xeb, 0x4d, 0x8f, 0x09, 0xb2, 0x70, 0x8a,
-    0x7c, 0xee, 0x38, 0x27, 0x5a, 0x7e, 0xb3, 0x38, 0xf6, 0x02, 0x52, 0x15,
-    0xa7, 0xfa, 0xff, 0xde, 0x1e, 0x7f, 0x44, 0xb4, 0xfc, 0x2c, 0x7b, 0xf1,
-    0xd5, 0xa7, 0xd9, 0x79, 0xf0, 0xeb, 0x4e, 0xd0, 0xf5, 0x68, 0x23, 0xc2,
-    0xf1, 0x3c, 0xfc, 0x54, 0x00, 0x7f, 0xa5, 0xa7, 0xe1, 0x33, 0xeb, 0x1f,
-    0x60, 0xa6, 0x0f, 0x81, 0xfd, 0x3b, 0xd3, 0x7f, 0x88, 0x63, 0x13, 0xcc,
-    0x12, 0x82, 0x8c, 0xd2, 0x78, 0xb2, 0xff, 0xd6, 0x87, 0xae, 0x17, 0x84,
-    0xaf, 0x04, 0x39, 0x1a, 0x61, 0x2c, 0xea, 0x3f, 0x9f, 0x1a, 0x4f, 0xff,
-    0xaf, 0xef, 0x70, 0x34, 0x7e, 0x57, 0x89, 0x9c, 0x5a, 0x7f, 0xff, 0xf7,
-    0xfd, 0xfd, 0xc2, 0xa0, 0x6b, 0x58, 0x66, 0x7f, 0xda, 0x0b, 0x71, 0x96,
-    0x9c, 0xeb, 0xae, 0xa5, 0x33, 0xd9, 0x2d, 0x8b, 0xf8, 0x64, 0xc4, 0xef,
-    0x55, 0xec, 0x26, 0x67, 0xeb, 0xdc, 0x7d, 0xd7, 0xdb, 0xd6, 0x9e, 0xe5,
-    0x6e, 0xea, 0xd3, 0xeb, 0xfa, 0x2c, 0x75, 0xa7, 0xff, 0x9b, 0xef, 0x89,
-    0x81, 0x5e, 0x07, 0xd2, 0x7a, 0xd1, 0x74, 0x23, 0x44, 0x4d, 0xa8, 0x8f,
-    0xc4, 0xf3, 0xbe, 0x85, 0xc5, 0xa7, 0x3c, 0x49, 0x69, 0xeb, 0xfe, 0x9a,
-    0x75, 0x69, 0xfb, 0xcc, 0xe1, 0x7f, 0xa5, 0xa2, 0xf4, 0x47, 0xbc, 0x7e,
-    0x86, 0xbc, 0x51, 0x35, 0x69, 0x69, 0xbf, 0xba, 0x56, 0x82, 0x36, 0x3f,
-    0x8a, 0xcd, 0x5b, 0x5d, 0x4e, 0xc7, 0x92, 0xeb, 0x2f, 0x36, 0xe7, 0xc6,
-    0xc0, 0x8d, 0xa5, 0x79, 0xdf, 0x1b, 0xab, 0xe1, 0x6a, 0x19, 0x44, 0xb9,
-    0x2e, 0xf4, 0xc8, 0x6b, 0xda, 0x1b, 0x3b, 0xc6, 0x7a, 0x31, 0xdb, 0xb9,
-    0x1f, 0xbf, 0x63, 0x68, 0x3c, 0x70, 0xbc, 0x9d, 0x08, 0xa8, 0x51, 0x80,
-    0x84, 0xa3, 0x2d, 0xd4, 0xea, 0x87, 0xa9, 0x93, 0x7f, 0xc7, 0x09, 0x77,
-    0x18, 0x3f, 0xd8, 0x67, 0x9a, 0x6e, 0x9f, 0xfd, 0xb1, 0xe9, 0xfb, 0x67,
-    0x6d, 0x55, 0x65, 0x45, 0x15, 0x3f, 0xb6, 0xce, 0xda, 0xaa, 0xca, 0x8b,
-    0xa2, 0x7f, 0xed, 0xa9, 0xfb, 0x67, 0x6d, 0x55, 0x65, 0x44, 0x97, 0x3e,
-    0xed, 0xaa, 0xac, 0xa8, 0xbc, 0xa6, 0xab, 0x8b, 0x4b, 0x6c, 0x3c, 0xab,
-    0xb3, 0x38, 0x67, 0x71, 0x73, 0x79, 0x43, 0xcf, 0xf0, 0xfe, 0xca, 0xee,
-    0x1f, 0x9c, 0xff, 0x91, 0xbc, 0x95, 0xb2, 0x62, 0xd4, 0xa0, 0x7f, 0x2b,
-    0xfe, 0x7f, 0x72, 0x13, 0x73, 0xff, 0xb6, 0x3d, 0x3f, 0x6c, 0xed, 0xaa,
-    0xac, 0xa8, 0x96, 0x66, 0xff, 0x8b, 0x4f, 0xc1, 0xf7, 0xf4, 0xfd, 0x2d,
-    0x3f, 0xee, 0x37, 0x04, 0xcf, 0x6a, 0x80, 0xb4, 0xf5, 0xaa, 0xac, 0xa8,
-    0x8c, 0xe7, 0xe1, 0x63, 0xdf, 0x8e, 0xad, 0x31, 0x3d, 0x69, 0x1d, 0x69,
-    0xf0, 0xf7, 0x95, 0xb7, 0x4f, 0x48, 0xe5, 0xbf, 0x45, 0x67, 0xea, 0x78,
-    0xf6, 0xba, 0xb4, 0xff, 0xda, 0x1f, 0xf5, 0x85, 0xfb, 0xf3, 0x4b, 0x4e,
-    0xd3, 0x6e, 0xb4, 0x3d, 0x39, 0x6e, 0x9f, 0x1d, 0xfc, 0x93, 0xb4, 0x57,
-    0xe4, 0x49, 0xfe, 0x7e, 0xb1, 0xbe, 0x36, 0x8e, 0xb4, 0xff, 0xde, 0x1e,
-    0xd0, 0x3e, 0x6e, 0xf6, 0x3a, 0xd3, 0xe2, 0x67, 0xea, 0x96, 0x81, 0x3e,
-    0xbb, 0x88, 0xd3, 0xe3, 0x3d, 0xe6, 0x3a, 0xd3, 0x7d, 0x7a, 0xd0, 0x27,
-    0x81, 0x45, 0x13, 0xff, 0xdf, 0xfb, 0x5b, 0xbd, 0x88, 0x1a, 0xf9, 0xf9,
-    0x2d, 0x39, 0xbc, 0xcb, 0x48, 0x42, 0x7d, 0xd7, 0x15, 0x26, 0xe3, 0x8b,
-    0x4f, 0xed, 0xf4, 0x59, 0xd0, 0xb2, 0xd0, 0x27, 0x93, 0x42, 0xf3, 0xde,
-    0xe7, 0xf7, 0x6b, 0x4f, 0xf7, 0x85, 0xdd, 0x37, 0x28, 0xdd, 0x69, 0x60,
-    0x9f, 0x09, 0xc9, 0xa7, 0xfd, 0xc6, 0x1e, 0x0b, 0x13, 0x9f, 0xad, 0x30,
-    0xba, 0xb4, 0xc6, 0xb1, 0x68, 0xd1, 0xad, 0xf0, 0xb4, 0xfe, 0xcd, 0x37,
-    0xb5, 0xc1, 0x5a, 0x7f, 0x89, 0x8b, 0xc3, 0x79, 0x32, 0xd2, 0xda, 0xea,
-    0x5d, 0xd1, 0xbc, 0x5f, 0x23, 0xc4, 0xdd, 0x5d, 0xc8, 0x52, 0x71, 0x8e,
-    0xa1, 0x1c, 0x07, 0x22, 0x84, 0x0e, 0x89, 0xae, 0x35, 0x5d, 0x90, 0xfd,
-    0x31, 0x9f, 0xfd, 0xb1, 0xe9, 0xfb, 0x67, 0x6d, 0x55, 0x65, 0x44, 0xd3,
-    0x3f, 0xfb, 0x63, 0xd3, 0xf6, 0xce, 0xda, 0xaa, 0xca, 0x89, 0xc6, 0x7f,
-    0xf6, 0xc7, 0xa7, 0xed, 0x9d, 0xb5, 0x55, 0x95, 0x14, 0x0c, 0xfb, 0xb6,
-    0xaa, 0xb2, 0xa2, 0xe0, 0x9f, 0x8b, 0x3d, 0x61, 0xd2, 0xd3, 0x30, 0xad,
-    0x3f, 0x89, 0xec, 0x21, 0xc3, 0xad, 0x2d, 0xb1, 0x14, 0x47, 0x33, 0xe1,
-    0x5f, 0xe2, 0x93, 0xf6, 0x38, 0xf6, 0x27, 0xad, 0x3c, 0xc0, 0xc7, 0x56,
-    0x98, 0x76, 0x23, 0xcd, 0xfa, 0x59, 0x3f, 0xcf, 0xdb, 0x3b, 0x6a, 0xab,
-    0x2a, 0x24, 0x99, 0x6d, 0xc3, 0xf4, 0xa2, 0xf9, 0x9d, 0x02, 0xd3, 0xfa,
-    0xbc, 0x59, 0x7d, 0x12, 0xd3, 0x56, 0xc1, 0x3c, 0x73, 0x05, 0xe2, 0xf6,
-    0x52, 0x7b, 0xe7, 0x8a, 0x2d, 0x0d, 0xd7, 0x15, 0xc0, 0xaf, 0xa8, 0x7c,
-    0xfa, 0x30, 0x5b, 0x8d, 0xf3, 0xfe, 0x32, 0xb6, 0xce, 0xda, 0xaa, 0xca,
-    0x8b, 0x52, 0x7f, 0xd4, 0xfd, 0xb3, 0xb6, 0xaa, 0xb2, 0xa2, 0x55, 0x85,
-    0xa5, 0xb1, 0x88, 0x9f, 0x3a, 0x59, 0xa4, 0xa9, 0xfd, 0xb6, 0x76, 0xd5,
-    0x56, 0x54, 0x45, 0x33, 0xfb, 0x6c, 0xed, 0xaa, 0xac, 0xa8, 0x8d, 0x26,
-    0xff, 0x8b, 0x4f, 0xff, 0xf8, 0xde, 0xbf, 0xd7, 0x30, 0x3f, 0x7e, 0xe8,
-    0x7e, 0xf8, 0x74, 0xe7, 0xd5, 0xa7, 0xad, 0x55, 0x65, 0x45, 0x3f, 0x37,
-    0x99, 0x68, 0xe9, 0xe1, 0x78, 0xb6, 0x7f, 0xde, 0x71, 0xbd, 0xca, 0x73,
-    0xe6, 0x2d, 0x3f, 0xf8, 0x4e, 0x5f, 0xf0, 0x7b, 0x9a, 0x71, 0x96, 0x9f,
-    0xfb, 0xff, 0x77, 0xf7, 0x35, 0x6a, 0x73, 0x4b, 0x4f, 0xfd, 0x8e, 0x7e,
-    0x57, 0xea, 0xd4, 0xe6, 0x96, 0x96, 0xd7, 0x52, 0xa0, 0xe6, 0x17, 0xc8,
-    0x5d, 0x89, 0x15, 0x20, 0x92, 0x4f, 0x92, 0x67, 0xff, 0x6c, 0x7a, 0x7e,
-    0xd9, 0xdb, 0x55, 0x59, 0x51, 0x35, 0x4f, 0xed, 0xb3, 0xb6, 0xaa, 0xb2,
-    0xa2, 0xbb, 0x9e, 0xb5, 0x55, 0x95, 0x15, 0xf4, 0xe7, 0x5d, 0x75, 0x29,
-    0x12, 0x5b, 0x17, 0xf1, 0xd3, 0xeb, 0x3a, 0x64, 0xe7, 0xb6, 0xeb, 0x4e,
-    0x73, 0x38, 0xb4, 0xff, 0xb3, 0x8e, 0xd7, 0xb4, 0xd9, 0x7a, 0xd2, 0xf2,
-    0xd3, 0xfc, 0x3d, 0xcb, 0xc5, 0xf8, 0x15, 0xa3, 0xa7, 0x8f, 0x42, 0x12,
-    0xea, 0xd0, 0xb4, 0xb8, 0x25, 0xd7, 0x44, 0x25, 0xb6, 0x26, 0x7e, 0xe1,
-    0x15, 0x0e, 0x10, 0xe6, 0xa1, 0x0b, 0x76, 0x77, 0x3f, 0xfb, 0x63, 0xd3,
-    0xf6, 0xce, 0xda, 0xaa, 0xca, 0x89, 0xee, 0x7d, 0xc6, 0x35, 0x5b, 0xad,
-    0x3e, 0xed, 0xaa, 0xac, 0xa8, 0xb8, 0x65, 0xb3, 0x1e, 0xe6, 0x14, 0xcf,
-    0xfd, 0xb5, 0x3f, 0x6c, 0xed, 0xaa, 0xac, 0xa8, 0x93, 0xe1, 0x97, 0xc2,
-    0x2f, 0x3a, 0x79, 0xf9, 0x92, 0x93, 0x6c, 0xe4, 0xe2, 0xbf, 0x63, 0xe9,
-    0xe3, 0x2e, 0xa1, 0x67, 0x70, 0x9e, 0x7f, 0x6d, 0x9d, 0xb5, 0x55, 0x95,
-    0x11, 0x54, 0xfb, 0xb6, 0xaa, 0xb2, 0xa2, 0x99, 0x9f, 0x87, 0x99, 0x5b,
-    0x81, 0x69, 0x6d, 0x87, 0xbf, 0x76, 0x67, 0x3f, 0xfb, 0x63, 0xd3, 0xf6,
-    0xce, 0xda, 0xaa, 0xca, 0x89, 0x9e, 0x7f, 0xf6, 0xc7, 0xa7, 0xed, 0x9d,
-    0xb5, 0x55, 0x95, 0x14, 0x6c, 0x5e, 0x9b, 0xb8, 0x61, 0x3c, 0x61, 0x5f,
-    0x95, 0xe7, 0xfd, 0x4f, 0xdb, 0x3b, 0x6a, 0xab, 0x2a, 0x23, 0xa9, 0xff,
-    0xbb, 0x7e, 0xda, 0x2c, 0xf6, 0x98, 0xeb, 0x46, 0xc8, 0x8f, 0x64, 0xa9,
-    0xbf, 0xe2, 0xd3, 0xd6, 0xb7, 0xf6, 0x5a, 0x7d, 0x84, 0x1c, 0xbd, 0x69,
-    0xfc, 0xcd, 0x6c, 0xef, 0x71, 0x68, 0x13, 0xd6, 0x22, 0x69, 0xff, 0x16,
-    0x19, 0x4e, 0x6b, 0x8c, 0x15, 0xa7, 0xad, 0x55, 0x65, 0x45, 0x35, 0x3e,
-    0xcd, 0xdd, 0xae, 0x2d, 0x02, 0x89, 0x3e, 0x9f, 0x11, 0x6c, 0xff, 0xee,
-    0x0f, 0xb5, 0x5b, 0xe3, 0x8d, 0xcd, 0x2d, 0x3f, 0xf3, 0xf8, 0x25, 0x7e,
-    0xbf, 0x6e, 0xb8, 0xb4, 0xff, 0x6b, 0x56, 0x1e, 0xf4, 0x6f, 0x5a, 0x66,
-    0x31, 0x69, 0xf8, 0x58, 0xf7, 0xe3, 0xab, 0x4f, 0xff, 0x67, 0xb9, 0x8f,
-    0xed, 0x17, 0xb9, 0x4f, 0x5a, 0x66, 0x02, 0xd3, 0xfa, 0xb7, 0x6b, 0x0d,
-    0xb6, 0xea, 0x23, 0xc8, 0xb7, 0xea, 0x6c, 0x71, 0x1f, 0xfa, 0x85, 0x2c,
-    0xb6, 0xba, 0x95, 0xb0, 0xb0, 0xb8, 0x5e, 0x72, 0x16, 0x76, 0x2e, 0xdd,
-    0x2b, 0xa8, 0xde, 0x8c, 0xe2, 0x7d, 0xdb, 0x55, 0x59, 0x51, 0x55, 0x4f,
-    0xfa, 0x9f, 0xb6, 0x76, 0xd5, 0x56, 0x54, 0x4d, 0xb2, 0xdb, 0x0f, 0xf4,
-    0xe6, 0x73, 0xfb, 0x6c, 0xed, 0xaa, 0xac, 0xa8, 0xaf, 0xe7, 0xdd, 0xb5,
-    0x55, 0x95, 0x16, 0x34, 0xc6, 0x9e, 0xb4, 0xb6, 0xc3, 0xcb, 0x70, 0xce,
-    0x7f, 0xb3, 0xde, 0xce, 0x87, 0x09, 0x69, 0xc6, 0x3f, 0x16, 0x9c, 0x3d,
-    0xd8, 0x8f, 0x4b, 0x46, 0xd3, 0xee, 0xda, 0xaa, 0xca, 0x8b, 0x56, 0x7f,
-    0xd4, 0xfd, 0xb3, 0xb6, 0xaa, 0xb2, 0xa2, 0x82, 0x96, 0xd8, 0x7f, 0xa7,
-    0x33, 0x9c, 0x6b, 0xac, 0xb4, 0xf5, 0xaa, 0xac, 0xa8, 0xb8, 0xa7, 0xef,
-    0xeb, 0x70, 0xe7, 0x56, 0x8e, 0x9e, 0xde, 0x8b, 0x67, 0x75, 0x8e, 0xb4,
-    0xf5, 0x1a, 0x1b, 0xd6, 0x9f, 0x73, 0xf3, 0x30, 0x96, 0x9c, 0x68, 0x6c,
-    0xb4, 0x04, 0xf1, 0x4d, 0x14, 0x4f, 0xe6, 0x3d, 0x5c, 0x6e, 0x9a, 0x5a,
-    0x7e, 0xce, 0xd7, 0xbf, 0x65, 0xa7, 0xff, 0xa8, 0x98, 0x4d, 0x68, 0x75,
-    0x9c, 0xcb, 0xb5, 0xa4, 0xe0, 0x4f, 0xf2, 0xe1, 0x64, 0xb6, 0x65, 0x43,
-    0xb8, 0xf1, 0xd2, 0x2e, 0x0d, 0xd3, 0x47, 0x89, 0x3e, 0xc2, 0xc6, 0x7d,
-    0x75, 0x9b, 0x70, 0x18, 0xcb, 0x4f, 0xbb, 0x6a, 0xab, 0x2a, 0x2e, 0x99,
-    0xf3, 0x15, 0x05, 0x96, 0x96, 0xc6, 0xc5, 0x11, 0x58, 0x66, 0x26, 0x73,
-    0xff, 0xd8, 0x5e, 0x13, 0xf1, 0x84, 0xab, 0xa6, 0x2d, 0x3f, 0xf9, 0xed,
-    0xd0, 0x7c, 0xd7, 0x18, 0xf4, 0x4b, 0x4f, 0xcf, 0xa7, 0xd1, 0x59, 0x69,
-    0x8f, 0xb6, 0x1f, 0xab, 0x89, 0x53, 0xd8, 0xed, 0xd0, 0x75, 0xa7, 0xf8,
-    0x7a, 0x4d, 0xb9, 0xeb, 0xcb, 0x4f, 0xff, 0xdc, 0x2f, 0xe8, 0xdf, 0x1f,
-    0xcc, 0x33, 0x02, 0xe7, 0xeb, 0x4d, 0x6c, 0x5a, 0x18, 0xfd, 0x4c, 0x60,
-    0x9f, 0xf3, 0xf3, 0xbd, 0xa7, 0xdf, 0x8e, 0xad, 0x3f, 0xf6, 0x05, 0x9e,
-    0xdd, 0x6f, 0xb4, 0x4b, 0x4f, 0xfa, 0xe6, 0x3c, 0xe1, 0x1b, 0x8c, 0x15,
-    0xa0, 0xe8, 0x83, 0xa4, 0x29, 0xab, 0x6e, 0xa6, 0x0d, 0xe2, 0x2f, 0xb0,
-    0xc2, 0x8e, 0x27, 0xec, 0x51, 0xd9, 0x4f, 0xfb, 0xc3, 0x61, 0x0d, 0x11,
-    0x8c, 0xb4, 0xff, 0x36, 0xfc, 0xad, 0x79, 0x9d, 0x5a, 0x18, 0xfd, 0x7a,
-    0x79, 0x37, 0xfc, 0x5a, 0x7c, 0x59, 0xca, 0xf2, 0xd3, 0xf3, 0xeb, 0x2e,
-    0x30, 0x56, 0x83, 0x68, 0xf4, 0x8d, 0xb4, 0x96, 0x78, 0x7f, 0x7b, 0x2d,
-    0x3e, 0xa7, 0x1e, 0x3e, 0x5a, 0x1e, 0x79, 0x00, 0x21, 0x9f, 0xff, 0xe6,
-    0x0f, 0x33, 0x7f, 0x15, 0x70, 0x15, 0xad, 0x57, 0x6c, 0xb4, 0xfe, 0xcc,
-    0xc3, 0x0c, 0xa7, 0xad, 0x06, 0x22, 0x5f, 0xcc, 0xb3, 0xeb, 0x83, 0xdc,
-    0x0a, 0xd3, 0xff, 0xda, 0xe0, 0xeb, 0xdc, 0xc0, 0x8e, 0xb0, 0x96, 0x9d,
-    0xc6, 0x2c, 0x3f, 0x5f, 0xca, 0x27, 0xad, 0x55, 0x65, 0x44, 0x99, 0x3e,
-    0xb1, 0xb1, 0xba, 0xee, 0x83, 0x69, 0x69, 0xfd, 0x9b, 0xfb, 0xd4, 0xfd,
-    0x2d, 0x0c, 0x7e, 0x1d, 0x3d, 0x87, 0xa3, 0xc3, 0xa6, 0x47, 0x84, 0xec,
-    0xfc, 0x10, 0x1b, 0x5a, 0x05, 0xda, 0xd3, 0xb4, 0x21, 0x5a, 0x7e, 0x26,
-    0xdc, 0xf5, 0xe5, 0xa7, 0xf9, 0xad, 0xef, 0xf9, 0xd6, 0x75, 0x69, 0xfe,
-    0xde, 0xc3, 0xdd, 0x38, 0xd4, 0xb4, 0xdc, 0x17, 0x11, 0x75, 0xd1, 0xb3,
-    0x96, 0x78, 0xea, 0x7b, 0xc2, 0x7a, 0x5a, 0x7f, 0x0f, 0x34, 0xde, 0x60,
-    0xad, 0x18, 0x7a, 0x3e, 0x20, 0x9f, 0xe6, 0xe7, 0x86, 0xf3, 0xb5, 0x96,
-    0x9f, 0xff, 0x55, 0xba, 0xdc, 0x2c, 0xf6, 0x6c, 0xeb, 0xae, 0xa5, 0x0f,
-    0x45, 0x86, 0x88, 0x7c, 0x71, 0x3f, 0x5a, 0xdf, 0xd8, 0x99, 0x69, 0xff,
-    0x57, 0x9b, 0xba, 0xe3, 0x17, 0x96, 0x9f, 0x63, 0xc6, 0xae, 0x2d, 0x2f,
-    0xc8, 0xf8, 0xf4, 0x79, 0x3e, 0xa7, 0xfd, 0xc7, 0x16, 0x9c, 0xeb, 0xae,
-    0xa5, 0x3d, 0x79, 0xc7, 0x49, 0x6c, 0x5f, 0xcc, 0xc1, 0x5a, 0x5d, 0xa3,
-    0xc7, 0x23, 0x29, 0xfc, 0xf6, 0xed, 0xed, 0xdb, 0xd6, 0x9f, 0xb5, 0xa1,
-    0xc2, 0x02, 0xd3, 0xbb, 0x86, 0xeb, 0x47, 0x4f, 0x24, 0xe5, 0x70, 0xc8,
-    0x9f, 0xc7, 0xd9, 0xf0, 0xfa, 0xfc, 0x75, 0x69, 0xfe, 0x6b, 0x70, 0xbf,
-    0xf3, 0x69, 0x69, 0xff, 0xf7, 0xb9, 0x8f, 0xf9, 0x6e, 0x0f, 0xb7, 0xb0,
-    0xf5, 0x68, 0xea, 0x2e, 0x0e, 0x50, 0x47, 0x13, 0xff, 0x37, 0x6c, 0x76,
-    0xdf, 0x59, 0x73, 0x16, 0x9f, 0xec, 0xa0, 0x7c, 0xc0, 0xd3, 0xd6, 0x9f,
-    0xef, 0x85, 0xf3, 0x57, 0xd5, 0x71, 0x69, 0xff, 0xd5, 0x7f, 0x05, 0x8b,
-    0x1c, 0x1e, 0x8a, 0xd1, 0x89, 0x97, 0xe8, 0xbf, 0xc8, 0xbf, 0x9c, 0x3a,
-    0x79, 0x3e, 0x2c, 0xe5, 0x79, 0x69, 0xff, 0x3d, 0x8a, 0xff, 0xbd, 0x2f,
-    0xde, 0xb4, 0x1b, 0x9f, 0x33, 0x84, 0xb3, 0xde, 0xbf, 0x02, 0xb4, 0xff,
-    0x09, 0x9f, 0x7a, 0x03, 0x8e, 0x96, 0x87, 0x0f, 0x76, 0xec, 0x8a, 0x73,
-    0xae, 0xba, 0xb4, 0xff, 0xfb, 0x0f, 0xe2, 0x60, 0x60, 0x75, 0x87, 0x6b,
-    0x25, 0xb1, 0x7f, 0x3f, 0xc6, 0xcf, 0x5b, 0xc3, 0x61, 0x0a, 0xd1, 0x89,
-    0xb3, 0x0c, 0x20, 0xf8, 0x8b, 0xa6, 0x29, 0xde, 0x7f, 0x16, 0x90, 0xad,
-    0x3f, 0x71, 0xbe, 0x58, 0x6f, 0x5a, 0x7e, 0xed, 0x74, 0x99, 0xeb, 0x4f,
-    0xff, 0x57, 0xb9, 0x97, 0x38, 0x3f, 0x35, 0xa1, 0x3a, 0xd0, 0x6d, 0xd1,
-    0x76, 0x10, 0xfe, 0x97, 0x91, 0x5c, 0xcf, 0xda, 0xea, 0x66, 0xa3, 0x5d,
-    0x6d, 0x2c, 0xec, 0xf8, 0x5c, 0xe4, 0x71, 0x26, 0x1a, 0xda, 0x1e, 0x1b,
-    0xc6, 0x94, 0x26, 0x0e, 0x42, 0x40, 0xe5, 0x15, 0x08, 0xf2, 0x86, 0x2e,
-    0xa5, 0x04, 0x7a, 0x50, 0xc5, 0xda, 0x0f, 0xd8, 0x6b, 0xcf, 0xfe, 0xee,
-    0x3a, 0x1e, 0x63, 0x85, 0x9d, 0x7a, 0xd3, 0xbb, 0x86, 0xeb, 0x4b, 0x3a,
-    0x7d, 0x07, 0x4a, 0x9f, 0xdd, 0xb7, 0xf4, 0x13, 0xb2, 0xd3, 0xff, 0x37,
-    0x7e, 0xf8, 0x7d, 0xcc, 0x08, 0xad, 0x3f, 0xee, 0x13, 0x5f, 0xf7, 0x9c,
-    0xa3, 0x75, 0xa1, 0x91, 0x75, 0x79, 0x9e, 0x22, 0x4f, 0xd5, 0x6d, 0x9d,
-    0x75, 0xd5, 0xa7, 0xe6, 0xed, 0x3c, 0x78, 0xb4, 0xfb, 0x0f, 0xca, 0x0a,
-    0xd2, 0xd9, 0x9b, 0x44, 0x8c, 0x86, 0x09, 0x85, 0xf6, 0x94, 0x3b, 0xd8,
-    0x4f, 0x55, 0x35, 0x9c, 0xa3, 0xa4, 0xd4, 0x38, 0x6e, 0x17, 0xba, 0x62,
-    0x68, 0xae, 0x1e, 0xdf, 0x7a, 0x86, 0x5c, 0x26, 0xf1, 0x83, 0x74, 0xa0,
-    0xf0, 0x8a, 0xe3, 0xd8, 0x21, 0x61, 0xa9, 0x48, 0xbe, 0x87, 0xdf, 0xf5,
-    0xa4, 0x1c, 0xff, 0xfb, 0x6f, 0xad, 0x7e, 0x79, 0x88, 0x41, 0x9b, 0xf9,
-    0x69, 0xfd, 0xb6, 0x76, 0xd5, 0x56, 0x54, 0x46, 0xb3, 0xee, 0xda, 0xaa,
-    0xca, 0x8a, 0x96, 0x6a, 0xb2, 0xa2, 0x1a, 0x96, 0xd8, 0x7a, 0xb4, 0x67,
-    0x3e, 0xed, 0xaa, 0xac, 0xa8, 0x8f, 0xa7, 0xff, 0x8a, 0xbc, 0xf6, 0x33,
-    0xe3, 0x7b, 0x4c, 0x05, 0xa7, 0x53, 0xf6, 0xc4, 0x41, 0xfd, 0x33, 0x9f,
-    0xfc, 0x7c, 0xdb, 0xeb, 0x77, 0x0b, 0xd9, 0xc5, 0xa3, 0x64, 0x40, 0x31,
-    0xb4, 0xfb, 0xb6, 0xaa, 0xb2, 0xa2, 0xc7, 0x9f, 0xe2, 0xa3, 0x38, 0x2c,
-    0x57, 0xad, 0x3f, 0x60, 0xfb, 0xc3, 0xe5, 0xa7, 0xd9, 0xdc, 0xc7, 0x16,
-    0x96, 0xd8, 0x8b, 0xb7, 0x0c, 0xf4, 0x6f, 0xf4, 0xae, 0x71, 0xb1, 0x39,
-    0x8b, 0x4f, 0xc6, 0xd1, 0x67, 0x2b, 0xcb, 0x4f, 0xf1, 0x50, 0x35, 0x5e,
-    0xf5, 0x2d, 0x3c, 0x03, 0x8f, 0x56, 0x9f, 0xff, 0xe6, 0xe9, 0x60, 0x73,
-    0x9c, 0x1b, 0x70, 0x7d, 0xaa, 0xdd, 0x68, 0x14, 0x42, 0xf0, 0x86, 0x7e,
-    0x6e, 0x82, 0xef, 0xff, 0x2d, 0x3f, 0xcc, 0x5e, 0xba, 0xeb, 0xdf, 0xb2,
-    0xd3, 0xaa, 0xac, 0xa8, 0xb4, 0x27, 0xfd, 0x4e, 0x9a, 0xb5, 0x76, 0xfc,
-    0x75, 0x69, 0xf8, 0x0c, 0x4d, 0xed, 0x2d, 0x16, 0x44, 0xa7, 0x49, 0xc0,
-    0x85, 0x3f, 0xff, 0xfc, 0x3d, 0xe5, 0x10, 0xb7, 0x87, 0x8d, 0xae, 0x66,
-    0xbb, 0x96, 0xcf, 0x2d, 0x0f, 0x4e, 0xa4, 0x26, 0x3d, 0x86, 0x87, 0x0c,
-    0x27, 0xff, 0xee, 0xf7, 0xfe, 0xf5, 0x8b, 0x0c, 0x1e, 0x73, 0x3e, 0xad,
-    0x3e, 0x2b, 0x56, 0x85, 0x69, 0xff, 0xfb, 0xa4, 0xcd, 0xbf, 0xcd, 0x78,
-    0x98, 0x3c, 0x6f, 0x2d, 0x30, 0xf1, 0x69, 0xe7, 0x95, 0x7d, 0x5a, 0x7f,
-    0x84, 0x34, 0x0e, 0xf6, 0x80, 0xb4, 0x32, 0x3b, 0xb0, 0x94, 0xdd, 0x6e,
-    0x85, 0x7f, 0x22, 0x9d, 0x46, 0xe2, 0xb4, 0xff, 0xbe, 0xf8, 0xc1, 0x31,
-    0xb0, 0x99, 0x69, 0xf7, 0xdf, 0x13, 0x01, 0x68, 0xdd, 0x10, 0x9d, 0x1d,
-    0xb8, 0x7f, 0x3e, 0x6f, 0x67, 0x19, 0x69, 0xff, 0xff, 0xdc, 0x10, 0xe0,
-    0xdf, 0xc6, 0x6f, 0x99, 0xbb, 0xf4, 0x3e, 0xa2, 0xc5, 0xa7, 0xff, 0xb3,
-    0xda, 0xc7, 0x38, 0xd7, 0x33, 0x9c, 0x65, 0xa7, 0xf8, 0x99, 0x9c, 0xcb,
-    0x83, 0xd5, 0xa2, 0xf4, 0xc8, 0xec, 0x4a, 0x4e, 0xde, 0x50, 0x86, 0x4e,
-    0x53, 0x23, 0x56, 0x9f, 0xff, 0x99, 0xcc, 0x0f, 0x1a, 0xe7, 0x33, 0xc4,
-    0xcc, 0x75, 0xa7, 0xed, 0xf5, 0xf6, 0xff, 0xc9, 0x69, 0xfe, 0x6b, 0x70,
-    0x5c, 0xaa, 0xbd, 0x68, 0x3a, 0x31, 0x29, 0x68, 0x06, 0x53, 0xf9, 0xed,
-    0xdb, 0xdb, 0xb7, 0xad, 0x3f, 0xc3, 0xf9, 0x3f, 0xad, 0x81, 0x5a, 0x7f,
-    0xff, 0xb9, 0x8f, 0xb7, 0x07, 0x8d, 0x9d, 0x7f, 0x89, 0x8f, 0xa5, 0xa3,
-    0x48, 0x9b, 0xf1, 0xbc, 0x32, 0x3c, 0xb2, 0x19, 0xf3, 0xf7, 0x5b, 0xd7,
-    0xe3, 0xab, 0x4f, 0xbd, 0xca, 0x23, 0x16, 0x9f, 0xe2, 0xfe, 0xf0, 0xf3,
-    0x09, 0x96, 0x96, 0x61, 0xef, 0xd8, 0x9e, 0x05, 0x16, 0x65, 0x08, 0xd9,
-    0xfd, 0x9c, 0x70, 0x78, 0x27, 0x5a, 0x7f, 0x3f, 0x3b, 0xa2, 0x6b, 0xd6,
-    0x9d, 0x9c, 0xa5, 0xa7, 0xce, 0x07, 0xff, 0xc9, 0x68, 0x09, 0xe2, 0x50,
-    0xd4, 0xfe, 0xc7, 0x72, 0xd6, 0xc7, 0x56, 0x9c, 0x63, 0xff, 0x5a, 0x7f,
-    0xdb, 0xbb, 0xfd, 0x17, 0x32, 0x9c, 0x5a, 0x04, 0xf7, 0xa8, 0x7a, 0x31,
-    0x16, 0x25, 0x09, 0x18, 0xc4, 0xe8, 0x37, 0x32, 0xa7, 0x6d, 0x43, 0x4a,
-    0x7b, 0x39, 0x5e, 0x5a, 0x7e, 0x12, 0xfd, 0xf9, 0xa5, 0xa7, 0xfd, 0x9e,
-    0x6d, 0xc1, 0x5c, 0xe0, 0xad, 0x23, 0xad, 0x3f, 0x09, 0x7e, 0xfc, 0xd7,
-    0xc3, 0xcd, 0xb8, 0x7b, 0x06, 0x23, 0x07, 0xcf, 0x32, 0xda, 0xea, 0x66,
-    0x5e, 0xdd, 0x64, 0x6c, 0x60, 0x18, 0x5d, 0xe4, 0x79, 0x62, 0x86, 0x78,
-    0xd2, 0xf9, 0x29, 0x8c, 0x10, 0xec, 0x28, 0xc8, 0x75, 0x0d, 0x9f, 0x47,
-    0x8d, 0x76, 0x85, 0xf6, 0x1c, 0x33, 0xf1, 0xa1, 0x09, 0x33, 0x8b, 0x4e,
-    0x6a, 0x25, 0xa7, 0xb3, 0x95, 0xe5, 0xa4, 0x6d, 0x61, 0xf3, 0xf0, 0xb8,
-    0x86, 0x67, 0x1f, 0x46, 0x2d, 0x3d, 0x9a, 0x00, 0xad, 0x3e, 0xed, 0xaa,
-    0xac, 0xa8, 0xb5, 0xa7, 0xec, 0x35, 0xaa, 0x2b, 0x2d, 0x3b, 0xac, 0x75,
-    0xa7, 0xee, 0x66, 0x9a, 0xf3, 0x4b, 0x4f, 0xf3, 0xf6, 0xce, 0xda, 0xaa,
-    0xca, 0x8a, 0x0e, 0x30, 0xfd, 0x28, 0xbe, 0x7b, 0x1c, 0x6f, 0x2d, 0x3f,
-    0xcc, 0xf6, 0xed, 0xed, 0xdb, 0xd6, 0x96, 0xd7, 0x5a, 0x7b, 0xcc, 0x70,
-    0xf1, 0xdc, 0x20, 0x70, 0xcf, 0xa5, 0xa7, 0x84, 0x7f, 0x08, 0x08, 0x86,
-    0x7f, 0xf6, 0xc7, 0xa7, 0xed, 0x9d, 0xb5, 0x55, 0x95, 0x14, 0x5c, 0xfe,
-    0xdb, 0x3b, 0x6a, 0xab, 0x2a, 0x2e, 0xa8, 0x66, 0xd1, 0x9d, 0xea, 0xf6,
-    0x84, 0xa0, 0xc6, 0x54, 0x78, 0x6f, 0x72, 0x9a, 0x06, 0x09, 0x69, 0xba,
-    0x84, 0x77, 0x95, 0xe7, 0xdd, 0xb5, 0x55, 0x95, 0x11, 0x0c, 0xee, 0x60,
-    0x56, 0x9e, 0xcb, 0x83, 0xd5, 0xa5, 0xb6, 0x1f, 0x86, 0xe6, 0x66, 0xe3,
-    0x73, 0xfb, 0x6c, 0xed, 0xaa, 0xac, 0xa8, 0x8d, 0xa7, 0xf6, 0xd9, 0xdb,
-    0x55, 0x59, 0x51, 0x4d, 0xcf, 0xed, 0xb3, 0xb6, 0xaa, 0xb2, 0xa2, 0xa0,
-    0x9f, 0xdb, 0x67, 0x6d, 0x55, 0x65, 0x45, 0x4d, 0x3e, 0xed, 0xaa, 0xac,
-    0xa8, 0xac, 0x27, 0xc2, 0xe8, 0x7f, 0xea, 0xd3, 0xfc, 0xfd, 0xb3, 0xb6,
-    0xaa, 0xb2, 0xa2, 0x3f, 0x9d, 0x8d, 0x7a, 0xd3, 0xfb, 0x37, 0x7d, 0x3c,
-    0x49, 0x69, 0xab, 0xcb, 0x4b, 0x6c, 0x4c, 0x0a, 0xc6, 0x74, 0x52, 0x48,
-    0xbe, 0x1b, 0xbb, 0x31, 0x9f, 0xfd, 0xb1, 0xe9, 0xfb, 0x67, 0x6d, 0x55,
-    0x65, 0x44, 0xdf, 0x3f, 0xf1, 0xe9, 0xfb, 0x67, 0x6d, 0x55, 0x65, 0x44,
-    0xfd, 0x39, 0x8a, 0xcb, 0x4f, 0xe3, 0x60, 0x6c, 0x96, 0x5e, 0xdb, 0xad,
-    0x3e, 0xba, 0x0d, 0xab, 0xbc, 0xdd, 0x69, 0x71, 0x68, 0xba, 0x11, 0x06,
-    0x6c, 0x9f, 0x7e, 0x6b, 0x3f, 0xc6, 0xc3, 0x95, 0xef, 0x55, 0x3a, 0xb4,
-    0xfd, 0xee, 0x0d, 0x00, 0xd8, 0x2d, 0x3e, 0xba, 0xcd, 0xb8, 0x0c, 0x65,
-    0xa7, 0xff, 0x99, 0x99, 0x99, 0x99, 0x99, 0xb7, 0xd2, 0xd3, 0xee, 0x8d,
-    0xf4, 0x74, 0xa6, 0x75, 0xd4, 0xa3, 0x0d, 0xfb, 0xa4, 0xf2, 0xfd, 0x2d,
-    0x8d, 0x0c, 0x32, 0x32, 0xf5, 0x0a, 0x99, 0xf5, 0x51, 0x31, 0xa5, 0xa7,
-    0xfe, 0xe3, 0x0f, 0x7f, 0x2f, 0xfd, 0xff, 0x96, 0x9e, 0xe9, 0x0b, 0x2d,
-    0x39, 0xda, 0x75, 0x69, 0xff, 0xde, 0xed, 0x5e, 0x1e, 0x36, 0xbd, 0xff,
-    0x16, 0x9b, 0x0f, 0xc3, 0xe9, 0xd0, 0xec, 0xfa, 0xad, 0xc1, 0xea, 0xd3,
-    0xff, 0xff, 0x8a, 0x8c, 0x1e, 0xb3, 0xfe, 0x70, 0x4e, 0x16, 0xf9, 0x77,
-    0xff, 0x07, 0xab, 0x4f, 0x53, 0xc7, 0x75, 0xa0, 0x28, 0xf2, 0xe9, 0x6f,
-    0x09, 0x89, 0xfa, 0x4c, 0xb4, 0xff, 0xf3, 0x6e, 0xfa, 0x20, 0x7c, 0x00,
-    0xf4, 0x4c, 0x5a, 0x2e, 0xcf, 0x80, 0xd0, 0x7c, 0xf5, 0xe7, 0x17, 0xad,
-    0x3e, 0xd1, 0x7f, 0x4f, 0x5a, 0x7f, 0x71, 0x8f, 0xb0, 0x00, 0xcb, 0x4b,
-    0xac, 0x7f, 0x98, 0x44, 0x24, 0xf3, 0xfd, 0xb8, 0x7e, 0xb1, 0xbf, 0x3f,
-    0xd2, 0xd3, 0xff, 0xe0, 0xf1, 0xba, 0x20, 0x6f, 0xac, 0xe1, 0x31, 0xd6,
-    0x9f, 0xc6, 0x31, 0x7b, 0x55, 0xc5, 0xa0, 0x51, 0x0f, 0x4a, 0xb0, 0xc8,
-    0xe8, 0x28, 0x63, 0xce, 0xcc, 0x71, 0x69, 0x1b, 0xad, 0x3b, 0xcf, 0xc5,
-    0xa6, 0xd6, 0x2d, 0x02, 0x78, 0x74, 0x26, 0x01, 0xb9, 0xff, 0x82, 0xde,
-    0xad, 0x67, 0x38, 0x27, 0x5a, 0x77, 0x85, 0xc5, 0xa1, 0x8f, 0x7b, 0x48,
-    0x53, 0xe6, 0x37, 0x17, 0x6c, 0xb4, 0x32, 0xee, 0x05, 0xe4, 0xe1, 0x26,
-    0xc4, 0x61, 0x8d, 0xe9, 0xc8, 0x4e, 0x76, 0x14, 0x67, 0x8c, 0x68, 0x04,
-    0xc4, 0xbd, 0xe8, 0x45, 0xfd, 0x21, 0x9c, 0xe7, 0xd3, 0xad, 0x3f, 0xd9,
-    0xed, 0x67, 0xb9, 0x80, 0x5a, 0x28, 0xf5, 0x88, 0x7e, 0x6a, 0x25, 0xa3,
-    0xa6, 0xd0, 0xe4, 0x13, 0xf6, 0x79, 0x88, 0x40, 0xb4, 0xe7, 0x5d, 0x75,
-    0x69, 0xeb, 0xc8, 0x59, 0x2d, 0x8b, 0xf9, 0xb7, 0x7a, 0xd3, 0xf8, 0xc6,
-    0xf6, 0xb9, 0x5f, 0xad, 0x3e, 0x1b, 0xf3, 0x7f, 0x2d, 0x30, 0xd9, 0x69,
-    0x6e, 0xc8, 0x88, 0x30, 0x5c, 0xe6, 0x9e, 0x28, 0x86, 0x4d, 0x98, 0x24,
-    0x3c, 0x49, 0xfe, 0x17, 0x13, 0xfe, 0xd5, 0x19, 0xc1, 0x62, 0xfd, 0x96,
-    0x9f, 0x57, 0x7f, 0xad, 0x2d, 0x33, 0xfc, 0xb4, 0xf3, 0x8d, 0xea, 0x5a,
-    0x7d, 0x7f, 0xe0, 0xc2, 0xb1, 0xb7, 0xfc, 0x5a, 0x7f, 0xe6, 0xe7, 0xd0,
-    0xf8, 0x71, 0xc6, 0x3a, 0xd3, 0xcd, 0xef, 0xce, 0xb4, 0xda, 0xb2, 0xa2,
-    0x0e, 0x83, 0x9e, 0x2f, 0x88, 0xa7, 0xff, 0xc7, 0xd5, 0x3f, 0x83, 0x9e,
-    0xd7, 0x70, 0x38, 0xb4, 0xff, 0x37, 0x8b, 0x2e, 0x16, 0x69, 0x68, 0x64,
-    0x56, 0x61, 0x16, 0x94, 0xe7, 0xea, 0xe3, 0x1b, 0xfe, 0xf5, 0xa2, 0xca,
-    0x8c, 0xba, 0xbc, 0x74, 0x0f, 0x46, 0x6d, 0x70, 0xba, 0x7f, 0x33, 0xcb,
-    0x37, 0xf6, 0x2d, 0x37, 0x42, 0xb4, 0xce, 0xba, 0xb4, 0x3c, 0xd7, 0x3a,
-    0x2d, 0x3d, 0xa6, 0x1b, 0x89, 0x6c, 0x68, 0xa7, 0xda, 0xfa, 0x10, 0x69,
-    0x68, 0x13, 0xdd, 0xfa, 0x67, 0x39, 0xd7, 0x5d, 0x4a, 0x12, 0xd8, 0xbf,
-    0x9e, 0x17, 0x45, 0xc4, 0xa2, 0xc6, 0xf0, 0x46, 0xa7, 0xd9, 0xd6, 0xb9,
-    0x8b, 0x46, 0x2e, 0x33, 0x0c, 0xa6, 0xfe, 0xaa, 0x72, 0x1b, 0xc4, 0xfd,
-    0xa2, 0x09, 0xfc, 0x5b, 0xfb, 0xef, 0x28, 0x0b, 0x4e, 0x21, 0xd2, 0xd3,
-    0xc1, 0xa2, 0x02, 0xd3, 0xff, 0x31, 0x00, 0x9b, 0x77, 0x18, 0x80, 0xb4,
-    0x62, 0x2c, 0x44, 0xd4, 0x03, 0x5a, 0x20, 0x9f, 0xc0, 0xd7, 0xdb, 0xef,
-    0xad, 0xd6, 0x9f, 0x36, 0x77, 0x82, 0xb4, 0xec, 0x39, 0xba, 0xd3, 0xfb,
-    0x34, 0x59, 0xee, 0x0a, 0xd0, 0x13, 0xce, 0x21, 0xe8, 0xc4, 0x66, 0x38,
-    0x71, 0x71, 0xce, 0x7e, 0xf6, 0x38, 0x4c, 0x75, 0xc4, 0x05, 0x3e, 0xa2,
-    0x0f, 0x19, 0x51, 0x01, 0x6c, 0x6e, 0x67, 0xfe, 0x1d, 0xf4, 0x1c, 0x26,
-    0x2f, 0xd9, 0x69, 0xff, 0xbf, 0xb1, 0x9d, 0xcd, 0xf4, 0x0a, 0xf2, 0xd3,
-    0xe6, 0x7d, 0x6e, 0xea, 0xd1, 0x88, 0xb1, 0x14, 0x2e, 0xa3, 0xcf, 0xf3,
-    0x76, 0xff, 0x98, 0xe0, 0x9d, 0x69, 0xe3, 0xb6, 0x1d, 0x69, 0xf3, 0x00,
-    0x77, 0xd2, 0xd3, 0xfb, 0xae, 0x68, 0x4b, 0xc2, 0xb4, 0xf6, 0xe0, 0xeb,
-    0x25, 0x33, 0xae, 0xa5, 0x0c, 0x6e, 0x9d, 0x22, 0x9f, 0xab, 0xaf, 0x79,
-    0x0a, 0x5b, 0x1a, 0x18, 0x65, 0x7b, 0xf9, 0x18, 0x38, 0xb5, 0xf6, 0x1e,
-    0x9c, 0x2e, 0xa3, 0xb2, 0x20, 0xf1, 0x3f, 0xf0, 0x8d, 0x9f, 0x7f, 0xef,
-    0xeb, 0xea, 0xa2, 0x07, 0x9c, 0x6e, 0x20, 0x5a, 0x66, 0xfd, 0x69, 0xf7,
-    0xe4, 0x0f, 0xaf, 0x5a, 0x7f, 0xf8, 0xb3, 0x5f, 0x3e, 0xf1, 0x80, 0x7a,
-    0x7f, 0xcc, 0x3c, 0x0d, 0x0b, 0x47, 0xe8, 0xc9, 0xb8, 0xbd, 0x3f, 0xee,
-    0x7f, 0x7b, 0x7c, 0x6f, 0x30, 0x56, 0x9d, 0x5d, 0xbd, 0x69, 0x9d, 0x75,
-    0x69, 0xfd, 0xd1, 0xcb, 0x9f, 0x5f, 0xb5, 0x8d, 0xa3, 0xa3, 0x90, 0x14,
-    0x62, 0x75, 0xd6, 0x7f, 0xe2, 0xc3, 0x39, 0x4f, 0xfb, 0x5b, 0xb2, 0xd0,
-    0xc7, 0xd1, 0x84, 0x73, 0xff, 0xb0, 0xe7, 0xa7, 0xe7, 0x6d, 0x55, 0x65,
-    0x44, 0x31, 0x02, 0x9e, 0x37, 0x23, 0x52, 0x22, 0x09, 0xfc, 0x7e, 0x55,
-    0xe4, 0xcf, 0x5a, 0x7f, 0x9b, 0x77, 0xf2, 0xa8, 0x99, 0x69, 0xf7, 0x6d,
-    0x55, 0x65, 0x44, 0x15, 0x3b, 0x8c, 0x75, 0xa3, 0x0f, 0x38, 0x4c, 0xe7,
-    0xbd, 0xa6, 0x02, 0x53, 0xab, 0xb7, 0xa5, 0x3d, 0xf9, 0x51, 0x89, 0x4f,
-    0xe1, 0xbf, 0x3d, 0xa6, 0x02, 0x50, 0x94, 0xfd, 0x96, 0x6e, 0x31, 0xd2,
-    0x99, 0xd7, 0x52, 0x9f, 0x89, 0x8a, 0xf1, 0xea, 0x51, 0x89, 0x84, 0xd8,
-    0x84, 0xe3, 0x9c, 0x22, 0x01, 0x91, 0x05, 0x3a, 0x57, 0xf4, 0x62, 0x61,
-    0xea, 0x5b, 0x1f, 0x9c, 0x3d, 0x3c, 0x3e, 0x47, 0x39, 0x0c, 0xaa, 0x8f,
-    0x86, 0x55, 0x29, 0x1e, 0x7f, 0x51, 0x66, 0xba, 0xda, 0x5a, 0x7e, 0x0e,
-    0x15, 0x7b, 0x4b, 0x49, 0x9e, 0x7b, 0x7a, 0x30, 0x9f, 0x77, 0x77, 0xe7,
-    0x96, 0x9f, 0xdc, 0x6b, 0x81, 0x60, 0x32, 0xd1, 0xd3, 0xdb, 0xf1, 0x44,
-    0xff, 0x36, 0xef, 0xbb, 0x6b, 0x61, 0xd6, 0x9f, 0xfd, 0x46, 0x59, 0xbd,
-    0xac, 0xf0, 0xee, 0xea, 0xd0, 0xc8, 0xa8, 0xe1, 0x11, 0x1d, 0xcf, 0xff,
-    0xaa, 0x9f, 0x5c, 0xf9, 0x97, 0xff, 0xef, 0xeb, 0xea, 0xa2, 0xfb, 0x9f,
-    0xf6, 0x84, 0xb7, 0x7f, 0x7f, 0x6d, 0x2d, 0x0e, 0x22, 0x9b, 0xcc, 0xf2,
-    0xb2, 0xd3, 0xff, 0xf8, 0x03, 0xd3, 0x38, 0xc7, 0x71, 0xe2, 0x5c, 0x6e,
-    0xb2, 0xd2, 0xf6, 0x1f, 0x86, 0x84, 0x27, 0xbc, 0x58, 0xf5, 0xa1, 0x8f,
-    0x1c, 0x49, 0xe7, 0xfc, 0x42, 0xff, 0x73, 0x3a, 0x3a, 0x5a, 0x7f, 0x71,
-    0x9e, 0x59, 0x97, 0xad, 0x3f, 0xbc, 0x0f, 0xa4, 0xfe, 0x62, 0xe2, 0x01,
-    0x9d, 0x5d, 0x7a, 0xe2, 0x01, 0x8c, 0x3e, 0x9f, 0xd0, 0x66, 0xa7, 0xae,
-    0x20, 0x19, 0xea, 0x2d, 0xde, 0xb8, 0x80, 0x67, 0xf0, 0xdb, 0x98, 0x00,
-    0x32, 0xe2, 0x01, 0x9c, 0x24, 0x15, 0xc4, 0x03, 0x01, 0x45, 0xa9, 0xc8,
-    0xb8, 0x5d, 0x70, 0xfa, 0x77, 0x5b, 0xcb, 0x88, 0x06, 0x17, 0x10, 0x0c,
-    0xcc, 0x75, 0xc4, 0x03, 0x01, 0x37, 0x22, 0x2f, 0x3c, 0x27, 0x0b, 0x2e,
-    0x20, 0x19, 0xde, 0xab, 0x2e, 0x20, 0x19, 0xff, 0x15, 0x3f, 0x6e, 0x0d,
-    0xab, 0xab, 0x88, 0x06, 0x7f, 0xea, 0xf7, 0xf7, 0x89, 0x7b, 0x94, 0xf5,
-    0xc4, 0x03, 0x35, 0x05, 0x71, 0x00, 0xcf, 0xe2, 0xa7, 0x75, 0xa6, 0x02,
-    0xe2, 0x01, 0x9f, 0x09, 0x94, 0x40, 0x5c, 0x40, 0x33, 0x0e, 0x97, 0x10,
-    0x0c, 0x74, 0xf5, 0x7c, 0x67, 0x3e, 0xf1, 0x36, 0xef, 0x54, 0x40, 0x33,
-    0x01, 0x97, 0x10, 0x0e, 0xc6, 0xd2, 0x7c, 0x2c, 0x7a, 0x0a, 0xe2, 0x01,
-    0x9e, 0xfe, 0x8a, 0xcb, 0x88, 0x06, 0x73, 0x76, 0xcb, 0x88, 0x06, 0x7f,
-    0xd9, 0xbe, 0x82, 0xd8, 0x40, 0xd2, 0xe2, 0x01, 0x9f, 0x7f, 0x4f, 0x7b,
-    0x2e, 0x20, 0x19, 0xf5, 0x5b, 0x8d, 0xba, 0xe2, 0x01, 0x8c, 0x45, 0x97,
-    0x12, 0xbf, 0x34, 0x9b, 0xa0, 0x5c, 0x40, 0x30, 0xf5, 0x59, 0x81, 0x22,
-    0xc8, 0x4a, 0x0a, 0xb7, 0x0c, 0xc0, 0x65, 0xa2, 0xef, 0x43, 0x6b, 0xf3,
-    0x09, 0xf6, 0x7b, 0x55, 0xba, 0xe2, 0x01, 0x9f, 0xc1, 0x6b, 0x39, 0xd6,
-    0xf2, 0xe2, 0x01, 0x09, 0xb4, 0x9d, 0xd6, 0x75, 0x71, 0x00, 0xc5, 0x8f,
-    0xe7, 0xaa, 0x13, 0xfb, 0xfa, 0x7b, 0xdb, 0xe9, 0xd7, 0x10, 0x0c, 0xf0,
-    0x93, 0xf4, 0xb8, 0x80, 0x67, 0xea, 0x71, 0xf9, 0xbb, 0xd7, 0x10, 0x0c,
-    0x62, 0x33, 0x38, 0x44, 0x04, 0x2f, 0xcb, 0x67, 0xfb, 0x8d, 0xad, 0xb5,
-    0xff, 0x40, 0xb8, 0x80, 0x64, 0x2b, 0x88, 0x06, 0x6a, 0xbc, 0x27, 0xc9,
-    0xc4, 0x89, 0xba, 0x05, 0xc4, 0x03, 0x3e, 0xaf, 0x68, 0x77, 0x5c, 0x40,
-    0x33, 0xf0, 0x97, 0xef, 0xcd, 0x2e, 0x20, 0x18, 0x64, 0x48, 0x11, 0x1f,
-    0x8d, 0x20, 0x2c, 0x8e, 0x2c, 0x86, 0xbb, 0x87, 0xfd, 0x61, 0xe1, 0x05,
-    0x16, 0x80, 0xa0, 0x92, 0xb5, 0x2c, 0x77, 0xd2, 0x80, 0xae, 0xe1, 0x43,
-    0xf6, 0x17, 0xd3, 0xaa, 0xac, 0xa8, 0x80, 0x76, 0x46, 0x4c, 0xf1, 0x86,
-    0xdc, 0x27, 0x5a, 0x7f, 0xe7, 0x96, 0x5b, 0x82, 0x00, 0x7e, 0xe2, 0xd3,
-    0x01, 0x92, 0x91, 0x89, 0x4e, 0xe3, 0x5e, 0xb4, 0xce, 0xba, 0x94, 0x09,
-    0xed, 0x1b, 0x8a, 0xb8, 0x22, 0xe8, 0xe4, 0xe3, 0x8e, 0x92, 0xd8, 0xf0,
-    0x27, 0x0f, 0xfe, 0x5a, 0x7f, 0xf7, 0xb5, 0x86, 0x0f, 0x7e, 0x80, 0x0d,
-    0xba, 0xd1, 0x7b, 0x31, 0xe5, 0xe4, 0x01, 0x3c, 0xb5, 0x29, 0x14, 0x4e,
-    0xa8, 0xa4, 0x10, 0xdf, 0xf1, 0x6f, 0xd1, 0xc9, 0xfb, 0xdf, 0x6e, 0x5c,
-    0x6d, 0x2d, 0x38, 0xb7, 0x7a, 0xe3, 0x00, 0x81, 0x3d, 0xca, 0x33, 0x9f,
-    0x38, 0xf6, 0xed, 0xeb, 0x4f, 0x31, 0x8c, 0x75, 0xa3, 0xa7, 0x94, 0x72,
-    0x99, 0xff, 0x3f, 0x5f, 0x0b, 0x0e, 0xdd, 0x31, 0x69, 0xf9, 0xed, 0xd0,
-    0x7d, 0x3a, 0xd3, 0xff, 0x5c, 0x2c, 0xd7, 0xb0, 0x9f, 0x9a, 0x5a, 0x78,
-    0xed, 0xff, 0x96, 0x8c, 0x3e, 0x5a, 0x43, 0x9b, 0x95, 0x88, 0xb4, 0x28,
-    0x4a, 0x4f, 0xf3, 0x59, 0x8e, 0x27, 0x00, 0xad, 0x1d, 0x3e, 0x73, 0x46,
-    0x33, 0xf7, 0xd7, 0x7a, 0x39, 0xc4, 0xa7, 0x9c, 0xe5, 0x38, 0xb4, 0xfb,
-    0x1c, 0x7b, 0x6e, 0xb4, 0xee, 0x0b, 0x8b, 0x4e, 0x26, 0x7a, 0x53, 0xfe,
-    0x20, 0x09, 0xa3, 0x5f, 0xbd, 0x8d, 0xd6, 0x8c, 0x3d, 0xfa, 0x1a, 0x8e,
-    0xa3, 0x98, 0x88, 0xfc, 0x50, 0x69, 0xee, 0x19, 0x57, 0xa6, 0x11, 0x0c,
-    0x6b, 0x7c, 0x24, 0xa8, 0xc5, 0x67, 0xed, 0xf5, 0xde, 0xb7, 0x96, 0x9f,
-    0x9f, 0xa3, 0x3b, 0x56, 0x5a, 0x71, 0x7b, 0x4b, 0x4f, 0xb5, 0xf9, 0x7f,
-    0x65, 0xa1, 0x8f, 0xc8, 0x4b, 0xbf, 0x1b, 0x9f, 0xfb, 0x8e, 0xb7, 0x75,
-    0x8e, 0xd7, 0x4c, 0x5a, 0x6b, 0xa7, 0x4b, 0x43, 0xcf, 0x87, 0xf4, 0x69,
-    0xff, 0x73, 0x0d, 0x51, 0x19, 0x9b, 0xf9, 0x69, 0xff, 0x1f, 0x2d, 0xc1,
-    0x0f, 0x3f, 0x31, 0x68, 0x31, 0x10, 0x00, 0x40, 0x9f, 0xe3, 0x2b, 0xe3,
-    0x1c, 0x84, 0xc5, 0xa7, 0xfd, 0x5a, 0x3b, 0x0f, 0x7a, 0x2e, 0xad, 0x2d,
-    0x18, 0x7e, 0xfc, 0x3a, 0x9f, 0xec, 0xf7, 0x84, 0xcf, 0x65, 0x96, 0x9f,
-    0xc1, 0x6d, 0xf5, 0x9b, 0xf9, 0x69, 0xfe, 0x6f, 0x0d, 0x84, 0x2d, 0xe5,
-    0xa5, 0xa0, 0xa2, 0x8b, 0x0e, 0x3a, 0x69, 0x1b, 0xa6, 0x01, 0xe8, 0x65,
-    0xcf, 0xf7, 0x86, 0xf6, 0xdc, 0x1d, 0x65, 0xa7, 0x6b, 0xd8, 0xb4, 0xd9,
-    0xaf, 0x87, 0xa9, 0xf4, 0xe6, 0x7e, 0xbb, 0xcf, 0x02, 0xbc, 0xb4, 0x3c,
-    0xf8, 0x3c, 0x63, 0x0c, 0xac, 0xf8, 0x61, 0x47, 0x51, 0xcd, 0xff, 0x0d,
-    0xe9, 0xee, 0x0d, 0x3d, 0x69, 0xfe, 0x79, 0x7e, 0x0f, 0x96, 0x38, 0x16,
-    0x93, 0x5e, 0x7b, 0x9b, 0x90, 0x4f, 0xaa, 0xe0, 0x42, 0xcb, 0x4d, 0xad,
-    0x2d, 0x39, 0xd7, 0x5d, 0x5a, 0x60, 0x52, 0x5b, 0x17, 0xf1, 0xd3, 0xda,
-    0xd1, 0xac, 0xff, 0xb3, 0x45, 0x46, 0x38, 0x42, 0xe2, 0xd3, 0xa8, 0x18,
-    0x94, 0x3d, 0x1f, 0x87, 0x84, 0x17, 0x08, 0xae, 0xcf, 0xa7, 0xc1, 0xe8,
-    0xff, 0x7a, 0xd3, 0xf1, 0x66, 0xe0, 0xfa, 0xf5, 0xa1, 0xc3, 0xd8, 0xf1,
-    0x4c, 0xd4, 0x75, 0xa7, 0xf8, 0xb2, 0xe6, 0x6c, 0xeb, 0xae, 0xa5, 0x38,
-    0xf5, 0xe5, 0xa1, 0xc3, 0xed, 0xe0, 0xad, 0xc3, 0xd9, 0xf8, 0xae, 0x51,
-    0xc4, 0xeb, 0x4f, 0xb1, 0xc7, 0xb3, 0xd6, 0x9f, 0xaf, 0x0b, 0x61, 0x05,
-    0x68, 0x64, 0xf7, 0xc6, 0x13, 0xb5, 0x09, 0x0d, 0x19, 0x78, 0xb7, 0xe9,
-    0x3c, 0xea, 0x00, 0xad, 0x39, 0xba, 0x4b, 0x4f, 0xbf, 0xab, 0xf5, 0xc5,
-    0xa4, 0x3d, 0x3c, 0x3f, 0x0d, 0x41, 0xd1, 0x09, 0x74, 0xae, 0xcf, 0xfe,
-    0xc0, 0xd1, 0xf3, 0x77, 0xe0, 0x30, 0x2b, 0x4d, 0xca, 0x5a, 0x67, 0x34,
-    0xb4, 0xfb, 0x2e, 0x09, 0x07, 0x0d, 0x67, 0xd1, 0x59, 0xf7, 0x33, 0x7f,
-    0x32, 0xd3, 0xe3, 0x55, 0x7f, 0xd7, 0xad, 0x1f, 0x13, 0x06, 0xd9, 0xd3,
-    0x0f, 0xff, 0x27, 0x9e, 0x0e, 0x72, 0x96, 0x9f, 0xf9, 0xb0, 0x9f, 0xcc,
-    0x22, 0x67, 0x56, 0x90, 0xf5, 0x14, 0x24, 0x83, 0xe2, 0x09, 0xfe, 0xc0,
-    0xe1, 0x31, 0x7e, 0xcb, 0x45, 0xee, 0x95, 0x65, 0xf2, 0xb1, 0xc3, 0x2b,
-    0x60, 0xc8, 0x49, 0x5a, 0x32, 0xa1, 0x86, 0xa7, 0x69, 0xaa, 0x87, 0x87,
-    0x6f, 0x25, 0xaf, 0x52, 0xa0, 0x21, 0x40, 0x52, 0xf3, 0x75, 0x0a, 0x9f,
-    0x4b, 0x04, 0xfe, 0x1c, 0xb7, 0x23, 0xcf, 0xfa, 0x69, 0x3f, 0xd9, 0xd2,
-    0x6f, 0x3f, 0x38, 0xb4, 0xfc, 0x40, 0xc0, 0xd3, 0xd6, 0x9f, 0x53, 0xfe,
-    0x04, 0x56, 0x9c, 0xf6, 0x02, 0xd3, 0xef, 0xae, 0x3d, 0x8d, 0xd2, 0x86,
-    0x46, 0x8e, 0x1b, 0x70, 0xaf, 0xc5, 0x1f, 0x46, 0xe7, 0xfe, 0x30, 0xbf,
-    0xaf, 0xb9, 0xa1, 0x62, 0x5a, 0x75, 0xd8, 0x85, 0x68, 0xe9, 0xf1, 0x1d,
-    0x12, 0x5f, 0x55, 0x10, 0x2c, 0xbc, 0xaa, 0x05, 0x24, 0x3e, 0x37, 0x8e,
-    0x8f, 0xcf, 0xf8, 0x6e, 0xf8, 0x3f, 0x76, 0x00, 0x19, 0x29, 0xfe, 0x2f,
-    0x6b, 0xfd, 0xfc, 0x2e, 0xad, 0x3f, 0xbf, 0xad, 0x66, 0x11, 0x8b, 0x43,
-    0x1f, 0x6f, 0x0e, 0xe7, 0xff, 0x09, 0x9f, 0x0a, 0x8c, 0xf9, 0xa0, 0x01,
-    0x96, 0x9f, 0xd5, 0xcd, 0xf4, 0xc5, 0xe5, 0xa3, 0x48, 0x80, 0xf2, 0x74,
-    0xf3, 0xf9, 0x97, 0xad, 0x3f, 0xcd, 0xb9, 0xeb, 0xd9, 0xbf, 0x96, 0x8d,
-    0xcf, 0x6c, 0x88, 0xa7, 0xf9, 0xad, 0xef, 0xf9, 0xd6, 0x75, 0x69, 0xff,
-    0xfd, 0xc6, 0xe8, 0x32, 0xe0, 0xeb, 0x58, 0x56, 0xa2, 0x02, 0xd3, 0xe6,
-    0xc2, 0xf5, 0xda, 0xd2, 0x3a, 0xd0, 0x73, 0x70, 0x45, 0x13, 0x9f, 0xf8,
-    0x56, 0x9d, 0xaa, 0xdf, 0xe1, 0xbd, 0xa2, 0x09, 0xff, 0xfb, 0x0a, 0xfd,
-    0x69, 0x81, 0x9c, 0x1e, 0xd3, 0xbe, 0x5a, 0x02, 0xab, 0x77, 0x78, 0x50,
-    0xf5, 0xf8, 0xe4, 0x5c, 0x3a, 0xf4, 0x35, 0x1d, 0x34, 0x86, 0x57, 0xfe,
-    0x32, 0xe3, 0x67, 0xff, 0xfb, 0xb7, 0xe0, 0xb9, 0x54, 0xfd, 0x31, 0xc3,
-    0xc6, 0x2b, 0x2d, 0x3c, 0x1e, 0x7f, 0x7a, 0xd3, 0xf8, 0x34, 0xfc, 0xbf,
-    0xf2, 0x5a, 0x6c, 0xbd, 0x8f, 0x5f, 0x09, 0x27, 0xef, 0x5d, 0xff, 0xcc,
-    0xb2, 0xd3, 0xfb, 0xad, 0xe1, 0x03, 0x3d, 0x69, 0xd7, 0x93, 0xd6, 0x86,
-    0x5e, 0x14, 0x3a, 0xf7, 0x27, 0x09, 0xa8, 0xa8, 0xa1, 0x79, 0xa2, 0xcf,
-    0x18, 0xfe, 0x63, 0x3f, 0x9e, 0xe6, 0x15, 0x73, 0x16, 0x9f, 0xd7, 0x29,
-    0xc0, 0xb1, 0x5e, 0xb4, 0xff, 0xbd, 0xe1, 0xeb, 0x5f, 0x5d, 0xb2, 0xd3,
-    0xff, 0xbb, 0x62, 0xcb, 0x85, 0x8d, 0xd6, 0xd2, 0xd3, 0xfa, 0x9c, 0xe6,
-    0x1f, 0x34, 0xb4, 0x61, 0xfd, 0x5c, 0x48, 0x9f, 0x84, 0xcf, 0x66, 0x1d,
-    0x69, 0xf6, 0x04, 0x7b, 0xa5, 0xa7, 0x7b, 0xdb, 0xad, 0x3f, 0xf6, 0xf6,
-    0x1e, 0x7c, 0x35, 0x9c, 0x13, 0xad, 0x2d, 0x00, 0xf9, 0x7c, 0x3b, 0x26,
-    0xbd, 0x16, 0x6e, 0xc2, 0x2e, 0x19, 0x50, 0xf6, 0x1a, 0x8c, 0x2e, 0x38,
-    0x47, 0xe8, 0x6f, 0xcf, 0xf8, 0x87, 0xee, 0xf9, 0x73, 0x76, 0xfa, 0xb4,
-    0xd5, 0xd5, 0xa7, 0xef, 0x0d, 0xe7, 0x6b, 0x2d, 0x01, 0x3c, 0x2e, 0x0a,
-    0xcd, 0x86, 0x96, 0x9e, 0x07, 0xd2, 0x7a, 0xd3, 0x02, 0x88, 0xdd, 0x78,
-    0x5e, 0x19, 0x10, 0xff, 0xae, 0x4d, 0xbb, 0x8b, 0x4f, 0xbe, 0xf8, 0x07,
-    0xc5, 0xa0, 0xe7, 0x82, 0x01, 0x89, 0xd6, 0x6d, 0x2d, 0x3f, 0xf1, 0xf4,
-    0x76, 0x0b, 0x77, 0xf6, 0x02, 0xd3, 0xfe, 0x6a, 0x2c, 0xf7, 0x85, 0xdf,
-    0x2d, 0x0c, 0x8b, 0xdc, 0x22, 0x11, 0xbf, 0xd1, 0x21, 0x97, 0x42, 0xdf,
-    0x29, 0x3f, 0x14, 0xf5, 0x18, 0x6f, 0xa3, 0x21, 0x9f, 0xfd, 0xac, 0x2f,
-    0xed, 0xcc, 0x3b, 0x95, 0x65, 0xa7, 0xee, 0x33, 0x99, 0x96, 0x5a, 0x7f,
-    0xe1, 0xe6, 0x38, 0x2e, 0x7e, 0x6b, 0xfd, 0x2d, 0x3e, 0x63, 0x5c, 0x67,
-    0x16, 0x87, 0x9f, 0x96, 0x92, 0x67, 0xfe, 0xfd, 0xc1, 0xe3, 0x6e, 0xf6,
-    0x71, 0x96, 0x9f, 0x06, 0x89, 0xb8, 0xb4, 0xff, 0xf6, 0xbd, 0xa1, 0x03,
-    0x3f, 0x59, 0x9b, 0xf9, 0x69, 0x0f, 0x0f, 0xd1, 0xd2, 0x59, 0xff, 0xf7,
-    0x7f, 0xef, 0x58, 0xb0, 0xc1, 0xe7, 0x33, 0xea, 0xd3, 0xf1, 0x50, 0x85,
-    0x89, 0x69, 0xeb, 0xd8, 0xd3, 0x2d, 0x3a, 0xe7, 0xfc, 0x5a, 0x18, 0xf0,
-    0x84, 0x8e, 0x7f, 0x9b, 0xef, 0x87, 0xa3, 0xef, 0xd6, 0x9f, 0xbf, 0xfb,
-    0xcc, 0xdf, 0x4b, 0x4f, 0xff, 0xff, 0xba, 0xde, 0x2a, 0xb0, 0xe9, 0xc1,
-    0xed, 0x9b, 0x5e, 0x6d, 0xdb, 0xee, 0x69, 0x69, 0xff, 0xff, 0xff, 0x6b,
-    0x59, 0xee, 0x51, 0xf5, 0xde, 0x8e, 0xfe, 0xaa, 0x33, 0x31, 0xcf, 0xfc,
-    0xce, 0xee, 0xcb, 0x43, 0x26, 0x41, 0x50, 0x83, 0x9e, 0x05, 0x6f, 0xa5,
-    0xa6, 0x75, 0xd5, 0xa3, 0x46, 0xe9, 0xd2, 0x29, 0xf0, 0xf2, 0xb3, 0x89,
-    0x6c, 0x68, 0xa1, 0xeb, 0xa2, 0x41, 0x4a, 0xde, 0x13, 0xc6, 0xe4, 0x4e,
-    0x42, 0xeb, 0xa5, 0x07, 0x57, 0xe3, 0x58, 0x08, 0x2e, 0x93, 0xa2, 0x8d,
-    0x47, 0x50, 0x83, 0x9f, 0x38, 0xce, 0x71, 0x96, 0x9c, 0xeb, 0xae, 0xa5,
-    0x3c, 0xff, 0x65, 0x92, 0xd8, 0xbf, 0x9f, 0x60, 0x44, 0x1a, 0x5d, 0xdf,
-    0xd1, 0xd3, 0xe4, 0x23, 0x18, 0x64, 0x66, 0x54, 0x2a, 0xe5, 0xa5, 0xa7,
-    0xd7, 0x9f, 0xfd, 0xfc, 0xb4, 0x74, 0xdd, 0xf8, 0x42, 0x75, 0xc6, 0xb2,
-    0xd0, 0xc6, 0xf8, 0x48, 0x67, 0xe2, 0xdf, 0x4e, 0x67, 0x96, 0x9f, 0xfd,
-    0xe7, 0x33, 0xb9, 0x47, 0x6e, 0x08, 0x56, 0x9f, 0xbf, 0x3e, 0x73, 0x7a,
-    0x5a, 0x08, 0xfd, 0xb4, 0x91, 0x3f, 0x37, 0xb8, 0xfd, 0x7e, 0xb4, 0xfa,
-    0xf3, 0x71, 0xcd, 0xd6, 0x9f, 0x0e, 0x9a, 0xf3, 0xae, 0xcf, 0xd9, 0xf3,
-    0x57, 0x41, 0xfa, 0xec, 0xfd, 0x9a, 0x9e, 0xbb, 0x3f, 0x67, 0xbf, 0x7e,
-    0x69, 0x76, 0x7e, 0xc0, 0x4f, 0x44, 0x88, 0xa7, 0xcd, 0x9a, 0xc2, 0x5d,
-    0x9f, 0xb0, 0xbb, 0x3f, 0x66, 0xaf, 0x2e, 0xcf, 0xd3, 0x96, 0xf2, 0x79,
-    0x1f, 0xcf, 0xe9, 0x13, 0xd9, 0x76, 0x20, 0x5d, 0x9f, 0xb0, 0xbb, 0x3f,
-    0x66, 0x03, 0x2e, 0xcf, 0xd9, 0xfe, 0xc0, 0x57, 0x72, 0xe6, 0x05, 0x76,
-    0x7e, 0xcf, 0xd9, 0xc1, 0xd7, 0xf7, 0xae, 0xcf, 0xd8, 0x02, 0x28, 0x88,
-    0x8b, 0x48, 0xb3, 0xdd, 0xbd, 0xbc, 0xbb, 0x3f, 0x61, 0x76, 0x7e, 0xe1,
-    0xaf, 0x99, 0xd7, 0x57, 0x67, 0xec, 0x3d, 0x58, 0x68, 0x4d, 0x32, 0x10,
-    0xbb, 0xc2, 0x6b, 0xa5, 0x07, 0x30, 0xd4, 0x2e, 0x7c, 0xbc, 0xe9, 0x34,
-    0xf6, 0x3d, 0x8c, 0x4d, 0x9f, 0xad, 0x91, 0x21, 0x3f, 0xec, 0xb0, 0x73,
-    0xae, 0xd7, 0x1c, 0x5a, 0x67, 0xde, 0x94, 0xf3, 0x95, 0x5d, 0x5a, 0x2f,
-    0x45, 0xce, 0xe8, 0x44, 0x7e, 0x68, 0x5e, 0x3a, 0xb9, 0x83, 0x53, 0x90,
-    0x33, 0xff, 0xe7, 0xf5, 0xae, 0x53, 0x8c, 0x1e, 0x31, 0xe9, 0xc5, 0xa7,
-    0xf1, 0xaa, 0xd0, 0xe9, 0xcc, 0x5a, 0x37, 0x44, 0x5f, 0x55, 0xe1, 0x97,
-    0xd3, 0x9f, 0x09, 0xfc, 0x1f, 0x18, 0x52, 0x74, 0x86, 0xa7, 0x3b, 0xff,
-    0x85, 0xc4, 0xff, 0xff, 0x0f, 0x2b, 0x8c, 0xfd, 0xb0, 0x0c, 0xfd, 0x07,
-    0x8d, 0xd5, 0xa7, 0xfc, 0x63, 0x6e, 0x4d, 0xce, 0x7f, 0x65, 0xa7, 0xff,
-    0x07, 0xad, 0x85, 0x8f, 0x1e, 0x65, 0xc5, 0xa7, 0xe2, 0xa3, 0x39, 0x4f,
-    0x5a, 0x73, 0xae, 0xba, 0x94, 0xef, 0xac, 0x04, 0xb6, 0x2f, 0xe7, 0xfa,
-    0x9f, 0xf7, 0xb9, 0x72, 0xba, 0xb4, 0xff, 0xfb, 0x98, 0xff, 0xa4, 0x59,
-    0x7b, 0x8f, 0x6e, 0xde, 0xb4, 0x12, 0x24, 0xfc, 0x77, 0x3c, 0xf6, 0x06,
-    0xeb, 0x4f, 0xc0, 0x62, 0xcd, 0xfc, 0xb4, 0xe2, 0xa0, 0x7c, 0x3c, 0xef,
-    0xa4, 0x53, 0xae, 0x37, 0x56, 0x87, 0xaa, 0xbb, 0x0b, 0x2e, 0x20, 0x1d,
-    0x20, 0x09, 0x65, 0x0c, 0x0f, 0x38, 0x5c, 0x36, 0x90, 0x16, 0x9f, 0xf0,
-    0xfb, 0x99, 0xaf, 0x9e, 0x1b, 0xd6, 0x9f, 0xe2, 0x1f, 0xee, 0x9d, 0x5d,
-    0xb7, 0x96, 0x87, 0xa2, 0x43, 0x82, 0x04, 0x81, 0x39, 0xd7, 0x5d, 0x4c,
-    0x42, 0x09, 0xf7, 0x6d, 0x55, 0x64, 0xc4, 0x20, 0xd8, 0xd6, 0xce, 0x75,
-    0xd7, 0x53, 0x10, 0x7a, 0x13, 0x10, 0x7b, 0x63, 0x5b, 0x23, 0xe2, 0x26,
-    0xec, 0xe5, 0x3f, 0xf7, 0x19, 0xe3, 0xec, 0xe5, 0x98, 0xeb, 0x43, 0x1f,
-    0x55, 0xc2, 0x89, 0xff, 0xd9, 0xc1, 0xef, 0x2b, 0x34, 0x35, 0x7a, 0xd3,
-    0xcd, 0xe6, 0x3a, 0xd0, 0x73, 0xe7, 0xf2, 0x3c, 0xfc, 0xed, 0x07, 0xfa,
-    0xfa, 0xb4, 0xf1, 0x0b, 0x18, 0xb4, 0xef, 0xac, 0x05, 0xa2, 0xf3, 0x7a,
-    0x72, 0x09, 0xf5, 0x9b, 0x8c, 0x74, 0xa7, 0xc5, 0x44, 0x58, 0x94, 0xd9,
-    0x64, 0xa6, 0x75, 0xd4, 0xa3, 0x0f, 0xdb, 0x44, 0xde, 0x23, 0x74, 0x56,
-    0x7f, 0x17, 0xd6, 0x07, 0x30, 0xd2, 0x5b, 0x1b, 0xc8, 0x64, 0xea, 0x70,
-    0x88, 0x5b, 0x6a, 0x1a, 0x93, 0xff, 0x30, 0x35, 0x98, 0x1a, 0x2a, 0x31,
-    0x69, 0xff, 0xe7, 0xe9, 0xd6, 0xef, 0x18, 0x78, 0xc4, 0x2b, 0x4f, 0xff,
-    0x68, 0xb3, 0x70, 0x56, 0xab, 0xa3, 0xb8, 0x16, 0x8d, 0xd1, 0x38, 0xea,
-    0x6c, 0x71, 0x30, 0x2a, 0x86, 0xec, 0xff, 0xff, 0x9a, 0xfd, 0xb5, 0xed,
-    0x6f, 0xf0, 0x38, 0x16, 0xae, 0xe1, 0x01, 0x69, 0xf1, 0xf4, 0xed, 0x6e,
-    0xb4, 0xb4, 0x14, 0x4c, 0x7d, 0x6f, 0x86, 0x5e, 0xc8, 0xc8, 0xc2, 0x06,
-    0x36, 0x1e, 0xca, 0x33, 0xa8, 0xd0, 0x75, 0x0c, 0x09, 0xce, 0xba, 0xea,
-    0x53, 0xc0, 0xa2, 0x0a, 0x5b, 0x17, 0xf3, 0xdd, 0xf8, 0x65, 0xda, 0xd3,
-    0xf7, 0xdc, 0xee, 0x63, 0x8b, 0x43, 0xd1, 0x0c, 0x26, 0x1a, 0x28, 0x9f,
-    0xfe, 0x2d, 0xfe, 0x6e, 0x06, 0x2b, 0x55, 0xe5, 0x4b, 0x4f, 0xff, 0xff,
-    0xf7, 0xb5, 0xf7, 0x5f, 0x39, 0x43, 0xe1, 0xe5, 0x87, 0xe3, 0xc7, 0x94,
-    0x5e, 0x7e, 0x77, 0x16, 0x9f, 0xfe, 0xc6, 0xd8, 0x24, 0xdf, 0xdb, 0x0c,
-    0x1e, 0xad, 0x3c, 0x6b, 0x80, 0xb8, 0xb4, 0x3c, 0xfd, 0x69, 0x3e, 0x7f,
-    0xec, 0xe8, 0x0e, 0x3a, 0xfb, 0xa6, 0xc5, 0xa7, 0x51, 0xbe, 0x96, 0x87,
-    0x9f, 0x15, 0x22, 0x4e, 0x0e, 0x1d, 0x69, 0xe0, 0x7b, 0x00, 0xb4, 0x09,
-    0xbc, 0xe8, 0xdc, 0x32, 0xa8, 0xc7, 0x97, 0xe2, 0x8d, 0x46, 0x18, 0x50,
-    0x83, 0xfd, 0x76, 0x7e, 0x37, 0xd0, 0x96, 0xef, 0x5a, 0x7f, 0xd5, 0xdb,
-    0xb1, 0xe6, 0x56, 0xe0, 0x5a, 0x7f, 0xfc, 0x3e, 0x63, 0xe6, 0xfe, 0x63,
-    0xfd, 0xed, 0x01, 0x69, 0xe1, 0x2a, 0x0a, 0xd3, 0xfd, 0xa6, 0xef, 0x9b,
-    0x60, 0x8a, 0xd0, 0xf4, 0x56, 0x85, 0x5b, 0x43, 0xf3, 0xf8, 0x4c, 0xf3,
-    0x71, 0xb4, 0xb4, 0xff, 0x8a, 0x9c, 0xe5, 0x77, 0xa2, 0x15, 0xa7, 0xbe,
-    0x04, 0x49, 0x68, 0xc4, 0xf7, 0xac, 0x60, 0x30, 0xed, 0xe9, 0x81, 0xcc,
-    0x9d, 0x3d, 0x9e, 0xef, 0x73, 0x4b, 0x4d, 0x8e, 0x2d, 0x27, 0xd1, 0xb7,
-    0xfa, 0x43, 0x3e, 0xe8, 0x73, 0x09, 0x69, 0xff, 0x8d, 0xc7, 0x38, 0xd7,
-    0x35, 0xc6, 0xdd, 0x68, 0xa3, 0xed, 0xd1, 0x2c, 0xff, 0x61, 0x77, 0x35,
-    0x83, 0xc5, 0xa7, 0xff, 0x9f, 0xe2, 0xca, 0xf1, 0x67, 0xbd, 0x8e, 0xad,
-    0x3f, 0xfb, 0xda, 0xc7, 0x38, 0xd7, 0x33, 0x9c, 0x65, 0xa7, 0xee, 0x04,
-    0x6e, 0x30, 0x56, 0x8c, 0x3f, 0x9a, 0x4b, 0x9e, 0xcf, 0x0e, 0x96, 0x9f,
-    0x8d, 0x97, 0x0a, 0xea, 0xbf, 0xf5, 0xa3, 0x47, 0xb5, 0xe2, 0x08, 0x0a,
-    0x77, 0x16, 0x21, 0xdc, 0xd4, 0xa1, 0x8d, 0xe7, 0xa9, 0xff, 0xe1, 0xd6,
-    0x07, 0xda, 0x13, 0x39, 0x44, 0x2b, 0x4f, 0xff, 0xe2, 0xf6, 0x70, 0x5b,
-    0xc2, 0x06, 0x7e, 0xce, 0xba, 0xea, 0x53, 0xc1, 0xcc, 0x31, 0x29, 0xea,
-    0x05, 0x79, 0x69, 0xfb, 0xda, 0x73, 0xf6, 0xea, 0xd3, 0x9e, 0x5f, 0xaa,
-    0x21, 0x99, 0xce, 0xba, 0xea, 0x53, 0xb0, 0xac, 0x96, 0xc5, 0xfc, 0xff,
-    0xb2, 0xfc, 0x0d, 0x3c, 0x9a, 0xf5, 0xa0, 0x07, 0xce, 0x45, 0x53, 0xd4,
-    0x46, 0xd9, 0x75, 0xad, 0x3f, 0x9e, 0x59, 0xef, 0x7f, 0x7a, 0xd3, 0xa8,
-    0xdd, 0x96, 0x9f, 0x60, 0x79, 0x46, 0xeb, 0x43, 0x2a, 0x48, 0xbd, 0x88,
-    0x24, 0x38, 0x41, 0xb9, 0x7f, 0x61, 0x5f, 0xc2, 0x1a, 0x2c, 0xfc, 0xd2,
-    0xe0, 0xec, 0xfe, 0x63, 0xe0, 0xf5, 0xc7, 0xad, 0x3c, 0x3e, 0x16, 0x5a,
-    0x7f, 0xfd, 0xca, 0xee, 0xb0, 0x4a, 0xbd, 0xa7, 0x58, 0x96, 0x9f, 0xdf,
-    0xe7, 0x40, 0x01, 0x25, 0xa7, 0xff, 0x9e, 0x21, 0xe7, 0xdd, 0x67, 0x6d,
-    0x55, 0x65, 0x44, 0x19, 0x3f, 0xfb, 0xb5, 0x73, 0x0a, 0xdc, 0x10, 0x7d,
-    0xf2, 0xd0, 0xc8, 0xa9, 0xfd, 0x76, 0x38, 0x8f, 0xef, 0x43, 0x6e, 0x6e,
-    0x7e, 0xb4, 0xff, 0xf9, 0xe2, 0x41, 0xe6, 0x6f, 0xf6, 0x8b, 0xc4, 0x15,
-    0xa7, 0x0b, 0xa6, 0xeb, 0x4f, 0xec, 0xb9, 0xaf, 0x79, 0x8e, 0xb4, 0x74,
-    0xf4, 0xf8, 0x3f, 0x02, 0x8e, 0x17, 0x05, 0xf5, 0x0a, 0x89, 0xfd, 0x77,
-    0x9a, 0xbb, 0xce, 0xb2, 0xd3, 0xff, 0xc4, 0xd6, 0xf9, 0xdc, 0x1f, 0xee,
-    0x9c, 0x35, 0x8b, 0x43, 0xd5, 0x9d, 0x04, 0x7c, 0x63, 0x50, 0xd4, 0x61,
-    0x3e, 0x35, 0x34, 0x6f, 0x3f, 0xdf, 0xf8, 0x1f, 0x9d, 0xb3, 0xcb, 0x4f,
-    0xfe, 0x2b, 0xfe, 0x38, 0x25, 0x81, 0xc2, 0x31, 0x69, 0xdf, 0x71, 0x96,
-    0x86, 0x3e, 0x7a, 0x4b, 0x9c, 0xdd, 0x71, 0x68, 0x66, 0x58, 0x40, 0x61,
-    0x27, 0x92, 0x93, 0x6c, 0xa0, 0x32, 0xa5, 0x79, 0x09, 0x4a, 0x96, 0xd8,
-    0x4c, 0xdf, 0xc2, 0x86, 0xec, 0x82, 0x7d, 0x47, 0xac, 0xd2, 0xd3, 0xff,
-    0xd6, 0x6d, 0x69, 0x8f, 0x9e, 0x1d, 0x72, 0x96, 0x9f, 0xc4, 0x4c, 0xf3,
-    0xb0, 0xad, 0x3f, 0xbc, 0x37, 0x07, 0xcf, 0x64, 0xa4, 0x75, 0xa7, 0xec,
-    0x23, 0x3a, 0xdb, 0x09, 0xe1, 0xfd, 0x33, 0x8c, 0x4c, 0x14, 0x53, 0x74,
-    0xe5, 0x3d, 0xdf, 0xf7, 0x7a, 0xd3, 0xf8, 0x9e, 0x58, 0x76, 0xb2, 0xd3,
-    0x8e, 0x1c, 0x5a, 0x18, 0xfb, 0xf0, 0x92, 0x8c, 0x27, 0xcc, 0x7f, 0x65,
-    0x96, 0x98, 0x6f, 0x5a, 0x38, 0x6f, 0x3c, 0x4d, 0x3e, 0x74, 0x42, 0x68,
-    0x56, 0x9f, 0xec, 0xf7, 0x30, 0xe5, 0x5e, 0x5a, 0x7e, 0xb8, 0x3d, 0xdd,
-    0x8d, 0xd6, 0x91, 0x04, 0xfa, 0x30, 0xda, 0x7f, 0xbd, 0xaf, 0xbd, 0x01,
-    0xc7, 0x4b, 0x43, 0x1f, 0x0f, 0xe4, 0xd2, 0xd2, 0xd3, 0xf3, 0x5f, 0x84,
-    0x26, 0x2d, 0x1d, 0x37, 0x9a, 0x10, 0x9f, 0xf9, 0x8a, 0xb8, 0xc0, 0xdb,
-    0xba, 0xd2, 0x50, 0x14, 0x61, 0x62, 0xf1, 0xc8, 0x67, 0xf5, 0x07, 0x5a,
-    0x6e, 0xbd, 0x69, 0xbf, 0xbd, 0x69, 0xfd, 0xbb, 0xf7, 0xd0, 0xf9, 0x96,
-    0x9c, 0x3b, 0xe9, 0x68, 0xc3, 0xd0, 0x13, 0x48, 0x14, 0x44, 0x71, 0xa2,
-    0x6c, 0xb2, 0xd3, 0xbb, 0x9a, 0x5b, 0xc5, 0xac, 0xff, 0xf0, 0x7e, 0x50,
-    0xe6, 0x9a, 0xfc, 0x21, 0x31, 0x69, 0xfd, 0xd3, 0xb6, 0xfe, 0xab, 0x2d,
-    0x18, 0x88, 0x21, 0x4f, 0x9f, 0x99, 0xc1, 0x3b, 0x38, 0xb4, 0xd8, 0xea,
-    0xd0, 0x94, 0xfd, 0xaf, 0xad, 0xd6, 0x3a, 0x50, 0x94, 0x25, 0x09, 0x42,
-    0x50, 0xf3, 0xe0, 0x10, 0xa0, 0x17, 0x7e, 0x15, 0x76, 0x14, 0x68, 0x2a,
-    0x6e, 0x62, 0x53, 0xf5, 0x57, 0x9c, 0x63, 0xa5, 0xf0, 0xb5, 0x95, 0xd2,
-    0x94, 0x25, 0x09, 0x43, 0xcb, 0x41, 0x0a, 0x84, 0xa1, 0x28, 0x4a, 0x12,
-    0x84, 0xa1, 0x28, 0xbc, 0xde, 0x04, 0x28, 0x42, 0x80, 0x15, 0xa0, 0xab,
-    0x81, 0x50, 0x94, 0x25, 0x0f, 0x2d, 0x34, 0x15, 0x09, 0x42, 0x50, 0x94,
-    0x25, 0x0f, 0x35, 0x00, 0x0a, 0xf0, 0x51, 0xa0, 0xa8, 0x4a, 0x12, 0x84,
-    0xa1, 0x28, 0xbc, 0xd4, 0x18, 0x15, 0xd0, 0xae, 0x05, 0x48, 0xc4, 0xa1,
-    0x28, 0x4a, 0x12, 0x84, 0xa0, 0x26, 0xa3, 0x70, 0xa0, 0x05, 0x7e, 0x15,
-    0x09, 0x42, 0x50, 0x94, 0xfb, 0x8c, 0x0d, 0x62, 0x50, 0x94, 0x3c, 0xf3,
-    0xac, 0x15, 0xc0, 0xaa, 0x0a, 0x01, 0x34, 0xac, 0x94, 0x25, 0x09, 0x42,
-    0x50, 0x94, 0x3c, 0xd4, 0x6e, 0x14, 0x21, 0x57, 0x02, 0xa1, 0x28, 0x4a,
-    0x12, 0x84, 0xa1, 0xe6, 0xa0, 0x21, 0x5c, 0x0a, 0x20, 0xa9, 0x71, 0x28,
-    0x4a, 0x12, 0x93, 0xd2, 0x84, 0xb7, 0x2c, 0x21, 0x28, 0x4a, 0x12, 0x84,
-    0xa2, 0xf3, 0xe6, 0x78, 0x51, 0x83, 0x56, 0x1a, 0x70, 0x28, 0x01, 0x5e,
-    0x0a, 0x96, 0x25, 0x09, 0x42, 0x52, 0x7a, 0x50, 0x96, 0xe5, 0x84, 0x25,
-    0x09, 0x43, 0x1e, 0x93, 0xc2, 0x84, 0x6b, 0xa3, 0x47, 0x0a, 0x84, 0xa1,
-    0x28, 0x4a, 0x12, 0x84, 0xa1, 0x8d, 0x96, 0xe1, 0x5d, 0x0a, 0x38, 0x51,
-    0x05, 0x42, 0x50, 0x94, 0x25, 0x1d, 0x2f, 0xb4, 0x15, 0xe0, 0xa8, 0x4a,
-    0x12, 0x84, 0xa0, 0xe5, 0xf1, 0x05, 0x78, 0x2a, 0x47, 0x4a, 0x12, 0x84,
-    0xa0, 0x05, 0xa7, 0xe1, 0x50, 0x94, 0x25, 0x09, 0x42, 0x50, 0xc6, 0xa1,
-    0xc0, 0xae, 0x05, 0x7e, 0x15, 0x0c, 0xbf, 0x49, 0x7b, 0x83, 0xcf, 0x42,
-    0x53, 0x8b, 0x76, 0x6b, 0xdd, 0x20, 0x59, 0x4d, 0xcf, 0x5c, 0x39, 0xec,
-    0x22, 0xce, 0x91, 0xc3, 0x8a, 0x65, 0x01, 0xd1, 0x3b, 0x69, 0x9b, 0xcc,
-    0x3f, 0xbc, 0xdc, 0x65, 0x75, 0x2e, 0xec, 0xb3, 0xe9, 0x21, 0xa4, 0x99,
-    0xf3, 0xc9, 0xb3, 0x49, 0x6c, 0x9a, 0xac, 0xe1, 0x63, 0xa5, 0x3c, 0x36,
-    0xae, 0xad, 0x38, 0x43, 0x8b, 0x4b, 0x6d, 0xd1, 0x1b, 0xd3, 0x9e, 0x0d,
-    0x78, 0x82, 0x4d, 0x71, 0x94, 0x83, 0xf6, 0x93, 0xf9, 0x3f, 0xb8, 0x2e,
-    0x87, 0xad, 0x7a, 0xd1, 0xb9, 0xf6, 0xb8, 0x73, 0x3e, 0xcc, 0x72, 0xbe,
-    0xad, 0x30, 0x19, 0x69, 0xfb, 0xb4, 0x5f, 0x58, 0x0b, 0x4d, 0x5d, 0x5a,
-    0x42, 0xb5, 0x8b, 0x59, 0x59, 0x69, 0x1d, 0x69, 0xae, 0xf6, 0x14, 0x4a,
-    0xf4, 0x57, 0x88, 0x54, 0x3d, 0xf4, 0x42, 0x7f, 0xb8, 0xc7, 0xc7, 0x18,
-    0xaf, 0x5a, 0x31, 0x12, 0x40, 0x5a, 0x9f, 0x8e, 0x37, 0x74, 0x40, 0x5a,
-    0x7f, 0xbe, 0xd0, 0x75, 0x87, 0x63, 0x75, 0xa7, 0x66, 0xee, 0xad, 0x3b,
-    0x70, 0x67, 0x4f, 0x64, 0x8f, 0x27, 0xa8, 0x34, 0x4b, 0x4f, 0xff, 0x37,
-    0xca, 0xef, 0x68, 0x0d, 0xb3, 0xae, 0xba, 0xb4, 0x32, 0x65, 0xb5, 0x08,
-    0x7d, 0x19, 0xfe, 0x3f, 0x17, 0xb6, 0x7a, 0x2f, 0x8c, 0xa8, 0x30, 0x9e,
-    0xb3, 0x46, 0xe4, 0x23, 0x1d, 0xa1, 0xb9, 0x7b, 0x90, 0xba, 0xe9, 0xb9,
-    0xe1, 0x59, 0xc2, 0x1a, 0xa5, 0x6d, 0x80, 0x90, 0xa3, 0x4f, 0xf4, 0x69,
-    0xf3, 0xe3, 0x89, 0x59, 0x96, 0x9f, 0x8f, 0xa1, 0x33, 0xce, 0xad, 0x3e,
-    0x6d, 0xf8, 0xcf, 0x5a, 0x3e, 0x9e, 0xb1, 0xa2, 0xf9, 0xb7, 0xf2, 0xd3,
-    0xef, 0x51, 0x7f, 0x8b, 0x49, 0xb0, 0xde, 0x90, 0xbc, 0xfd, 0xbe, 0x98,
-    0xd7, 0x59, 0x69, 0xf9, 0xe4, 0x2f, 0xe6, 0x2d, 0x3e, 0xbc, 0x7a, 0xcf,
-    0x5a, 0x3a, 0x7a, 0x44, 0x57, 0x3d, 0x81, 0x13, 0x16, 0x9f, 0xf7, 0x1b,
-    0xa0, 0x2c, 0x76, 0x80, 0xb4, 0xec, 0xc7, 0x16, 0x96, 0x70, 0xf6, 0x00,
-    0x7b, 0x3f, 0x7f, 0xdf, 0xcf, 0x44, 0xb4, 0xf1, 0xdb, 0x2f, 0x5a, 0x7d,
-    0x97, 0x09, 0xb7, 0x5a, 0x04, 0xf2, 0x74, 0x43, 0x3c, 0xc5, 0xeb, 0x2d,
-    0x26, 0xc4, 0xde, 0x7a, 0x42, 0x4f, 0x3a, 0x27, 0xf3, 0xbd, 0xd9, 0x0c,
-    0xf7, 0xf5, 0xd7, 0xad, 0x3c, 0xdf, 0xdd, 0x3a, 0x4a, 0x7c, 0xfd, 0x9d,
-    0x75, 0xd5, 0xa0, 0x8f, 0x4f, 0xf2, 0x79, 0xea, 0xf1, 0xfc, 0xb4, 0x05,
-    0x17, 0x18, 0xea, 0x02, 0x28, 0x65, 0xc4, 0x11, 0x7b, 0x3b, 0x1d, 0x12,
-    0x02, 0x3f, 0xaf, 0xe3, 0x16, 0x9d, 0x74, 0x1b, 0x69, 0xb4, 0xb4, 0xe7,
-    0x95, 0x2d, 0x2d, 0xee, 0x83, 0xc7, 0x62, 0xd9, 0xf9, 0xbb, 0x7b, 0x76,
-    0xf5, 0xa7, 0xdf, 0x83, 0x0a, 0xcb, 0x4e, 0xeb, 0x38, 0xb4, 0xfe, 0xf6,
-    0x7d, 0x67, 0x07, 0x4b, 0x43, 0xd1, 0x4b, 0xd2, 0xe3, 0x93, 0xdc, 0x1c,
-    0x9f, 0xe6, 0x1e, 0x31, 0xef, 0xc7, 0x56, 0x9f, 0x9b, 0x83, 0x7d, 0x12,
-    0xd3, 0xfd, 0x79, 0x63, 0xf9, 0x80, 0xd2, 0xd3, 0xfe, 0xc2, 0xdd, 0xfa,
-    0xef, 0xec, 0x05, 0xa7, 0xd9, 0xed, 0x61, 0x8b, 0x40, 0x9f, 0x31, 0xcf,
-    0xe7, 0x82, 0x16, 0xb8, 0xb4, 0xff, 0xf7, 0x18, 0xf6, 0x6f, 0x67, 0x6d,
-    0x55, 0x65, 0x45, 0xf1, 0x3a, 0xbb, 0x7a, 0xa2, 0xff, 0x86, 0x44, 0x1d,
-    0x96, 0xa7, 0x01, 0x8d, 0x2d, 0x3f, 0xe3, 0x43, 0x84, 0x13, 0x07, 0x3a,
-    0xb4, 0xfd, 0x5d, 0xdd, 0xf9, 0xe5, 0xa7, 0xfd, 0xed, 0x0f, 0x7c, 0x5f,
-    0xd3, 0xd6, 0x9d, 0x5b, 0x9a, 0x5a, 0x7e, 0xaf, 0x69, 0xb2, 0xf5, 0xa1,
-    0x91, 0x6b, 0x85, 0xb7, 0x0f, 0x9d, 0x1e, 0x9f, 0xfb, 0x58, 0x5e, 0xd7,
-    0xdb, 0x8d, 0x9b, 0xad, 0x38, 0x78, 0x2b, 0x4f, 0xb1, 0xfd, 0x0b, 0xd6,
-    0x9f, 0xfa, 0xe7, 0x8c, 0x62, 0x7e, 0x70, 0x4e, 0xb4, 0xff, 0x65, 0xce,
-    0x53, 0xdb, 0x09, 0x69, 0xfb, 0x1d, 0xfb, 0xca, 0xf2, 0xd3, 0xff, 0xef,
-    0x7d, 0x7b, 0x5c, 0x12, 0x07, 0x45, 0x8f, 0x89, 0x4f, 0x73, 0xee, 0xfe,
-    0x5a, 0x75, 0xee, 0x1b, 0xad, 0x17, 0xa3, 0x2f, 0x0b, 0xec, 0xad, 0xf9,
-    0x2c, 0xde, 0xc5, 0xa7, 0xdd, 0x1b, 0xe8, 0xea, 0x98, 0x4e, 0x7b, 0xdf,
-    0xb5, 0x2a, 0x61, 0x39, 0x80, 0xca, 0xa0, 0x4e, 0x7f, 0x15, 0x19, 0xe6,
-    0xe8, 0x15, 0x40, 0x9c, 0xfe, 0xd6, 0x70, 0x75, 0xfd, 0xea, 0x98, 0x4e,
-    0x6c, 0x0a, 0xa6, 0x13, 0x99, 0xd7, 0x57, 0x30, 0x9c, 0x62, 0x69, 0x7b,
-    0x9a, 0x09, 0x71, 0xc8, 0xb4, 0x7f, 0x71, 0x05, 0xd2, 0x29, 0x79, 0x33,
-    0x09, 0xb6, 0x3e, 0x79, 0x0e, 0xe9, 0xfb, 0xbb, 0x1e, 0x3c, 0x0a, 0xbe,
-    0xee, 0x0d, 0x51, 0x39, 0x22, 0xea, 0x30, 0x2f, 0x4a, 0x35, 0x9c, 0x40,
-    0x3a, 0xd3, 0xfc, 0xdf, 0xf8, 0x86, 0xe7, 0xd3, 0xad, 0x38, 0xb3, 0x58,
-    0x7a, 0xfd, 0x1b, 0x86, 0x5f, 0xf5, 0xbe, 0x13, 0xc1, 0x21, 0xb4, 0x29,
-    0x84, 0x8b, 0xa3, 0xbc, 0x87, 0x9e, 0x8f, 0xbd, 0x38, 0x6b, 0x72, 0x17,
-    0x53, 0xe0, 0xe7, 0x44, 0xc5, 0xa7, 0xee, 0x37, 0xd2, 0xdc, 0x0b, 0x4f,
-    0xcd, 0xec, 0x70, 0x4e, 0xb4, 0xfa, 0x9f, 0xec, 0xb2, 0xd3, 0xe2, 0xcf,
-    0xb8, 0xe2, 0xd3, 0xfd, 0xca, 0x3f, 0x05, 0xb7, 0x7a, 0xd3, 0xf7, 0xd2,
-    0x7d, 0xdd, 0x5e, 0xb4, 0x09, 0xf5, 0x00, 0xe2, 0x2f, 0x4c, 0x17, 0xa5,
-    0x84, 0x4d, 0xe8, 0x49, 0x4f, 0xfb, 0x2b, 0x8e, 0x09, 0x73, 0x37, 0x5a,
-    0x19, 0x96, 0x3b, 0x79, 0xf8, 0x4e, 0x32, 0x90, 0x40, 0x30, 0xab, 0x37,
-    0x27, 0xa8, 0xcd, 0x09, 0x0e, 0x7f, 0xf8, 0x4b, 0x0e, 0xdf, 0x4b, 0xf7,
-    0x96, 0x1d, 0x69, 0xfe, 0xe0, 0xbf, 0x94, 0xf1, 0x3a, 0xd3, 0xfe, 0xd0,
-    0x96, 0xef, 0xf0, 0xe8, 0x56, 0x8c, 0x3f, 0x4f, 0x1b, 0xcf, 0xb4, 0x76,
-    0x0b, 0x2d, 0x0f, 0x4c, 0x24, 0xf0, 0xc2, 0xf1, 0x0c, 0xff, 0xfe, 0x2c,
-    0xdf, 0x35, 0x45, 0xc1, 0x6f, 0x73, 0xfa, 0x3a, 0xd3, 0xf1, 0x7e, 0x71,
-    0xe3, 0x2d, 0x3f, 0xfe, 0xa2, 0xf5, 0x57, 0x09, 0xbd, 0xa7, 0x73, 0x8b,
-    0x4f, 0xfa, 0xfa, 0x2d, 0x7b, 0x82, 0xda, 0x5a, 0x77, 0x75, 0xa5, 0xc4,
-    0x07, 0x3f, 0xfb, 0xad, 0xc6, 0xf9, 0x9d, 0xb5, 0x55, 0x95, 0x10, 0x1e,
-    0xc6, 0xa6, 0x29, 0x19, 0xbf, 0x59, 0xa0, 0x09, 0xa1, 0xfa, 0x31, 0xf8,
-    0xc4, 0xe6, 0x46, 0x36, 0xf9, 0xdc, 0xa3, 0x75, 0xa7, 0x98, 0x17, 0x78,
-    0xb4, 0x00, 0xf0, 0x7c, 0x3d, 0x3c, 0x5e, 0x07, 0xeb, 0x4f, 0x8f, 0x74,
-    0x5d, 0x17, 0x41, 0xb2, 0xb4, 0xff, 0xfc, 0xfc, 0xd0, 0xf7, 0xa2, 0x7f,
-    0xbe, 0xe6, 0x3b, 0xe5, 0xa3, 0x11, 0x76, 0x24, 0x54, 0x79, 0x3f, 0xff,
-    0xd4, 0xfc, 0x27, 0x1f, 0x9b, 0xbf, 0xeb, 0x03, 0x67, 0x5d, 0x75, 0x28,
-    0x64, 0xdd, 0xf9, 0x0d, 0xd2, 0x2d, 0x9f, 0x01, 0xbd, 0x86, 0xeb, 0x4f,
-    0xe6, 0xce, 0xda, 0xaa, 0xca, 0x88, 0x26, 0x7f, 0x9b, 0xd9, 0xdb, 0x55,
-    0x59, 0x51, 0x7c, 0xce, 0x2c, 0xd0, 0x51, 0x01, 0x63, 0xd9, 0x09, 0x23,
-    0x72, 0xe4, 0x2a, 0x67, 0xf7, 0xfc, 0xbb, 0xe0, 0xdb, 0x8b, 0x4f, 0xfa,
-    0xfa, 0xde, 0xef, 0x3c, 0x55, 0x71, 0x69, 0xff, 0x60, 0x59, 0xed, 0xcc,
-    0x05, 0x2d, 0x39, 0xd7, 0x5d, 0x4a, 0x7d, 0xcc, 0xb5, 0x75, 0x2d, 0x8b,
-    0xf9, 0xff, 0xfc, 0xe7, 0x5a, 0xe7, 0xc3, 0x2b, 0xe7, 0xd7, 0x35, 0xf3,
-    0x37, 0xf2, 0xd1, 0xe4, 0x52, 0xfd, 0x36, 0x8b, 0xd3, 0x67, 0x3a, 0x19,
-    0x43, 0xfe, 0x7f, 0xc7, 0x6d, 0xf4, 0x59, 0x7f, 0xd7, 0xad, 0x3f, 0x8c,
-    0xf8, 0xe3, 0xdb, 0xba, 0x5a, 0x2f, 0x3f, 0x81, 0x41, 0x9f, 0x8d, 0xf1,
-    0xfc, 0x6e, 0xad, 0x3f, 0xfb, 0x72, 0xf9, 0x6e, 0x08, 0x00, 0xdd, 0x7a,
-    0xd0, 0xc7, 0xf7, 0xf4, 0xbe, 0x7f, 0xdf, 0xe9, 0xb0, 0xbc, 0x6d, 0x3b,
-    0x65, 0xa7, 0xff, 0xfb, 0x57, 0xe3, 0xa5, 0x81, 0xe8, 0xff, 0x78, 0x78,
-    0xc5, 0x7a, 0xd3, 0x9d, 0x75, 0xd4, 0xa7, 0xf7, 0xd0, 0x31, 0x66, 0xfe,
-    0x4b, 0x62, 0xfe, 0x7f, 0xfe, 0xba, 0x7e, 0x5b, 0x82, 0x10, 0xe3, 0xbf,
-    0x3d, 0xac, 0xbd, 0x68, 0xe2, 0x2a, 0xbf, 0x44, 0x81, 0x4d, 0x5a, 0xa3,
-    0x32, 0x87, 0xae, 0x7e, 0x04, 0xb8, 0x63, 0x9e, 0xec, 0x2b, 0x8f, 0x09,
-    0xd2, 0x23, 0xf4, 0x73, 0x53, 0xfe, 0xc1, 0x2b, 0xe8, 0xbd, 0x87, 0x5a,
-    0x7f, 0xdc, 0x17, 0x43, 0xcc, 0xf5, 0xde, 0x2d, 0x3e, 0xe6, 0x79, 0xc7,
-    0xad, 0x3f, 0xec, 0xf3, 0x77, 0x5c, 0x62, 0xf2, 0xe2, 0x08, 0x9f, 0xcd,
-    0x9d, 0xb5, 0x55, 0x95, 0x10, 0x46, 0xc7, 0x93, 0x3f, 0x57, 0x3b, 0xd1,
-    0x75, 0x69, 0xf8, 0xdc, 0x2e, 0xd1, 0x3d, 0x68, 0x23, 0xdd, 0xfc, 0xb6,
-    0x38, 0x99, 0xf8, 0x1c, 0x4a, 0x15, 0x93, 0xf7, 0x33, 0xde, 0x13, 0xad,
-    0x3f, 0x7b, 0xee, 0x72, 0xb7, 0x5a, 0x4d, 0xb9, 0xed, 0x91, 0x64, 0xcc,
-    0x62, 0xd3, 0xfe, 0xce, 0x30, 0xf8, 0xb3, 0x82, 0xb4, 0xd4, 0xef, 0xc3,
-    0xd0, 0xf0, 0xb4, 0x3d, 0x14, 0xe4, 0xef, 0x3f, 0xdc, 0x6e, 0xf8, 0x9b,
-    0x37, 0x5a, 0x7f, 0xff, 0x86, 0xf6, 0x7e, 0xbb, 0xd1, 0xdd, 0xc7, 0xd7,
-    0x4f, 0x9b, 0xad, 0x3d, 0xee, 0x61, 0x05, 0x14, 0x1c, 0x37, 0x9f, 0xbe,
-    0x9f, 0x4e, 0xd6, 0xeb, 0x43, 0x1f, 0x57, 0x8e, 0x67, 0x85, 0xc1, 0x75,
-    0x69, 0xff, 0xf7, 0xf7, 0x93, 0x67, 0x36, 0x6f, 0x67, 0x3f, 0xea, 0xd3,
-    0xde, 0xd7, 0xdd, 0x04, 0xfe, 0x7e, 0x91, 0x4f, 0xa9, 0xe4, 0x2c, 0xb4,
-    0x61, 0xf1, 0x1c, 0xfa, 0x7e, 0xb7, 0x06, 0xec, 0x4c, 0x5a, 0x78, 0xdf,
-    0x99, 0x7a, 0xd3, 0xf9, 0x83, 0x9e, 0x1e, 0x7e, 0xb4, 0x8e, 0xc7, 0xae,
-    0x12, 0x59, 0xff, 0xff, 0x1e, 0x88, 0x0f, 0x1d, 0x7e, 0x7e, 0x0b, 0x7b,
-    0x9f, 0xd1, 0xd6, 0x9f, 0xbb, 0x5a, 0xef, 0xc3, 0x75, 0xa6, 0x1f, 0x52,
-    0x27, 0xbf, 0x6c, 0x80, 0xa6, 0xf4, 0x30, 0x87, 0xa8, 0x62, 0xcf, 0xfc,
-    0x1f, 0xfd, 0xa6, 0x26, 0x0e, 0x38, 0xb4, 0xf8, 0x18, 0x76, 0xe2, 0xd0,
-    0x27, 0xd4, 0x48, 0x93, 0xbb, 0xf7, 0x4b, 0x4c, 0xc6, 0xdd, 0x69, 0xff,
-    0x51, 0x5b, 0x3b, 0x6a, 0xab, 0x2a, 0x21, 0x18, 0x64, 0x40, 0x80, 0x7b,
-    0xf1, 0xb9, 0xff, 0xcd, 0x9b, 0xfd, 0xf0, 0x97, 0xef, 0xcd, 0x2d, 0x3f,
-    0xef, 0xb9, 0xca, 0x3e, 0xce, 0xba, 0xea, 0xd3, 0xff, 0xec, 0xb7, 0x18,
-    0x82, 0x43, 0x7e, 0x10, 0x98, 0xb4, 0xd5, 0x57, 0xa2, 0x59, 0xe8, 0x90,
-    0x14, 0xc3, 0xdc, 0x87, 0x0c, 0xff, 0x05, 0xb5, 0xa6, 0xbf, 0x1d, 0x5a,
-    0x30, 0xf8, 0xe8, 0xaa, 0x73, 0xae, 0xba, 0x94, 0xff, 0x60, 0x2b, 0xb9,
-    0x73, 0x02, 0x96, 0xc5, 0xfc, 0xce, 0xba, 0x94, 0xe7, 0x5d, 0x75, 0x29,
-    0xfa, 0xaf, 0x0f, 0x1b, 0x49, 0x6c, 0x5f, 0xc1, 0x22, 0xf1, 0xd4, 0x8b,
-    0xb3, 0x79, 0xf5, 0x84, 0x3f, 0x4e, 0x96, 0xc6, 0xce, 0x73, 0xae, 0xba,
-    0x94, 0xed, 0x37, 0x52, 0xd8, 0xbf, 0x90, 0x05, 0x10, 0x9e, 0x59, 0x9f,
-    0x82, 0x4c, 0xfa, 0xb2, 0xd3, 0xe0, 0x8d, 0xc6, 0x0a, 0xd3, 0xd8, 0x58,
-    0x6e, 0xb4, 0xbe, 0xf4, 0xf2, 0x8e, 0x51, 0x3f, 0xf7, 0x29, 0xe5, 0x46,
-    0x38, 0x42, 0xe2, 0xd3, 0xf7, 0x32, 0xe6, 0x7b, 0x4b, 0x45, 0x8f, 0xcb,
-    0xc8, 0x91, 0xd4, 0xcc, 0xf8, 0xea, 0x50, 0x9c, 0x86, 0x4e, 0x43, 0x23,
-    0x5b, 0x9d, 0xb9, 0xb6, 0x1b, 0x2b, 0x4f, 0xfe, 0xc3, 0x7a, 0x20, 0x65,
-    0x9b, 0x8c, 0x75, 0xa7, 0xeb, 0x0e, 0xb8, 0x2e, 0x25, 0x3f, 0x8b, 0x37,
-    0x7e, 0x84, 0xc5, 0xa7, 0xaa, 0xba, 0x62, 0xd1, 0xf0, 0xf5, 0x2f, 0x33,
-    0x9e, 0x6a, 0x3d, 0xc4, 0xa7, 0xee, 0x61, 0xcf, 0x4f, 0x5a, 0x73, 0xae,
-    0xba, 0x94, 0xfe, 0x2f, 0x70, 0x58, 0xaf, 0x4b, 0x62, 0xfe, 0x7b, 0xeb,
-    0x03, 0x1e, 0x88, 0xcc, 0x4b, 0x96, 0x59, 0x1d, 0x07, 0x85, 0x74, 0xfe,
-    0x6f, 0xbd, 0xe8, 0xfb, 0x4b, 0x43, 0x2a, 0x61, 0x79, 0x4e, 0xe9, 0x23,
-    0x08, 0x1e, 0x46, 0x1a, 0x45, 0xb3, 0xe0, 0x60, 0xf0, 0xc5, 0xa7, 0xff,
-    0xb2, 0xcc, 0x55, 0xed, 0x07, 0xfa, 0xeb, 0xd6, 0x8d, 0xcf, 0xd4, 0xe4,
-    0xf3, 0xac, 0xda, 0x5a, 0x7f, 0xef, 0xaf, 0xce, 0x57, 0x07, 0xbd, 0x65,
-    0xa3, 0x0f, 0x7c, 0x03, 0x73, 0xe6, 0xf6, 0xae, 0x62, 0xd3, 0xef, 0xfa,
-    0x67, 0x05, 0x68, 0x64, 0x7a, 0x14, 0x20, 0xbc, 0x43, 0x76, 0x51, 0x3f,
-    0xfc, 0x37, 0x30, 0x82, 0x54, 0xee, 0x15, 0x18, 0xb4, 0xff, 0xff, 0x07,
-    0x82, 0xee, 0x1a, 0x13, 0xd7, 0xb5, 0xfb, 0xf3, 0x7f, 0x2d, 0x18, 0x8b,
-    0x8a, 0x4e, 0x86, 0x6f, 0x38, 0x6f, 0x36, 0x7c, 0x7e, 0xe1, 0x8f, 0x83,
-    0x27, 0x83, 0x0c, 0x7b, 0xb1, 0xd8, 0xc7, 0x00, 0xe4, 0x66, 0xfd, 0x8c,
-    0xb0, 0xf0, 0xfc, 0xe4, 0x73, 0x75, 0x0a, 0x30, 0x42, 0x84, 0xa3, 0xa2,
-    0xd4, 0xb4, 0x2f, 0x4a, 0x89, 0xfe, 0x3c, 0xb7, 0x61, 0xf7, 0x3a, 0xe3,
-    0x12, 0xd3, 0xff, 0xd8, 0x5b, 0x78, 0xc1, 0xdf, 0x5c, 0xc0, 0x52, 0xd0,
-    0xf3, 0xec, 0x08, 0xe4, 0xfe, 0xa2, 0xb6, 0x7b, 0x82, 0xb4, 0x6e, 0x7a,
-    0x47, 0x22, 0x98, 0xdb, 0x4d, 0xba, 0xd3, 0xf7, 0x1c, 0x1e, 0x09, 0xd6,
-    0x9f, 0xf1, 0x37, 0xb9, 0x40, 0xad, 0xf4, 0xb4, 0xe7, 0x3f, 0xea, 0xd3,
-    0xfe, 0xa1, 0xee, 0x6f, 0xb3, 0xae, 0xba, 0xb4, 0x51, 0xf0, 0x68, 0x7a,
-    0x7f, 0xf8, 0x99, 0xff, 0x3e, 0xf8, 0x4b, 0xf7, 0xe6, 0x96, 0x8c, 0x4c,
-    0xf6, 0xc5, 0xbc, 0x84, 0xe8, 0x08, 0x67, 0xf3, 0x13, 0xcb, 0x30, 0x0b,
-    0x4f, 0xd9, 0xdd, 0x13, 0x5e, 0xb4, 0xfd, 0x5e, 0xe5, 0x10, 0x16, 0x9f,
-    0xf5, 0x7b, 0x1c, 0xa6, 0x26, 0x71, 0x69, 0x0f, 0x4f, 0x9f, 0x85, 0x70,
-    0xf4, 0x5d, 0x5a, 0x12, 0x73, 0xff, 0xd9, 0xe6, 0x2b, 0x67, 0xb8, 0x3d,
-    0x05, 0x96, 0x9f, 0xcc, 0x7d, 0x6a, 0x8a, 0xf5, 0xa7, 0xd5, 0xac, 0x2f,
-    0x2d, 0x3b, 0xd4, 0x6e, 0xb4, 0xfe, 0xf7, 0x07, 0x60, 0x50, 0xad, 0x01,
-    0x47, 0xa7, 0x13, 0x48, 0xcb, 0xc4, 0xbf, 0x8f, 0x4f, 0xef, 0xc0, 0xdc,
-    0x1a, 0x7a, 0xd3, 0xfd, 0x6c, 0xf3, 0x5c, 0x12, 0x02, 0xd3, 0xff, 0xf7,
-    0xed, 0xed, 0x61, 0x7c, 0xeb, 0x08, 0x4a, 0x9e, 0xb4, 0x0a, 0x24, 0x88,
-    0xe2, 0x7f, 0xfe, 0x2c, 0xd7, 0xff, 0x33, 0x94, 0x58, 0xe3, 0xdb, 0x75,
-    0xa7, 0xfd, 0x9a, 0xff, 0x3b, 0x6a, 0xab, 0x2a, 0x20, 0x69, 0xef, 0x72,
-    0x9f, 0xf1, 0x14, 0xc4, 0xb9, 0x3e, 0x0d, 0xd5, 0x41, 0xba, 0x96, 0x86,
-    0x4c, 0xcf, 0x21, 0x8f, 0x47, 0x73, 0xfb, 0x37, 0xf0, 0x73, 0x0c, 0x5a,
-    0x7e, 0xcf, 0x31, 0x08, 0x16, 0x9f, 0xf5, 0x77, 0x08, 0x1a, 0xf6, 0xb7,
-    0x5a, 0x7f, 0xff, 0xfe, 0xcf, 0x72, 0x88, 0xcf, 0x9a, 0xed, 0x57, 0xae,
-    0x60, 0x7e, 0x61, 0xe8, 0xb7, 0x7a, 0xe2, 0x0b, 0x9f, 0xf5, 0x51, 0x96,
-    0xa0, 0xfc, 0x31, 0xd5, 0xc4, 0x17, 0x3f, 0xf7, 0x07, 0x82, 0xc5, 0xef,
-    0x86, 0x3a, 0xb8, 0x82, 0xe7, 0xf3, 0x09, 0x7b, 0xe1, 0x8e, 0xae, 0x20,
-    0xb9, 0xf8, 0xf8, 0x1f, 0x86, 0x3a, 0xb8, 0x82, 0xe7, 0xff, 0xfa, 0x88,
-    0x84, 0xff, 0x35, 0x6e, 0x0f, 0x44, 0xcb, 0xf1, 0xd5, 0xc4, 0x17, 0x36,
-    0xff, 0x02, 0x9c, 0xbd, 0x93, 0xfa, 0xa7, 0x48, 0x44, 0x7d, 0x0c, 0xab,
-    0x1f, 0x87, 0xc5, 0x28, 0xc6, 0x7f, 0x0b, 0x19, 0xaf, 0x6b, 0x75, 0xa7,
-    0xab, 0xa0, 0xa5, 0xa7, 0xfe, 0xe0, 0xf0, 0x58, 0xbd, 0xf0, 0xc7, 0x57,
-    0x10, 0x5c, 0xff, 0x39, 0xab, 0x0d, 0xff, 0x0c, 0x75, 0x71, 0x05, 0xcf,
-    0xbd, 0xa6, 0x3f, 0xcb, 0x22, 0x7f, 0xea, 0x9c, 0xff, 0xef, 0x96, 0xe0,
-    0xd9, 0xbd, 0xaf, 0x86, 0x3a, 0xb8, 0x82, 0xe7, 0xff, 0xfe, 0x22, 0x13,
-    0xfc, 0xff, 0x3e, 0x6a, 0xdc, 0x1e, 0x89, 0x97, 0xe3, 0xab, 0x88, 0x2e,
-    0x31, 0x32, 0x5d, 0xd1, 0x29, 0x76, 0x7f, 0xb8, 0x3d, 0x13, 0x2f, 0xc7,
-    0x57, 0x10, 0x5c, 0xff, 0xf5, 0x56, 0xef, 0xd7, 0x04, 0x21, 0x6e, 0xb2,
-    0x53, 0xfe, 0xc7, 0xbf, 0xfd, 0x74, 0xaf, 0xbb, 0x5c, 0x41, 0x71, 0x64,
-    0x72, 0xf5, 0x1f, 0x49, 0xd3, 0xfe, 0xb0, 0xf7, 0xd4, 0x0d, 0x7c, 0x75,
-    0x71, 0x05, 0xcf, 0xdc, 0x1e, 0x70, 0x40, 0xa8, 0x02, 0xe7, 0xd8, 0x0f,
-    0x86, 0x3a, 0xb8, 0x82, 0xe6, 0xcf, 0x58, 0xfc, 0x78, 0x73, 0x1b, 0xa3,
-    0xb3, 0x50, 0xbf, 0x9f, 0x8f, 0x81, 0xf8, 0x63, 0xab, 0x88, 0x2e, 0x7f,
-    0xd6, 0xe0, 0xf4, 0x4c, 0xbf, 0x1d, 0x5c, 0x41, 0x73, 0x67, 0xca, 0x44,
-    0x5e, 0x8f, 0xa7, 0xf7, 0xe2, 0x7a, 0x2d, 0xde, 0xb8, 0x82, 0xe7, 0xfd,
-    0x83, 0x73, 0x0b, 0x03, 0x4f, 0x5c, 0x41, 0x67, 0x3c, 0x08, 0x0a, 0xef,
-    0xef, 0x4d, 0xc0, 0x68, 0x51, 0xf2, 0x6a, 0x31, 0x5f, 0x46, 0x39, 0xfc,
-    0x2d, 0x1d, 0x6f, 0x98, 0x0c, 0xa8, 0x82, 0xf6, 0x44, 0x64, 0xd5, 0x65,
-    0xa5, 0xa0, 0x1e, 0x57, 0x8d, 0x62, 0xf6, 0x50, 0xf8, 0x4c, 0xc1, 0x49,
-    0xc4, 0x9f, 0xf6, 0x3f, 0x94, 0xf3, 0x46, 0xbf, 0xbd, 0x69, 0xfa, 0x9e,
-    0xd7, 0x2b, 0x8b, 0x4f, 0x6f, 0xa6, 0xdd, 0x69, 0xc7, 0x67, 0xad, 0x3e,
-    0xc0, 0xf3, 0xf7, 0x56, 0x8f, 0x87, 0xcf, 0x44, 0x64, 0x37, 0x38, 0x35,
-    0xe5, 0xa3, 0xa7, 0x95, 0x45, 0xf3, 0x86, 0xef, 0x16, 0x9d, 0x5d, 0x02,
-    0xd2, 0xdd, 0x8d, 0xc7, 0x87, 0x67, 0xec, 0xbe, 0xb8, 0xc6, 0xeb, 0x43,
-    0x27, 0x1a, 0x30, 0xde, 0xa5, 0x92, 0x27, 0x9f, 0xfe, 0xc2, 0x26, 0xbc,
-    0xfc, 0x1e, 0xf6, 0x9e, 0xb4, 0xea, 0xed, 0xeb, 0x4c, 0x06, 0x5a, 0x78,
-    0x58, 0xf8, 0xb4, 0x2d, 0x3f, 0x51, 0x9e, 0x6e, 0x81, 0x68, 0x09, 0xb7,
-    0x20, 0xa9, 0xff, 0xfc, 0xc2, 0x12, 0x6f, 0xed, 0xec, 0xb0, 0x5a, 0xdf,
-    0x4e, 0xb4, 0xc0, 0x65, 0xa6, 0x63, 0x16, 0x9f, 0xec, 0xf6, 0x98, 0xff,
-    0x71, 0xc5, 0xa7, 0xf6, 0xb3, 0x83, 0xaf, 0xef, 0x5a, 0x67, 0x5d, 0x4a,
-    0x7f, 0x8b, 0x2e, 0x53, 0xf4, 0x21, 0x5a, 0x2c, 0x9f, 0x88, 0x8e, 0x74,
-    0x54, 0xea, 0xdc, 0x20, 0x03, 0x0d, 0xd2, 0x2a, 0x42, 0xda, 0x3a, 0x74,
-    0xd3, 0xe8, 0xc4, 0xe7, 0x5d, 0x75, 0x29, 0x1d, 0x2d, 0x8b, 0xf9, 0xf5,
-    0x39, 0x55, 0xd4, 0xb6, 0x46, 0xf7, 0xd8, 0x5f, 0x4f, 0xed, 0xfc, 0xd9,
-    0xcc, 0xbd, 0x68, 0x66, 0xd9, 0x1d, 0xe4, 0x79, 0x1b, 0x01, 0x88, 0x5b,
-    0xc3, 0xa4, 0x63, 0x1c, 0xea, 0x57, 0x23, 0xf7, 0xaa, 0x52, 0x91, 0x1f,
-    0x6a, 0x3d, 0x1f, 0x1f, 0xff, 0x2c, 0x72, 0xe2, 0x6c, 0xea, 0xb6, 0x2d,
-    0x36, 0x3a, 0xb4, 0xcd, 0xe5, 0xa2, 0xf3, 0x57, 0x61, 0x69, 0x1d, 0x68,
-    0xc3, 0x65, 0xe2, 0x29, 0xf8, 0xed, 0x7f, 0xb2, 0xcb, 0x4f, 0x61, 0xf3,
-    0xcb, 0x4f, 0xff, 0xfd, 0x6a, 0x73, 0xf7, 0xff, 0x6f, 0x9c, 0x1f, 0x79,
-    0xb7, 0x6b, 0xdb, 0x4b, 0x4f, 0xff, 0xf1, 0xb9, 0x55, 0x5c, 0x67, 0xf1,
-    0xbb, 0x7b, 0x7b, 0x54, 0xf5, 0xa7, 0x0e, 0xee, 0x2d, 0x3e, 0xcc, 0xbf,
-    0xfd, 0x2d, 0x3f, 0xf7, 0x3f, 0xbf, 0xfd, 0xb8, 0x36, 0xae, 0xad, 0x3f,
-    0xdc, 0xad, 0x70, 0x6f, 0xa2, 0x5a, 0x7a, 0xaf, 0xfa, 0xf5, 0xa2, 0xeb,
-    0x55, 0x5a, 0xce, 0xf7, 0x90, 0x6e, 0x5b, 0xd2, 0x0a, 0x78, 0x03, 0x4e,
-    0x87, 0x7c, 0x51, 0xf5, 0x20, 0xd1, 0xbc, 0xfc, 0x5f, 0x84, 0xf4, 0xf5,
-    0xa7, 0xff, 0x3c, 0x9b, 0xe1, 0xc9, 0x8c, 0xf0, 0xde, 0xb4, 0xfa, 0x8f,
-    0x9c, 0x3a, 0xd1, 0xb9, 0xf8, 0xf9, 0x2e, 0x77, 0xba, 0xcb, 0x4f, 0xed,
-    0x7a, 0xe6, 0x16, 0x05, 0x68, 0x64, 0xc3, 0xc6, 0x13, 0xc7, 0x23, 0xa1,
-    0xb9, 0xd5, 0xf3, 0xea, 0xd3, 0xff, 0xc4, 0xff, 0x98, 0x11, 0xd6, 0xfe,
-    0xfe, 0xb4, 0xb4, 0xfd, 0xd3, 0x35, 0xa1, 0x71, 0x69, 0xf7, 0xce, 0x37,
-    0x5e, 0xb4, 0x7c, 0x46, 0x4e, 0x0f, 0xd2, 0x93, 0xa5, 0xf3, 0xf5, 0xee,
-    0x3e, 0xeb, 0xed, 0xeb, 0x4f, 0x1f, 0x2b, 0x8b, 0x4c, 0xfb, 0xd6, 0x9f,
-    0x73, 0x05, 0xfa, 0x5a, 0x7f, 0xfb, 0x8d, 0xf7, 0x6f, 0x15, 0x03, 0x5a,
-    0x60, 0x25, 0x3f, 0x81, 0x9d, 0xb5, 0x55, 0x97, 0x10, 0x24, 0xef, 0x0d,
-    0xeb, 0x4e, 0xbe, 0x89, 0x68, 0x7a, 0x3b, 0x02, 0x4d, 0xd5, 0x13, 0x9f,
-    0x78, 0x72, 0x7e, 0x2b, 0x51, 0x9c, 0x15, 0xa6, 0x34, 0xf5, 0xa7, 0xbd,
-    0x7d, 0x12, 0xd3, 0x8a, 0x8c, 0x5a, 0x7b, 0x7d, 0x57, 0x96, 0x8b, 0xcf,
-    0xdb, 0x06, 0x2c, 0x43, 0xc1, 0xb9, 0xfc, 0x54, 0xee, 0xb4, 0xc0, 0x5a,
-    0x75, 0xdd, 0x18, 0xb4, 0xff, 0x31, 0xdf, 0x97, 0xe7, 0xf7, 0x4a, 0xd1,
-    0x87, 0xba, 0x23, 0xf3, 0x9d, 0x75, 0xd5, 0xd5, 0xf5, 0x3a, 0x88, 0x29,
-    0xab, 0xe9, 0xb1, 0xac, 0x9f, 0x63, 0xff, 0x63, 0x16, 0x80, 0xa6, 0x79,
-    0xd8, 0x47, 0x81, 0x33, 0xc7, 0x33, 0xff, 0xec, 0x21, 0x33, 0x6d, 0x7b,
-    0x9f, 0xd3, 0xde, 0xcb, 0x45, 0xe8, 0x99, 0x31, 0x0e, 0x7b, 0x03, 0x4f,
-    0x5a, 0x7d, 0x44, 0x42, 0x75, 0xa7, 0xc2, 0x7a, 0x2c, 0x5a, 0x2e, 0x85,
-    0xce, 0x36, 0x36, 0x79, 0x06, 0x46, 0x06, 0x62, 0x50, 0xc2, 0x8a, 0xa5,
-    0x08, 0x80, 0x94, 0x88, 0x2e, 0xc9, 0x27, 0xc3, 0xe6, 0xf6, 0x92, 0x9e,
-    0xb3, 0x7b, 0x49, 0x4c, 0xeb, 0xa9, 0x43, 0xcf, 0x7f, 0x09, 0x9d, 0x21,
-    0x9b, 0x1d, 0x4b, 0x63, 0x5f, 0x3f, 0xfe, 0xcf, 0x35, 0xb3, 0x0b, 0xdc,
-    0x16, 0x2b, 0xd6, 0x80, 0x1f, 0xc3, 0xa4, 0xf3, 0xff, 0xf9, 0xae, 0x09,
-    0x03, 0xe7, 0xb5, 0x96, 0xe5, 0x17, 0xb4, 0xb4, 0xf9, 0xfc, 0xfd, 0xba,
-    0xb4, 0xff, 0xd4, 0x7e, 0xb5, 0xc1, 0xb8, 0x5f, 0xe9, 0x68, 0xdc, 0xfb,
-    0xf8, 0x51, 0x3e, 0xcf, 0xce, 0xda, 0x5a, 0x16, 0x9d, 0x98, 0xe7, 0x4d,
-    0x8e, 0x89, 0xe1, 0xc4, 0x43, 0x75, 0x52, 0x73, 0xeb, 0xab, 0x4f, 0x9f,
-    0x9e, 0xc0, 0xa5, 0x21, 0x70, 0xf0, 0x7c, 0x37, 0x3f, 0xc5, 0x9c, 0xcf,
-    0x9c, 0xcb, 0xd6, 0x9f, 0xbf, 0xba, 0x47, 0xbd, 0xc5, 0xa7, 0xbc, 0x66,
-    0x71, 0x69, 0xf8, 0x1f, 0xeb, 0xe0, 0x81, 0x69, 0x80, 0xcb, 0x4c, 0x06,
-    0x5a, 0x7d, 0xfb, 0xf0, 0xb6, 0x13, 0x54, 0x01, 0x58, 0x64, 0x5d, 0x00,
-    0x88, 0x96, 0xa7, 0xff, 0xb0, 0xab, 0x7d, 0x18, 0x65, 0x7c, 0xb1, 0xc0,
-    0xb4, 0xff, 0xde, 0xe6, 0x1f, 0xeb, 0x03, 0x37, 0xf2, 0xd3, 0xfb, 0x7b,
-    0x0f, 0x7e, 0xb0, 0x56, 0x9e, 0x01, 0xe9, 0xff, 0x11, 0x9d, 0xa5, 0x3f,
-    0x23, 0x4e, 0xbb, 0xcd, 0xd6, 0x9e, 0x07, 0x47, 0xab, 0x43, 0x22, 0x26,
-    0x92, 0x5d, 0x1f, 0x9e, 0xd7, 0xfb, 0xf9, 0x69, 0xdd, 0xc7, 0x56, 0x9f,
-    0xf3, 0x8d, 0x7e, 0xbb, 0x96, 0x6b, 0xd6, 0x9f, 0xc7, 0xc3, 0xe0, 0x45,
-    0xd5, 0xa7, 0xe2, 0xc7, 0x38, 0x3e, 0x5a, 0x7b, 0x33, 0x9a, 0x5a, 0x31,
-    0x17, 0xd4, 0x81, 0xe3, 0x23, 0x45, 0x93, 0x9d, 0x75, 0xd4, 0xa7, 0xd8,
-    0x61, 0x7f, 0xa4, 0xb6, 0x2f, 0xe7, 0xd9, 0xb3, 0xae, 0xba, 0xb4, 0x31,
-    0xf1, 0xf8, 0xe2, 0x7f, 0xc5, 0x9a, 0xb7, 0x06, 0xcc, 0x4b, 0x4f, 0xff,
-    0xe3, 0x1d, 0xae, 0x99, 0xb6, 0xb1, 0xe5, 0xfd, 0x6b, 0x09, 0x68, 0xc4,
-    0x4f, 0x09, 0xdc, 0xf3, 0xb4, 0x4f, 0x5a, 0x7f, 0xbc, 0xdb, 0x82, 0xb9,
-    0xc1, 0x5a, 0x5c, 0x5a, 0x30, 0xf2, 0x2c, 0x71, 0x39, 0xd7, 0x5d, 0x4a,
-    0x7e, 0x1a, 0x33, 0x83, 0xe4, 0xb6, 0x2f, 0xe7, 0xab, 0x8c, 0x15, 0xa7,
-    0xd8, 0x0c, 0xc7, 0x16, 0x96, 0xbe, 0x23, 0x0b, 0xa8, 0x1c, 0x3c, 0x22,
-    0x09, 0xbf, 0x78, 0x53, 0x6f, 0xc8, 0xca, 0xe4, 0x3c, 0x4f, 0x18, 0xa3,
-    0x90, 0x9e, 0xae, 0x8f, 0x16, 0x86, 0x64, 0xb8, 0x3c, 0x8f, 0x23, 0x57,
-    0x31, 0x96, 0xc5, 0x02, 0x73, 0xd8, 0x76, 0x72, 0x38, 0x5a, 0x2f, 0x01,
-    0x21, 0x43, 0x6b, 0x50, 0xbf, 0xf4, 0xa8, 0x5b, 0xb2, 0xe9, 0x8d, 0x91,
-    0x5a, 0x7e, 0x63, 0xf7, 0xb5, 0xe5, 0xa7, 0xff, 0x84, 0xfb, 0xbf, 0x5f,
-    0x30, 0x8b, 0x04, 0x0b, 0x45, 0xd0, 0x89, 0x5e, 0x0d, 0x78, 0xb2, 0x5b,
-    0x1b, 0x50, 0xe7, 0x4f, 0xba, 0xa1, 0x3a, 0x6d, 0xce, 0xcd, 0xb4, 0xf8,
-    0xd8, 0x99, 0x34, 0xf5, 0xf5, 0xf2, 0xac, 0xdf, 0x39, 0x52, 0x19, 0xcf,
-    0x3c, 0xb4, 0xbc, 0xa6, 0x4a, 0x17, 0xb4, 0xf6, 0x06, 0xf3, 0xb1, 0x43,
-    0x3a, 0xe0, 0xe5, 0x23, 0x83, 0xb4, 0x9f, 0xe3, 0xcb, 0xa5, 0xe5, 0x35,
-    0x1e, 0xab, 0x48, 0x30, 0x4e, 0xa2, 0xdd, 0x30, 0xab, 0x2a, 0x5f, 0x7e,
-    0xab, 0xe7, 0x2f, 0x57, 0x0c, 0x9f, 0xcb, 0x9e, 0xb9, 0x1d, 0x93, 0xb1,
-    0x84, 0xdd, 0xce, 0x90, 0xfd, 0xa5, 0x8d, 0x1a, 0x8d, 0xe6, 0x36, 0x87,
-    0x51, 0xbb, 0xf1, 0xcf, 0x3f, 0x3e, 0xd8, 0x07, 0xcf, 0x2d, 0x3f, 0xb6,
-    0xce, 0xda, 0xaa, 0xca, 0x8b, 0x8e, 0x7f, 0x6d, 0x9d, 0xb5, 0x55, 0x95,
-    0x17, 0x5c, 0xff, 0xdb, 0x53, 0xf6, 0xce, 0xda, 0xaa, 0xca, 0x89, 0x46,
-    0x1a, 0x1d, 0xca, 0x8f, 0x39, 0x09, 0xf9, 0x87, 0xf6, 0x3f, 0x18, 0xd0,
-    0x4d, 0xd7, 0xeb, 0x1d, 0x51, 0xc0, 0x39, 0xd1, 0x47, 0x8f, 0xcd, 0x1f,
-    0xcf, 0xfe, 0xd8, 0xf4, 0xfd, 0xb3, 0xb6, 0xaa, 0xb2, 0xa2, 0x5a, 0x9f,
-    0x76, 0xd5, 0x56, 0x54, 0x46, 0xf3, 0xfe, 0xa7, 0xed, 0x9d, 0xb5, 0x55,
-    0x95, 0x12, 0xfc, 0xb6, 0xc3, 0xfd, 0x39, 0x9c, 0xfe, 0xdb, 0x3b, 0x6a,
-    0xab, 0x2a, 0x2a, 0xb9, 0x84, 0xd2, 0xd3, 0xc2, 0x7a, 0xb8, 0xb4, 0x18,
-    0x6e, 0x7c, 0x2f, 0x38, 0x8d, 0x3a, 0xb4, 0xfd, 0x5c, 0x70, 0x98, 0x2b,
-    0x4e, 0x67, 0xe2, 0xd0, 0x13, 0xc6, 0x70, 0xb2, 0x7f, 0x8c, 0xc2, 0xcd,
-    0xfd, 0x47, 0x5a, 0x60, 0x8a, 0xd3, 0xf6, 0x76, 0xd5, 0x56, 0x54, 0x48,
-    0x11, 0xf0, 0xf3, 0x76, 0x15, 0x9f, 0x6a, 0x8a, 0xb7, 0x5a, 0x1e, 0x79,
-    0x7b, 0x92, 0xcf, 0xe7, 0xb7, 0x6f, 0x6e, 0xde, 0xb4, 0xfe, 0xed, 0xe7,
-    0x62, 0x7e, 0x96, 0x86, 0x3e, 0x7c, 0x34, 0x9f, 0xfd, 0x8e, 0x72, 0x8f,
-    0xee, 0x37, 0xbf, 0x3a, 0xd1, 0x7a, 0xa6, 0xe0, 0x91, 0x63, 0x21, 0x84,
-    0x75, 0x0d, 0x02, 0x84, 0x57, 0xd2, 0x09, 0xff, 0x8b, 0x2f, 0xda, 0xed,
-    0x88, 0xb3, 0xcb, 0x46, 0xc8, 0xb6, 0xeb, 0x8c, 0xfe, 0xdb, 0x3b, 0x6a,
-    0xab, 0x2a, 0x2c, 0x89, 0xfd, 0xb6, 0x76, 0xd5, 0x56, 0x54, 0x5a, 0xf3,
-    0xfb, 0x6c, 0xed, 0xaa, 0xac, 0xa8, 0xb9, 0x27, 0xdd, 0xb5, 0x55, 0x95,
-    0x17, 0x64, 0xff, 0xa9, 0xfb, 0x67, 0x6d, 0x55, 0x65, 0x45, 0x1d, 0x2d,
-    0xb0, 0xff, 0x4e, 0x67, 0x3c, 0x4c, 0xf3, 0xad, 0x27, 0xad, 0x3e, 0xed,
-    0xaa, 0xac, 0xa8, 0xa5, 0x67, 0xfa, 0xdc, 0x17, 0x38, 0xd7, 0xe2, 0xd3,
-    0xff, 0xb8, 0xd7, 0xb7, 0x06, 0xe5, 0x07, 0x82, 0xb6, 0xc6, 0xe6, 0x67,
-    0xed, 0x88, 0xc7, 0x71, 0xb2, 0x37, 0x4c, 0x1e, 0xa1, 0xaf, 0x2d, 0x82,
-    0x9a, 0x81, 0xe3, 0x27, 0x8b, 0xd7, 0xe7, 0xdf, 0x0d, 0x4d, 0xca, 0x06,
-    0x5c, 0xe1, 0xc9, 0x00, 0x7f, 0xa3, 0xff, 0x42, 0xf2, 0xe4, 0x6f, 0x13,
-    0xfc, 0xfd, 0xb3, 0xb6, 0xaa, 0xb2, 0xa2, 0x38, 0x9f, 0xe1, 0xdb, 0x3b,
-    0x6a, 0xab, 0x2a, 0x2b, 0x59, 0x6d, 0x48, 0x89, 0xf2, 0x2c, 0xff, 0xed,
-    0x8f, 0x4f, 0xdb, 0x3b, 0x6a, 0xab, 0x2a, 0x25, 0xb9, 0xb3, 0x75, 0xa7,
-    0xf0, 0x70, 0xe7, 0x61, 0xd2, 0xd1, 0xb9, 0xe3, 0x88, 0xb4, 0xee, 0x05,
-    0xeb, 0x4f, 0xf6, 0x6e, 0x58, 0x00, 0x53, 0xd6, 0x98, 0xf6, 0x5a, 0x18,
-    0xf3, 0x5e, 0x6f, 0x3f, 0xff, 0x72, 0xb7, 0x00, 0x79, 0x4f, 0xcd, 0x17,
-    0xf5, 0xf5, 0x69, 0xf8, 0x7a, 0x43, 0xed, 0x2d, 0x3e, 0xed, 0x16, 0x32,
-    0xd0, 0xa8, 0x86, 0xf8, 0x79, 0xf4, 0x57, 0x3f, 0x9e, 0x24, 0x1c, 0x10,
-    0xad, 0x3f, 0xea, 0x7e, 0xd9, 0xdb, 0x55, 0x59, 0x51, 0x30, 0x4f, 0xfe,
-    0xcf, 0x5d, 0xb5, 0xfe, 0x26, 0xff, 0xda, 0x5a, 0x7f, 0x68, 0x78, 0x27,
-    0xc3, 0x16, 0x9f, 0xfd, 0x57, 0xf0, 0x58, 0xb1, 0xc1, 0xe8, 0xad, 0x1e,
-    0x3f, 0x97, 0x4c, 0xa6, 0xb6, 0x2d, 0x37, 0xe0, 0x4a, 0x04, 0xd6, 0x74,
-    0x56, 0x7f, 0x60, 0x4b, 0x3d, 0xcc, 0x5a, 0x7e, 0xbf, 0xed, 0xdd, 0x10,
-    0x16, 0x9f, 0xb3, 0xde, 0x6e, 0xe9, 0x69, 0xfa, 0x88, 0x17, 0x83, 0xcb,
-    0x43, 0x22, 0x2c, 0x8c, 0xae, 0xcb, 0x25, 0xb3, 0x2e, 0x13, 0xde, 0x44,
-    0x16, 0x9c, 0x21, 0xb4, 0x2b, 0x37, 0x34, 0x39, 0x81, 0x25, 0x6a, 0x18,
-    0xde, 0x4f, 0xb8, 0x41, 0xf6, 0x17, 0x73, 0x8f, 0xff, 0x52, 0x9f, 0xf5,
-    0x3f, 0x6c, 0xed, 0xaa, 0xac, 0xa8, 0x98, 0xe7, 0x9b, 0xac, 0x69, 0x69,
-    0x6c, 0x28, 0x89, 0x38, 0xef, 0x12, 0xa7, 0xc2, 0xd7, 0xb7, 0x56, 0x9f,
-    0x9b, 0x5f, 0x3d, 0x9c, 0x5a, 0x73, 0x15, 0xeb, 0x4f, 0xff, 0xff, 0x3f,
-    0x5c, 0xcf, 0xdd, 0xd7, 0x32, 0xd9, 0xaf, 0x99, 0xbb, 0xf4, 0x24, 0x2b,
-    0x4f, 0x5a, 0xaa, 0xca, 0x8a, 0xc6, 0x7f, 0xd7, 0x79, 0xe2, 0xcf, 0xd8,
-    0xbc, 0xb4, 0x18, 0x99, 0xad, 0x8b, 0xb7, 0x1b, 0xec, 0x20, 0x3c, 0x5b,
-    0x3f, 0xf9, 0x8b, 0xc6, 0x7e, 0xc5, 0x96, 0x6e, 0xad, 0x3f, 0xc1, 0xe6,
-    0x6b, 0x77, 0xb7, 0x16, 0x9f, 0xe6, 0xdd, 0xee, 0x3e, 0xbb, 0x7a, 0xd1,
-    0x87, 0xe8, 0x27, 0x33, 0xfe, 0xc0, 0xf4, 0x7f, 0xbc, 0x1a, 0x7a, 0xd3,
-    0xff, 0xbb, 0x7b, 0x7b, 0xe7, 0xdb, 0x7d, 0x35, 0xf7, 0x4b, 0x4c, 0x1f,
-    0x2d, 0x18, 0x7d, 0x84, 0xad, 0x3f, 0xff, 0xf1, 0x7f, 0x7e, 0x5b, 0xe1,
-    0x7e, 0x6b, 0xe6, 0x6e, 0xfc, 0xfc, 0x81, 0xa5, 0xa7, 0xeb, 0xdc, 0x7d,
-    0xd7, 0xdb, 0xd6, 0x9e, 0x22, 0xcf, 0x2d, 0x17, 0x41, 0xea, 0xb1, 0xb4,
-    0xfd, 0x7f, 0xdb, 0xba, 0x20, 0x2d, 0x3f, 0xf3, 0x9c, 0xa3, 0xfb, 0x8d,
-    0xef, 0xce, 0xb4, 0x31, 0xfc, 0x61, 0x94, 0xee, 0x0e, 0xcc, 0xb9, 0xc7,
-    0x91, 0xad, 0xd9, 0x4b, 0x90, 0xbc, 0x22, 0x0d, 0x42, 0xb3, 0xc4, 0x17,
-    0x70, 0xd0, 0xfb, 0x09, 0xe9, 0xfb, 0xbd, 0x60, 0xe1, 0xd6, 0x9b, 0xe8,
-    0x16, 0x9d, 0xc1, 0x3a, 0xd2, 0x71, 0x68, 0xa3, 0x59, 0xf8, 0xdc, 0xfa,
-    0x8a, 0xff, 0xf4, 0xb4, 0xff, 0x30, 0x79, 0x81, 0xed, 0x59, 0x68, 0x14,
-    0x78, 0x00, 0xb0, 0x91, 0x34, 0x43, 0xe2, 0x89, 0xda, 0xfb, 0xa5, 0xa7,
-    0xb7, 0xbd, 0x8c, 0x5a, 0x02, 0x78, 0x5f, 0x8f, 0x4d, 0xe6, 0x5a, 0x7c,
-    0x7c, 0x26, 0x7a, 0xd3, 0xdf, 0xfb, 0x34, 0xb4, 0xf3, 0x76, 0x89, 0x69,
-    0xed, 0x69, 0x80, 0xb4, 0x32, 0x21, 0xc4, 0x97, 0x84, 0x4e, 0x8f, 0xcf,
-    0x99, 0xe0, 0xfd, 0xeb, 0x4f, 0x3b, 0xd6, 0x3a, 0xd3, 0xe6, 0xbf, 0xee,
-    0x38, 0xb4, 0xe6, 0x27, 0xad, 0x0e, 0x22, 0x38, 0x8a, 0x34, 0x45, 0xe2,
-    0xa9, 0xdc, 0xfa, 0x75, 0xa7, 0xe6, 0x3e, 0x10, 0x98, 0xb4, 0xb4, 0xb4,
-    0x09, 0xbb, 0xa2, 0xb9, 0x80, 0xc9, 0x4c, 0xeb, 0xa9, 0x40, 0x9a, 0xd7,
-    0x45, 0x67, 0xf5, 0x3c, 0xb3, 0xdc, 0x14, 0xb6, 0x34, 0x33, 0xc1, 0xad,
-    0xf4, 0xb4, 0xe6, 0x27, 0x16, 0x98, 0x99, 0x69, 0x38, 0xb4, 0x38, 0x78,
-    0x1d, 0x1b, 0xa1, 0x49, 0xff, 0x8c, 0x12, 0xb6, 0x98, 0xf5, 0xbf, 0x96,
-    0x9c, 0x0c, 0x34, 0xb4, 0x18, 0x7c, 0x3d, 0x44, 0x9e, 0x3e, 0xbf, 0x3a,
-    0xd2, 0x31, 0x69, 0xba, 0x62, 0xd0, 0xc7, 0x96, 0x24, 0x7f, 0x44, 0x67,
-    0xff, 0x79, 0x9e, 0x3e, 0xe6, 0x6f, 0xef, 0xd9, 0x69, 0x62, 0xd0, 0x27,
-    0xb3, 0x76, 0x95, 0x0c, 0xa8, 0x33, 0x18, 0x86, 0x12, 0x1c, 0x6e, 0xa8,
-    0x44, 0x42, 0xd2, 0x3a, 0xd2, 0xe7, 0x8b, 0xab, 0x81, 0x53, 0xf0, 0x1b,
-    0x99, 0x72, 0x96, 0x9f, 0x87, 0xd9, 0xca, 0x31, 0x69, 0xce, 0xba, 0xea,
-    0x53, 0xfe, 0xb0, 0x5a, 0xff, 0xb9, 0xca, 0xdd, 0x2d, 0x8b, 0xf9, 0xcc,
-    0x71, 0x5a, 0x30, 0xfa, 0xec, 0xa3, 0x3c, 0x3d, 0x34, 0x15, 0xa7, 0xdc,
-    0x6d, 0xe8, 0xdd, 0x69, 0xff, 0xe6, 0xf6, 0x83, 0x9e, 0x1e, 0x7f, 0x9b,
-    0xf9, 0x68, 0xe1, 0xfd, 0x78, 0xaa, 0x5d, 0x5a, 0x6f, 0xf4, 0xb4, 0xea,
-    0xa2, 0x5a, 0x7c, 0x71, 0xf0, 0x29, 0x68, 0xbd, 0x32, 0x5c, 0x84, 0xe9,
-    0xb9, 0x15, 0x08, 0x78, 0x5f, 0xf1, 0x99, 0xee, 0x78, 0x6f, 0x5a, 0x7f,
-    0x58, 0x74, 0x59, 0x72, 0x96, 0x9b, 0x3c, 0xb4, 0xfb, 0x2f, 0x2c, 0xdd,
-    0x68, 0xc4, 0x48, 0x6e, 0x45, 0xc3, 0x22, 0x15, 0x9d, 0xc6, 0x0a, 0xd0,
-    0xb4, 0xf7, 0x8e, 0x7e, 0xad, 0x3f, 0xf0, 0x18, 0xad, 0x5e, 0x07, 0xd2,
-    0x7a, 0xd3, 0xde, 0x2c, 0x7a, 0xd3, 0xec, 0xfe, 0xe9, 0xd5, 0x2d, 0x3f,
-    0xf8, 0x75, 0xcc, 0x09, 0x65, 0xc2, 0xcd, 0x2d, 0x06, 0x23, 0xeb, 0x72,
-    0x2e, 0xa2, 0x11, 0x07, 0x8b, 0x25, 0xb3, 0x32, 0xad, 0xaf, 0x84, 0x53,
-    0xc8, 0xc3, 0x09, 0xcc, 0x86, 0x50, 0x9e, 0xf5, 0x64, 0xed, 0xbc, 0x94,
-    0x9b, 0x4d, 0x80, 0x28, 0xba, 0x4b, 0x4a, 0x16, 0xda, 0x8d, 0x1b, 0xd0,
-    0xf0, 0x74, 0xf2, 0xec, 0x6f, 0xec, 0x60, 0x93, 0xee, 0xda, 0xaa, 0xca,
-    0x8a, 0xde, 0x7f, 0xd4, 0xfd, 0xb3, 0xb6, 0xaa, 0xb2, 0xa2, 0x70, 0x96,
-    0xd8, 0x7f, 0xa7, 0x33, 0x9b, 0xfe, 0x2d, 0x3e, 0xed, 0xaa, 0xac, 0xa8,
-    0xb4, 0x67, 0xf9, 0xcc, 0x37, 0xd7, 0x7b, 0x5e, 0x5a, 0x7e, 0x6a, 0x2f,
-    0xc3, 0x8b, 0x4c, 0x26, 0x2d, 0x3f, 0xfe, 0xbd, 0xbc, 0xc1, 0xeb, 0x72,
-    0xb4, 0x58, 0x05, 0xa7, 0xfc, 0xdb, 0xd1, 0xbf, 0x0a, 0x8d, 0xef, 0x5a,
-    0x7f, 0xcd, 0xd0, 0x60, 0xe7, 0x7d, 0xfa, 0xd0, 0xc8, 0xd4, 0xe2, 0x9e,
-    0x91, 0x25, 0x8e, 0x26, 0x33, 0xa8, 0x75, 0x4f, 0xf6, 0x73, 0x9f, 0x98,
-    0x76, 0xd2, 0xd3, 0xd8, 0x0a, 0xe2, 0xd2, 0xda, 0xea, 0x54, 0xa7, 0x82,
-    0xee, 0x19, 0x9c, 0xf3, 0x91, 0xa2, 0x78, 0xbe, 0xec, 0xea, 0x7a, 0xd5,
-    0x56, 0x54, 0x5b, 0x53, 0xf7, 0x18, 0xec, 0x21, 0x5a, 0x3a, 0x7b, 0x1e,
-    0x2d, 0x9f, 0xf7, 0x04, 0x34, 0xf0, 0xf0, 0x4e, 0xb4, 0xf3, 0x5c, 0xc1,
-    0x5a, 0x7f, 0x99, 0xed, 0xdb, 0xdb, 0xb7, 0xad, 0x3f, 0xcd, 0xdf, 0x9a,
-    0x6e, 0x50, 0xad, 0x3f, 0xb8, 0x34, 0xff, 0x0d, 0xeb, 0x46, 0x26, 0x47,
-    0x62, 0x2e, 0x9e, 0x91, 0x0b, 0xa7, 0x37, 0x67, 0x13, 0xf1, 0x95, 0xd0,
-    0xfe, 0x4b, 0x4f, 0x86, 0xf3, 0xb5, 0x96, 0x9f, 0x56, 0xef, 0xfb, 0xa5,
-    0xa5, 0xb1, 0x87, 0xff, 0xe2, 0xeb, 0x84, 0xf1, 0xb2, 0x62, 0x40, 0x86,
-    0xcc, 0xfe, 0xdb, 0x3b, 0x6a, 0xab, 0x2a, 0x2e, 0x59, 0xfd, 0xb6, 0x76,
-    0xd5, 0x56, 0x54, 0x5d, 0xb0, 0xcd, 0xfb, 0xfd, 0xe5, 0x2f, 0x9c, 0xc5,
-    0x0c, 0x69, 0x46, 0x4e, 0x8c, 0x8d, 0x31, 0x54, 0xde, 0x3a, 0xee, 0x4a,
-    0x7b, 0x29, 0x61, 0x1a, 0x2a, 0xf1, 0xfc, 0xfe, 0xdb, 0x3b, 0x6a, 0xab,
-    0x2a, 0x2a, 0x79, 0x79, 0x69, 0xfe, 0x6a, 0xbf, 0xe6, 0xfa, 0x60, 0xad,
-    0x02, 0x79, 0x64, 0x21, 0x3d, 0x6a, 0xab, 0x2a, 0x2b, 0x99, 0xfd, 0xb6,
-    0x76, 0xd5, 0x56, 0x54, 0x59, 0xd1, 0xd3, 0xec, 0xe1, 0x6c, 0xff, 0xef,
-    0x36, 0xbe, 0x7f, 0xaf, 0x33, 0x8e, 0x0a, 0xd3, 0xf9, 0xb9, 0xf0, 0xf7,
-    0x51, 0xb5, 0xe5, 0xa3, 0x11, 0x1b, 0x71, 0x3a, 0x7d, 0xdc, 0xf0, 0x9d,
-    0x69, 0xea, 0x26, 0x0a, 0xd3, 0xf6, 0x38, 0xc7, 0x6f, 0xab, 0x4f, 0xbb,
-    0x6a, 0xab, 0x2a, 0x24, 0x29, 0xff, 0x61, 0xf2, 0xbb, 0x7f, 0xcd, 0xce,
-    0xb4, 0xff, 0x0e, 0xfa, 0xf1, 0x31, 0xf4, 0xb4, 0xcf, 0xdb, 0x11, 0x59,
-    0xc3, 0x30, 0x20, 0xcf, 0x5d, 0x5c, 0x63, 0xad, 0x3f, 0xb3, 0x9a, 0xd6,
-    0x76, 0xf5, 0xa5, 0xb0, 0x55, 0x89, 0xe4, 0x23, 0x06, 0x15, 0xfd, 0x24,
-    0x39, 0x37, 0x07, 0xea, 0x1b, 0x5a, 0x3c, 0xf1, 0x34, 0xff, 0xed, 0x8f,
-    0x4f, 0xdb, 0x3b, 0x6a, 0xab, 0x2a, 0x27, 0xc8, 0xb2, 0xe4, 0x39, 0xbc,
-    0xb9, 0xde, 0x42, 0x4e, 0x73, 0xc7, 0x75, 0xa7, 0xd9, 0xdc, 0xc7, 0x16,
-    0x96, 0xdc, 0x3c, 0x2f, 0xa3, 0x93, 0xee, 0xda, 0xaa, 0xca, 0x8a, 0xca,
-    0x7f, 0xd4, 0xfd, 0xb3, 0xb6, 0xaa, 0xb2, 0xa2, 0x6e, 0x96, 0xd8, 0x7f,
-    0xa7, 0x33, 0x8b, 0x23, 0x40, 0x61, 0x51, 0x3e, 0xed, 0xaa, 0xac, 0xa8,
-    0x95, 0xa7, 0xc4, 0xc1, 0xae, 0x2d, 0x3e, 0xd8, 0xf4, 0xfd, 0xb0, 0xf6,
-    0x04, 0xce, 0x7f, 0xe7, 0x8e, 0xbf, 0x39, 0x0d, 0xcf, 0xe9, 0x69, 0xf7,
-    0x6d, 0x55, 0x65, 0x44, 0xb9, 0x3f, 0xc3, 0x4f, 0xf1, 0x31, 0xf4, 0xb4,
-    0xf5, 0xc1, 0x26, 0x5a, 0x7f, 0xfd, 0x5e, 0x1f, 0xde, 0x42, 0xf6, 0xf1,
-    0x7e, 0xf5, 0xa7, 0xdb, 0x1e, 0x9f, 0xb3, 0x26, 0x49, 0x88, 0xdc, 0x33,
-    0xa3, 0x6d, 0x10, 0xcf, 0xfd, 0xb5, 0x3f, 0x6c, 0xed, 0xaa, 0xac, 0xa8,
-    0x8e, 0xe7, 0xfb, 0xdc, 0xc7, 0xed, 0x45, 0xa5, 0xa7, 0xeb, 0xac, 0x9a,
-    0xd8, 0x4b, 0x4d, 0xff, 0x16, 0x9f, 0x8d, 0xa2, 0xce, 0x57, 0x96, 0x9f,
-    0xd8, 0xee, 0x98, 0xbd, 0xa5, 0xa7, 0xfc, 0xc5, 0xff, 0x86, 0xae, 0x53,
-    0xd6, 0x9e, 0xb5, 0x55, 0x95, 0x15, 0x0c, 0x58, 0xfa, 0xfa, 0x7d, 0x33,
-    0xf1, 0x69, 0xff, 0xe6, 0xa3, 0xe7, 0x4b, 0x06, 0xe0, 0xf6, 0x96, 0x9f,
-    0xe6, 0x7b, 0x76, 0xf6, 0xed, 0xeb, 0x4f, 0xf6, 0x0d, 0xca, 0x3f, 0x1d,
-    0xa5, 0xa7, 0xb9, 0xec, 0xbd, 0x69, 0xf6, 0x5f, 0x45, 0x71, 0x69, 0xff,
-    0xff, 0xfc, 0xcf, 0xf9, 0xee, 0x0b, 0x6b, 0xe6, 0x7f, 0x66, 0xb9, 0xf3,
-    0x3b, 0xdc, 0xb9, 0xfd, 0x71, 0x68, 0xc4, 0x71, 0x11, 0x16, 0x8a, 0x27,
-    0xff, 0xfb, 0xfa, 0x37, 0x1b, 0xf9, 0x43, 0xe6, 0xe0, 0xfb, 0x58, 0x15,
-    0xa5, 0xb1, 0xb4, 0xae, 0x02, 0xea, 0x2f, 0xba, 0xc5, 0xef, 0x30, 0xc8,
-    0x4e, 0xd8, 0x8b, 0xa2, 0xa4, 0x99, 0xa3, 0x9f, 0x46, 0x37, 0x76, 0x5d,
-    0x3e, 0xed, 0xaa, 0xac, 0xa8, 0xaa, 0x27, 0xfd, 0x4f, 0xdb, 0x3b, 0x6a,
-    0xab, 0x2a, 0x26, 0xb9, 0x6d, 0x87, 0xfa, 0x73, 0x39, 0xf7, 0x6d, 0x55,
-    0x65, 0x45, 0x59, 0x3f, 0xcc, 0xf6, 0xed, 0xed, 0xdb, 0xd6, 0x96, 0xd8,
-    0x7d, 0x84, 0x67, 0x3f, 0xed, 0xb8, 0xdb, 0xf9, 0xb9, 0x46, 0xeb, 0x4f,
-    0xfd, 0xb5, 0x3f, 0x6c, 0xed, 0xaa, 0xac, 0xa8, 0x91, 0x27, 0xdd, 0xb5,
-    0x55, 0x95, 0x16, 0x94, 0xff, 0xa9, 0xfb, 0x67, 0x6d, 0x55, 0x65, 0x44,
-    0xfb, 0x2d, 0xb0, 0xff, 0x4e, 0x67, 0x3f, 0xfb, 0x63, 0xd3, 0xf6, 0xce,
-    0xda, 0xaa, 0xca, 0x8a, 0x12, 0x7d, 0xc1, 0xbd, 0xba, 0xb4, 0xfb, 0xb6,
-    0xaa, 0xb2, 0xa2, 0x8f, 0x9f, 0xe6, 0x7b, 0x76, 0xf6, 0xed, 0xeb, 0x4f,
-    0xf8, 0x99, 0xc6, 0x26, 0x73, 0x8c, 0xb4, 0xff, 0xfd, 0x81, 0xe3, 0x7d,
-    0xdb, 0xc5, 0x40, 0xd6, 0x98, 0x09, 0x4f, 0xb6, 0x3d, 0x3f, 0x66, 0x4c,
-    0xaf, 0x09, 0xc8, 0xcf, 0xc7, 0x37, 0x67, 0x90, 0xcc, 0xae, 0xcb, 0xe3,
-    0x63, 0x7b, 0x3e, 0x28, 0x99, 0x2e, 0xe2, 0xd1, 0x9d, 0x6f, 0x09, 0x41,
-    0x27, 0x71, 0x0b, 0x90, 0xce, 0x01, 0x47, 0xa3, 0x82, 0x9f, 0xdb, 0x67,
-    0x6d, 0x55, 0x65, 0x44, 0x45, 0x3f, 0x67, 0x6d, 0x55, 0x65, 0x44, 0x57,
-    0x3f, 0xc6, 0xfb, 0x67, 0x6d, 0x55, 0x65, 0x45, 0x71, 0x1b, 0x22, 0x02,
-    0x8e, 0x27, 0xff, 0x01, 0x8a, 0xdb, 0x57, 0x81, 0xf4, 0x9e, 0xb4, 0xf6,
-    0xd7, 0xb8, 0x6e, 0xb4, 0x87, 0x73, 0xf3, 0x02, 0x5c, 0xf6, 0x72, 0xbc,
-    0xb4, 0xfe, 0xc1, 0xe8, 0x01, 0xfe, 0x96, 0x91, 0xb4, 0x47, 0xa7, 0xa2,
-    0x09, 0xff, 0xfb, 0xda, 0x1e, 0x50, 0xbc, 0x4b, 0xdf, 0xf3, 0xb8, 0xb4,
-    0xfb, 0xb6, 0xaa, 0xb2, 0xa2, 0x9e, 0x9d, 0x63, 0x8a, 0xd3, 0xff, 0xf7,
-    0x7b, 0xff, 0x7a, 0xc5, 0x86, 0x0f, 0x39, 0x9f, 0x56, 0x9f, 0xf8, 0x5f,
-    0x84, 0x06, 0x38, 0xf5, 0xeb, 0x4f, 0xe7, 0xb7, 0x6f, 0x6e, 0xde, 0xb4,
-    0xf7, 0xc2, 0xa7, 0xad, 0x3e, 0xac, 0xe0, 0x9d, 0x68, 0xd1, 0xe3, 0xdc,
-    0x22, 0x86, 0x44, 0xfe, 0x3d, 0xcf, 0xf3, 0x15, 0xb2, 0xe6, 0x7b, 0x4b,
-    0x45, 0xd6, 0xa9, 0xa5, 0x8b, 0x31, 0x66, 0xc6, 0x62, 0x37, 0x4b, 0xa5,
-    0x0e, 0x0b, 0x84, 0x33, 0xff, 0xa9, 0xfb, 0x04, 0xa9, 0xdd, 0x69, 0x80,
-    0xb4, 0x6c, 0x8c, 0x40, 0xbd, 0x4e, 0xd8, 0x38, 0xb4, 0xff, 0xfb, 0x8d,
-    0xdc, 0x78, 0xd7, 0xb0, 0x23, 0xfd, 0x96, 0x9f, 0x33, 0xc1, 0xfb, 0xd6,
-    0x9e, 0xb5, 0x55, 0x95, 0x15, 0x9c, 0x38, 0x7a, 0xbd, 0x28, 0x9e, 0xf0,
-    0x9f, 0x4b, 0x4f, 0xd7, 0x9d, 0x89, 0xfa, 0x5a, 0x73, 0x5e, 0x2b, 0x4f,
-    0xbc, 0x0f, 0xa4, 0xf5, 0xa7, 0x7f, 0x5a, 0x5a, 0x7d, 0x8e, 0x5f, 0xf8,
-    0x16, 0x96, 0xc1, 0x4e, 0x8f, 0x21, 0x51, 0xb9, 0x1f, 0x48, 0x78, 0x5b,
-    0x43, 0x64, 0x53, 0xf4, 0x72, 0x7f, 0xed, 0xa9, 0xfb, 0x67, 0x6d, 0x55,
-    0x65, 0x44, 0x8b, 0x3f, 0x67, 0x6d, 0x55, 0x65, 0x45, 0x93, 0x3f, 0xfb,
-    0xda, 0xfb, 0xad, 0xb2, 0xf1, 0x27, 0xe9, 0x68, 0xd9, 0x10, 0xb8, 0x71,
-    0x3f, 0xb6, 0xce, 0xda, 0xaa, 0xca, 0x8b, 0x62, 0x76, 0x6b, 0x16, 0x9e,
-    0xb5, 0x55, 0x95, 0x16, 0xdc, 0xf6, 0xaf, 0xae, 0xad, 0x1d, 0x3c, 0xff,
-    0x16, 0xcf, 0xc3, 0xcf, 0x08, 0x3f, 0x5a, 0x7f, 0x99, 0xed, 0xdb, 0xdb,
-    0xb7, 0xad, 0x2d, 0x9e, 0x8f, 0x1c, 0x69, 0x70, 0x88, 0x8b, 0x67, 0x5d,
-    0x7c, 0x0a, 0xd3, 0xaf, 0xe0, 0xad, 0x3f, 0xeb, 0xae, 0xeb, 0x36, 0xfe,
-    0xe6, 0x13, 0x01, 0x69, 0xf9, 0x89, 0xe1, 0xfc, 0xeb, 0x4f, 0xbb, 0x6a,
-    0xab, 0x2a, 0x2f, 0x09, 0xef, 0x5d, 0xe7, 0x16, 0x9f, 0xf9, 0xbe, 0x9f,
-    0x77, 0xfb, 0x0b, 0xda, 0x5a, 0x7d, 0x84, 0x03, 0x4c, 0xb4, 0xf9, 0xbe,
-    0xff, 0x5a, 0x5a, 0x77, 0x98, 0x0b, 0x4b, 0x63, 0x69, 0x3b, 0xfb, 0xac,
-    0x84, 0xdb, 0x47, 0x2f, 0x4d, 0xc2, 0xdd, 0xcc, 0xf8, 0x48, 0x04, 0x62,
-    0x27, 0xf1, 0x4c, 0xe1, 0xcd, 0xd6, 0x9e, 0xb5, 0x55, 0x95, 0x17, 0xa4,
-    0xff, 0x87, 0xdc, 0x2a, 0x78, 0x28, 0x0b, 0x47, 0x4f, 0xa4, 0xe5, 0xb3,
-    0x8e, 0x3e, 0x5a, 0x7f, 0xab, 0xcf, 0x63, 0x3c, 0x37, 0xad, 0x07, 0x3d,
-    0x42, 0x1b, 0x9f, 0x61, 0xf9, 0x41, 0x5a, 0x5b, 0x05, 0x34, 0x1c, 0x84,
-    0x27, 0xd7, 0x63, 0x44, 0x30, 0xcc, 0xdb, 0xbb, 0xe1, 0x7e, 0xf8, 0x4b,
-    0x64, 0xba, 0x8b, 0x12, 0x0c, 0x77, 0xfd, 0x7e, 0x3c, 0x35, 0x80, 0x46,
-    0x51, 0x98, 0x7f, 0x28, 0x09, 0xd8, 0xf9, 0x66, 0xff, 0x8b, 0x4f, 0x67,
-    0x2b, 0xcb, 0x4f, 0xec, 0x1e, 0x80, 0x1f, 0xe9, 0x69, 0x1b, 0x44, 0x7a,
-    0x7a, 0x20, 0x9f, 0x0f, 0x9b, 0x7b, 0xd6, 0x9f, 0x76, 0xd5, 0x56, 0x54,
-    0x44, 0x73, 0xff, 0xdc, 0xff, 0x5a, 0xc3, 0x96, 0x5c, 0xf8, 0xc6, 0xca,
-    0xd3, 0xfe, 0x7b, 0x5f, 0xdc, 0xf7, 0x87, 0xcb, 0x4f, 0xf6, 0x77, 0x35,
-    0x94, 0x57, 0xad, 0x3f, 0xff, 0xcd, 0xca, 0x1f, 0x37, 0x0b, 0x3d, 0xc1,
-    0xe6, 0x0b, 0xab, 0x4d, 0x79, 0xd2, 0x99, 0xd7, 0x52, 0x9f, 0xf6, 0xd6,
-    0xe0, 0xb9, 0xc6, 0xbf, 0x60, 0x1a, 0xf7, 0x45, 0xe7, 0xae, 0x37, 0x99,
-    0x68, 0x79, 0xfe, 0x0a, 0xd4, 0xfd, 0x94, 0x7c, 0xdf, 0xcb, 0x4d, 0x74,
-    0x1b, 0xad, 0x3f, 0x1b, 0x96, 0x72, 0xbc, 0xb4, 0xfc, 0xc6, 0x61, 0x09,
-    0x8b, 0x4f, 0xd9, 0xe3, 0x5e, 0xce, 0x2d, 0x18, 0x88, 0x82, 0x2e, 0xd1,
-    0x64, 0xff, 0xfd, 0x6d, 0xbb, 0x44, 0x3e, 0xdb, 0xad, 0xe2, 0xa0, 0x2d,
-    0x17, 0x52, 0xe2, 0x2d, 0xd6, 0xd4, 0xc5, 0x98, 0x51, 0x63, 0x3d, 0xd6,
-    0x04, 0xfb, 0xa6, 0xd5, 0x18, 0x68, 0x08, 0x74, 0x59, 0xe8, 0x53, 0x5c,
-    0x2e, 0x98, 0xd7, 0x16, 0x9f, 0x76, 0xd5, 0x56, 0x54, 0x45, 0xd3, 0xef,
-    0x03, 0xe9, 0x3d, 0x29, 0x6d, 0x79, 0xfa, 0x60, 0xc5, 0x19, 0xc6, 0xc9,
-    0xb9, 0x3e, 0x33, 0xd9, 0xff, 0x8f, 0x4f, 0xdb, 0x3b, 0x6a, 0xab, 0x2a,
-    0x26, 0x69, 0xf8, 0xd8, 0x9b, 0x73, 0x6b, 0x4d, 0xe5, 0xa7, 0x6e, 0xda,
-    0x5a, 0x75, 0x84, 0xeb, 0x4d, 0x77, 0x74, 0x2d, 0x3f, 0xfb, 0x8c, 0x7a,
-    0xf6, 0x6e, 0x03, 0xfd, 0xe2, 0xd3, 0xf7, 0xb2, 0xfc, 0x03, 0x8b, 0x4f,
-    0xef, 0x98, 0x55, 0xd0, 0x5d, 0xad, 0x3f, 0xfe, 0x3d, 0x73, 0x37, 0x07,
-    0x1d, 0xae, 0x39, 0xcf, 0xd6, 0x80, 0xa2, 0x3f, 0x0d, 0xa6, 0xd6, 0x2d,
-    0x17, 0x42, 0x6b, 0xc2, 0x3c, 0xe2, 0x67, 0x21, 0x7b, 0x44, 0x53, 0xf3,
-    0xac, 0x45, 0x9e, 0x5a, 0x7a, 0xb8, 0x2e, 0x2d, 0x18, 0x79, 0x96, 0x2b,
-    0x95, 0x96, 0x9f, 0xff, 0x03, 0x77, 0xf3, 0xf6, 0xee, 0xdc, 0x1b, 0x57,
-    0x56, 0x9f, 0xf8, 0xd0, 0xf8, 0x6c, 0x21, 0xf6, 0x59, 0x69, 0xff, 0xfe,
-    0xfe, 0x8a, 0xc5, 0x81, 0xe7, 0xff, 0x38, 0xcf, 0xeb, 0x5e, 0xb4, 0xf7,
-    0x87, 0x82, 0xb4, 0xff, 0x57, 0x5f, 0xf3, 0x2c, 0x1c, 0x5a, 0x19, 0x35,
-    0xec, 0x58, 0xe2, 0x21, 0x34, 0xfe, 0x41, 0x2e, 0xad, 0x3f, 0x7b, 0x0f,
-    0xbe, 0x1d, 0x69, 0x73, 0x0d, 0xe8, 0x88, 0x4f, 0xff, 0x82, 0x25, 0x7e,
-    0x68, 0x6b, 0x9b, 0x3a, 0xeb, 0xa9, 0x4f, 0xde, 0xe3, 0x5f, 0xcf, 0xd6,
-    0x9f, 0xb7, 0x7e, 0x81, 0xfb, 0x8b, 0x4e, 0xaa, 0xb2, 0xa2, 0xcf, 0x9f,
-    0x81, 0x44, 0xf1, 0x3a, 0xd1, 0x63, 0xd2, 0x01, 0x3c, 0xff, 0x87, 0x8c,
-    0xf1, 0xf3, 0x7b, 0x4b, 0x4f, 0xff, 0x0f, 0x79, 0x5f, 0x32, 0xe1, 0x66,
-    0xb0, 0x96, 0x9c, 0xeb, 0xae, 0xa5, 0x3f, 0xea, 0x7e, 0x8b, 0x2c, 0x1c,
-    0xea, 0x5b, 0x17, 0xf3, 0xff, 0x36, 0xef, 0x2f, 0xc1, 0xf2, 0xc7, 0x02,
-    0xd3, 0xfc, 0xdc, 0x10, 0x95, 0x53, 0x8b, 0x4f, 0xf0, 0x90, 0x7e, 0x87,
-    0xff, 0x69, 0x68, 0x7a, 0xb0, 0x0b, 0x12, 0xee, 0xb0, 0xe1, 0x7f, 0x61,
-    0x06, 0x72, 0x2e, 0x1e, 0x01, 0xbb, 0x49, 0x9e, 0x48, 0xb8, 0x6d, 0x3f,
-    0xdd, 0xa7, 0x78, 0x2d, 0xd6, 0x5a, 0x7b, 0xa2, 0xc7, 0x5a, 0x7f, 0xfd,
-    0xe3, 0x3f, 0x6c, 0x0f, 0x33, 0x5b, 0xbd, 0xb8, 0xb4, 0x1c, 0xfd, 0xc8,
-    0x82, 0x6a, 0x7a, 0xd3, 0xff, 0xff, 0xf1, 0x53, 0xbe, 0xce, 0x16, 0x7b,
-    0xf0, 0x1e, 0x9f, 0x41, 0x62, 0xae, 0xd3, 0xd6, 0x9f, 0xd9, 0xce, 0x7f,
-    0xea, 0x25, 0xa4, 0x21, 0x46, 0x63, 0x82, 0xbd, 0x84, 0x2c, 0x32, 0x65,
-    0x1c, 0x87, 0x6c, 0xff, 0xff, 0xfb, 0x01, 0xac, 0xc2, 0x33, 0xef, 0x49,
-    0xb3, 0x9b, 0x68, 0xb2, 0xf3, 0xe1, 0xd6, 0x9f, 0x5c, 0xae, 0x37, 0xd5,
-    0xa3, 0x11, 0x5a, 0x30, 0x83, 0x9d, 0xa6, 0xbd, 0x69, 0xd7, 0x79, 0xc5,
-    0xa1, 0xe7, 0xc1, 0xa2, 0x6f, 0x0e, 0x4e, 0xe7, 0xee, 0xad, 0x38, 0x1f,
-    0xd9, 0x69, 0xde, 0xcf, 0xab, 0x4f, 0xcd, 0xbe, 0xbe, 0x75, 0x96, 0x9e,
-    0x10, 0xff, 0x65, 0xa7, 0x9b, 0xda, 0x65, 0xa0, 0x28, 0xc9, 0xdc, 0x78,
-    0x47, 0x4e, 0x3b, 0xc2, 0xfb, 0xb2, 0x29, 0xb2, 0xcb, 0x4f, 0xdd, 0x1b,
-    0x98, 0x5a, 0x5a, 0x7d, 0xc2, 0x6c, 0xea, 0x93, 0xfe, 0x1e, 0xbf, 0x3b,
-    0x7f, 0xf4, 0x15, 0x44, 0x1b, 0xb1, 0xa5, 0x9f, 0x55, 0x84, 0xec, 0xb4,
-    0xfc, 0xfe, 0x15, 0x6f, 0xe5, 0xa5, 0x96, 0x3d, 0x22, 0x25, 0x9f, 0xff,
-    0xf5, 0x3b, 0xec, 0xe7, 0x9b, 0x0b, 0x7f, 0x67, 0x46, 0xfa, 0x3a, 0xd1,
-    0x75, 0x27, 0x4e, 0xc2, 0xaf, 0x52, 0xc8, 0x57, 0x91, 0x34, 0xf8, 0x77,
-    0x78, 0x92, 0xd3, 0x87, 0x98, 0xb4, 0xcc, 0x7c, 0x3c, 0x0b, 0x13, 0x4f,
-    0xb0, 0x3a, 0xe3, 0x2d, 0x02, 0x7a, 0x5d, 0x2c, 0x9d, 0xcc, 0x25, 0xa7,
-    0xff, 0xe2, 0xa3, 0x3e, 0x7d, 0x2a, 0xf6, 0x87, 0x7e, 0x0b, 0xab, 0x46,
-    0x1f, 0xcf, 0xe3, 0x53, 0xc2, 0x54, 0x15, 0xa7, 0xfc, 0x7c, 0xf6, 0xbe,
-    0xea, 0x9f, 0x8b, 0x4f, 0xb4, 0xdd, 0xf3, 0x2d, 0xb1, 0xbf, 0x80, 0xa2,
-    0x57, 0x4b, 0xd3, 0xef, 0xae, 0x55, 0x75, 0x69, 0xee, 0x60, 0xdc, 0x5a,
-    0x7e, 0xd0, 0xf7, 0x3f, 0xea, 0xd0, 0x28, 0x9b, 0x39, 0x1f, 0x0a, 0x7c,
-    0x45, 0x31, 0xcd, 0xa5, 0x45, 0xf9, 0x3f, 0xf3, 0xfd, 0xfb, 0xde, 0x7f,
-    0x79, 0x8e, 0xb4, 0xff, 0xf7, 0x18, 0x39, 0x6f, 0x98, 0x58, 0x1e, 0x32,
-    0xd3, 0xff, 0x0e, 0x16, 0x66, 0xbe, 0x3f, 0x47, 0x5a, 0x37, 0x46, 0xbb,
-    0x88, 0xda, 0x4e, 0x9c, 0x63, 0x75, 0x69, 0xf8, 0x2c, 0x0e, 0xe6, 0xeb,
-    0x46, 0xc7, 0x92, 0x71, 0xc9, 0xfc, 0xc7, 0xc1, 0xeb, 0x8f, 0x5a, 0x61,
-    0x71, 0x69, 0xde, 0x1b, 0xd6, 0x9c, 0x4d, 0x65, 0xa7, 0xff, 0x89, 0xad,
-    0xf3, 0xb8, 0x3f, 0xdd, 0x38, 0x6b, 0x16, 0x8f, 0x88, 0xa2, 0x38, 0xb1,
-    0x0e, 0x1a, 0x1a, 0x86, 0x55, 0xda, 0x13, 0xcc, 0x87, 0xf8, 0xbd, 0xf0,
-    0x8e, 0xa1, 0xa9, 0x3e, 0xe0, 0xdc, 0xc0, 0xad, 0x3e, 0xa3, 0x89, 0xac,
-    0x5a, 0x77, 0x9b, 0x75, 0xa3, 0x0f, 0x0e, 0x89, 0xe7, 0xff, 0xfc, 0xdc,
-    0x13, 0xec, 0xe3, 0xeb, 0xbf, 0x78, 0x3b, 0xea, 0xc3, 0x7a, 0xd0, 0x62,
-    0x3f, 0x1c, 0x6b, 0x34, 0x41, 0x3f, 0x57, 0x5b, 0x9f, 0x42, 0xb4, 0xf3,
-    0xb5, 0x9a, 0x5a, 0x7f, 0x9e, 0x7a, 0x7f, 0xb4, 0xc6, 0x2d, 0x0c, 0x7b,
-    0x54, 0x43, 0x3d, 0x9a, 0x12, 0x5a, 0x29, 0x18, 0xe5, 0x08, 0x8f, 0xc8,
-    0x27, 0x6f, 0x7b, 0xd6, 0x9e, 0xfb, 0xfd, 0x69, 0x69, 0xe0, 0x03, 0x37,
-    0x5a, 0x7e, 0x35, 0xec, 0xa2, 0xb2, 0xd3, 0xfd, 0xfd, 0x3c, 0x39, 0x80,
-    0xd2, 0xd3, 0xf8, 0x03, 0xbe, 0xef, 0xcf, 0x2d, 0x1c, 0x3e, 0xcd, 0x1c,
-    0x4f, 0xcd, 0xbe, 0x8e, 0x26, 0xeb, 0x47, 0x53, 0x0d, 0xe1, 0x17, 0xa1,
-    0x33, 0x70, 0x8a, 0x7f, 0xb9, 0xf5, 0xad, 0x77, 0x9d, 0x65, 0xa1, 0x93,
-    0xb2, 0xc8, 0xcc, 0x69, 0x16, 0x67, 0x3f, 0x5a, 0x47, 0x5a, 0x37, 0x35,
-    0x17, 0x48, 0xc4, 0xfd, 0x5b, 0xbc, 0x98, 0x2b, 0x4f, 0xf3, 0x6e, 0xf1,
-    0x23, 0xd7, 0x96, 0x8a, 0x3e, 0x32, 0x2c, 0x9f, 0xf8, 0x5b, 0x45, 0x4f,
-    0xf9, 0xac, 0xea, 0xd3, 0xff, 0xf8, 0x75, 0x7e, 0x3b, 0x85, 0xf9, 0xa6,
-    0xdb, 0x0a, 0xba, 0xb4, 0x12, 0x29, 0x7c, 0x87, 0x3f, 0xff, 0xee, 0x0e,
-    0xfe, 0xcd, 0xfd, 0xde, 0xb7, 0x81, 0xf4, 0x9f, 0xcc, 0x5a, 0x78, 0x21,
-    0xa2, 0x5a, 0x7f, 0xd5, 0xcb, 0x0d, 0x7c, 0xd5, 0x71, 0x69, 0xff, 0x65,
-    0xb8, 0x26, 0x5d, 0xff, 0xd3, 0x16, 0x9f, 0xee, 0x0d, 0x03, 0x03, 0x4f,
-    0x5a, 0x19, 0x55, 0xc0, 0x61, 0x15, 0x90, 0xc5, 0xb1, 0x10, 0xb7, 0xf0,
-    0x80, 0x8f, 0xbc, 0x89, 0x3f, 0xf6, 0x10, 0x33, 0x3b, 0xaf, 0x36, 0x2d,
-    0x3f, 0xdb, 0xfb, 0x3a, 0x37, 0xd1, 0xd6, 0x96, 0x00, 0xfe, 0x49, 0x02,
-    0x7f, 0xfc, 0xc4, 0xfc, 0xe0, 0x9c, 0x38, 0xe3, 0x67, 0x56, 0x9f, 0x81,
-    0xab, 0x37, 0x4c, 0x5a, 0x7f, 0x63, 0xf0, 0x43, 0xc1, 0x5a, 0x7b, 0xcf,
-    0x3f, 0x16, 0x9e, 0x13, 0x05, 0xd5, 0xa3, 0x0f, 0x10, 0x88, 0xa6, 0xf9,
-    0x8b, 0x4f, 0x68, 0x98, 0xeb, 0x43, 0x1b, 0x7d, 0xc5, 0xe7, 0xb3, 0x8f,
-    0x3a, 0xd0, 0xc9, 0xd9, 0x98, 0x4d, 0x4a, 0x44, 0x5d, 0xa7, 0x4f, 0xd5,
-    0xee, 0xc8, 0x65, 0xc5, 0xa6, 0xd3, 0xd6, 0x80, 0x1a, 0x6f, 0xc4, 0x27,
-    0xeb, 0xdc, 0x7d, 0xd7, 0xdb, 0xd6, 0x9d, 0x59, 0xd5, 0xa7, 0x16, 0x79,
-    0x68, 0xe1, 0xb4, 0x21, 0xa9, 0xe0, 0xb6, 0xfa, 0x5a, 0x7f, 0x19, 0xcc,
-    0xf7, 0x07, 0xcb, 0x4c, 0x3d, 0x5a, 0x7e, 0xbf, 0xe5, 0xf5, 0x5c, 0x5a,
-    0x2e, 0x84, 0xc9, 0x19, 0xab, 0x08, 0x04, 0x8b, 0x86, 0x74, 0x2b, 0x3f,
-    0xf5, 0xfc, 0xc0, 0x84, 0x77, 0xcd, 0xfc, 0xb4, 0xff, 0xc1, 0x60, 0xf5,
-    0xbc, 0x36, 0x10, 0xad, 0x3c, 0xe3, 0x1a, 0x7a, 0xd3, 0xfc, 0xe6, 0xae,
-    0x51, 0x5f, 0xf8, 0x56, 0x9f, 0xb9, 0xfd, 0xee, 0x70, 0x56, 0x9e, 0x22,
-    0xcf, 0x2d, 0x0c, 0x99, 0xc0, 0x51, 0xb1, 0x08, 0x49, 0x38, 0x7b, 0xe3,
-    0x09, 0xff, 0xec, 0x26, 0xb9, 0xd6, 0xee, 0x0f, 0x18, 0x2b, 0x4b, 0x6b,
-    0xa1, 0xd1, 0x02, 0xdd, 0x47, 0xc6, 0xdc, 0x71, 0xa3, 0x79, 0xbe, 0x14,
-    0x0f, 0x21, 0x0c, 0x6d, 0xd9, 0x2e, 0x18, 0xc8, 0x51, 0xda, 0x3d, 0x6d,
-    0xe3, 0x35, 0x18, 0x7c, 0x39, 0x28, 0x07, 0xb0, 0xe4, 0x3c, 0x26, 0xb9,
-    0x38, 0x7f, 0x51, 0xad, 0x82, 0x1f, 0x77, 0x49, 0xa1, 0x47, 0xa1, 0xa9,
-    0x62, 0x9e, 0x95, 0x4a, 0xec, 0x23, 0x6e, 0xe3, 0x46, 0xfb, 0x1c, 0x89,
-    0xa5, 0x58, 0xd9, 0xd2, 0x28, 0x72, 0xd1, 0x2a, 0xcf, 0xfe, 0xd8, 0xf4,
-    0xfd, 0xb3, 0xb6, 0xaa, 0xb2, 0xa2, 0x6c, 0x9f, 0xdb, 0x67, 0x6d, 0x55,
-    0x65, 0x45, 0x5b, 0x3f, 0x9e, 0xff, 0xfc, 0x4c, 0xf5, 0xa7, 0xb3, 0x95,
-    0xe5, 0xa4, 0x6d, 0x61, 0xe9, 0x91, 0x9c, 0xea, 0xab, 0x2a, 0x2b, 0x49,
-    0xf1, 0x9b, 0xeb, 0xfd, 0xd6, 0x97, 0x6c, 0x7a, 0x62, 0x4f, 0x3f, 0xfd,
-    0x66, 0xee, 0x02, 0x8f, 0x4f, 0x61, 0xb2, 0xd3, 0xff, 0xcf, 0xd6, 0x13,
-    0x1e, 0xb3, 0xde, 0x63, 0xad, 0x37, 0xbc, 0xc8, 0x98, 0xa4, 0xc9, 0xe7,
-    0xf8, 0x6f, 0x5a, 0x7d, 0xf7, 0xc4, 0xc0, 0x5a, 0x4d, 0xb9, 0xe5, 0x5c,
-    0x22, 0x9f, 0x67, 0x07, 0x0e, 0xb4, 0xff, 0xc5, 0x43, 0x6e, 0x57, 0xf7,
-    0xf4, 0x56, 0x8b, 0xcf, 0xa3, 0x84, 0xb3, 0xf9, 0xed, 0xdb, 0xdb, 0xb7,
-    0xad, 0x3e, 0x73, 0x02, 0x73, 0x75, 0xa7, 0xe2, 0x67, 0x77, 0x7e, 0x96,
-    0x87, 0x0f, 0x64, 0xd1, 0x5c, 0x32, 0x2c, 0xb2, 0x11, 0xb3, 0xf9, 0xf9,
-    0xea, 0x20, 0x7e, 0xb4, 0xb6, 0xba, 0xd5, 0xb9, 0xe3, 0xf0, 0xc2, 0xff,
-    0x8e, 0xf5, 0x09, 0x22, 0x86, 0xaf, 0x89, 0xa7, 0xf6, 0xd9, 0xdb, 0x55,
-    0x59, 0x51, 0x60, 0x4f, 0xbb, 0x6a, 0xab, 0x2a, 0x27, 0x59, 0xff, 0xfd,
-    0xc6, 0xbc, 0x38, 0x7d, 0xb5, 0xac, 0xe0, 0xeb, 0xfb, 0xd6, 0x9f, 0x6c,
-    0x7a, 0x7e, 0xd8, 0x89, 0x77, 0x0c, 0xe7, 0xf3, 0xf5, 0xb1, 0x86, 0x31,
-    0xd6, 0x9f, 0x76, 0xd5, 0x56, 0x54, 0x5b, 0x33, 0xff, 0xfa, 0x9f, 0xb6,
-    0x98, 0x70, 0x23, 0x9a, 0xcf, 0x13, 0x2d, 0x3f, 0xe0, 0x36, 0xb6, 0xe0,
-    0xda, 0xba, 0xb4, 0xff, 0x33, 0xdb, 0xb7, 0xb7, 0x6f, 0x5a, 0x5b, 0x62,
-    0x60, 0xc7, 0x33, 0xa5, 0xc2, 0x3e, 0x9f, 0xff, 0x50, 0x01, 0xfe, 0xb6,
-    0xce, 0xd6, 0xb9, 0x4f, 0x5a, 0x7a, 0xd5, 0x56, 0x54, 0x5c, 0xd2, 0x3a,
-    0xd1, 0xd3, 0x7a, 0xe9, 0x6c, 0xce, 0x1d, 0x69, 0x6d, 0x86, 0xe5, 0xd2,
-    0x29, 0xf7, 0x6d, 0x55, 0x65, 0x45, 0xdf, 0x3f, 0x9f, 0xb6, 0xbb, 0xd1,
-    0x75, 0x69, 0x6d, 0x87, 0xd1, 0x46, 0x73, 0xdb, 0x18, 0x10, 0x2d, 0x0c,
-    0xeb, 0x71, 0xb2, 0xd2, 0x3d, 0xd8, 0xd7, 0x75, 0x71, 0x9c, 0x05, 0xeb,
-    0xe9, 0xe1, 0xad, 0x48, 0x40, 0x8c, 0xf0, 0x90, 0xb5, 0x0c, 0xcf, 0x42,
-    0x43, 0xe9, 0x3c, 0xfb, 0x5a, 0x3d, 0x3d, 0x69, 0xff, 0xb7, 0xb7, 0xf5,
-    0xbf, 0xb3, 0x08, 0xc5, 0xa7, 0x15, 0x6c, 0xc7, 0xdb, 0xe2, 0x79, 0xfc,
-    0x57, 0xe1, 0xaf, 0x31, 0x8b, 0x4f, 0xfb, 0x54, 0x67, 0x05, 0x8b, 0xf6,
-    0x5a, 0x7f, 0xdc, 0xaf, 0x57, 0x37, 0x7e, 0x79, 0x68, 0xc3, 0xfb, 0x13,
-    0xd9, 0xff, 0xff, 0xee, 0x95, 0x3a, 0x59, 0xef, 0x65, 0xec, 0x54, 0x66,
-    0x8e, 0xd8, 0x41, 0x5a, 0x7a, 0xd5, 0x56, 0x54, 0x4a, 0xf3, 0xff, 0xbd,
-    0xcc, 0x7d, 0xb8, 0x21, 0x62, 0xf2, 0xd1, 0xd3, 0xf5, 0x22, 0xd9, 0x9f,
-    0x7a, 0xd3, 0xfe, 0x2a, 0x74, 0x3c, 0x6b, 0xf1, 0xd5, 0xa7, 0xff, 0xe7,
-    0xe0, 0x83, 0x0e, 0x3e, 0xd3, 0x1e, 0xb7, 0xf2, 0xd3, 0xdf, 0xd7, 0x5e,
-    0xb4, 0xff, 0xfe, 0x1f, 0x51, 0xe8, 0x81, 0xc7, 0x68, 0xaf, 0xb0, 0xde,
-    0xb4, 0x05, 0x10, 0x54, 0x45, 0x01, 0x4c, 0xf3, 0x0f, 0xf9, 0x0d, 0xb9,
-    0xff, 0x7a, 0x9f, 0xae, 0x37, 0x7e, 0x85, 0x69, 0xff, 0xbc, 0x37, 0x07,
-    0xce, 0x3d, 0x8b, 0xcb, 0x4e, 0xa7, 0xec, 0xca, 0xfb, 0x5f, 0x0b, 0x00,
-    0x90, 0x64, 0x3b, 0xce, 0x43, 0xa8, 0xd4, 0xfc, 0x6b, 0xf5, 0x02, 0x7f,
-    0xf6, 0x73, 0x62, 0xc0, 0x89, 0x7b, 0x38, 0xb4, 0xef, 0x30, 0x52, 0x9f,
-    0xfd, 0xca, 0x1f, 0x33, 0xc7, 0xb7, 0xfe, 0x04, 0xa7, 0xf5, 0x5b, 0x60,
-    0xf6, 0xe9, 0xd9, 0x8f, 0x97, 0x43, 0x72, 0xda, 0xcb, 0xb6, 0x27, 0x9c,
-    0x1f, 0xf4, 0x25, 0x6e, 0x42, 0xb2, 0x7f, 0xf6, 0xc7, 0xa7, 0xed, 0x9d,
-    0xb5, 0x55, 0x95, 0x13, 0x0c, 0xff, 0xfd, 0x9b, 0x7d, 0xed, 0x03, 0x63,
-    0x3c, 0xf7, 0x5b, 0x4f, 0x5a, 0x7f, 0xe3, 0x6b, 0x37, 0x7f, 0xf5, 0xe2,
-    0x67, 0xad, 0x3f, 0x84, 0x38, 0x7f, 0x9b, 0x9b, 0xad, 0x3f, 0x9a, 0xaf,
-    0xf1, 0x95, 0xd5, 0xa7, 0xd5, 0xd7, 0xd1, 0xd6, 0x82, 0x3d, 0x9f, 0xcc,
-    0xe7, 0xff, 0xc3, 0xde, 0x57, 0xc0, 0xe3, 0xf8, 0xd7, 0x02, 0xcb, 0x4f,
-    0xfd, 0x9b, 0xbb, 0xf7, 0x8d, 0x6e, 0x0b, 0x8b, 0x47, 0x11, 0x3e, 0x4a,
-    0xf3, 0xf1, 0xdb, 0x0b, 0xd7, 0x6b, 0x4b, 0x4b, 0x4f, 0x9b, 0x0b, 0xd7,
-    0x6b, 0x4f, 0xdc, 0x1f, 0x6a, 0xb7, 0xf8, 0x7c, 0xce, 0x17, 0x1c, 0x42,
-    0x7f, 0xff, 0x3a, 0x6b, 0xd9, 0xcf, 0x85, 0x97, 0x8e, 0x16, 0xef, 0xd2,
-    0xd3, 0xe7, 0x7d, 0x9c, 0xb2, 0xd2, 0x2c, 0x44, 0x6d, 0x32, 0xcf, 0xff,
-    0x37, 0x8a, 0x81, 0xcc, 0x10, 0xff, 0xed, 0x2d, 0x3f, 0x5c, 0xfb, 0xe2,
-    0x60, 0x2d, 0x3f, 0xf9, 0xbc, 0x06, 0x7e, 0x6f, 0xeb, 0xff, 0x75, 0x68,
-    0x63, 0xfd, 0x13, 0x09, 0xfc, 0x0a, 0x07, 0x7a, 0x3d, 0x5a, 0x7e, 0xd0,
-    0x98, 0x7a, 0xf2, 0xd3, 0xff, 0xfe, 0xee, 0x5c, 0x62, 0xf7, 0xcf, 0xa4,
-    0xdc, 0xa1, 0xf3, 0x7b, 0x4b, 0x4f, 0xc5, 0x9a, 0xf9, 0x6b, 0xad, 0x68,
-    0xdd, 0x19, 0xdd, 0x2d, 0xb8, 0xdd, 0x3d, 0xf2, 0xe1, 0xab, 0xd6, 0x8c,
-    0x3d, 0xc3, 0x0c, 0xe7, 0xfb, 0x8c, 0x5e, 0xa3, 0x8f, 0x96, 0x9f, 0xff,
-    0x70, 0xb3, 0xdc, 0x1c, 0xdf, 0xd9, 0x71, 0xb4, 0xb4, 0xe6, 0x07, 0xd5,
-    0xa3, 0x0f, 0xc8, 0x95, 0x67, 0xab, 0xe8, 0x71, 0x69, 0x6d, 0x75, 0xaf,
-    0x3f, 0x32, 0x48, 0x61, 0x23, 0x90, 0xc1, 0xb4, 0x22, 0x1c, 0x87, 0x17,
-    0x49, 0xb9, 0x0c, 0xb0, 0x10, 0x14, 0x6b, 0x9a, 0x22, 0xf4, 0x2a, 0x3f,
-    0x20, 0x9f, 0xfe, 0xe8, 0xee, 0xfd, 0x0f, 0xb8, 0xdd, 0xf3, 0x2d, 0x3e,
-    0xed, 0xaa, 0xac, 0xa8, 0xab, 0xa7, 0x75, 0x8e, 0xb4, 0xff, 0x3f, 0x6c,
-    0xed, 0xaa, 0xac, 0xa8, 0x8f, 0x27, 0xf9, 0x9e, 0xdd, 0xbd, 0xbb, 0x7a,
-    0xd2, 0xd8, 0x29, 0x8d, 0xe2, 0x7f, 0x4c, 0xe8, 0x6c, 0x91, 0x67, 0xdd,
-    0xb5, 0x55, 0x95, 0x16, 0x0c, 0xe3, 0x1a, 0xf5, 0xa7, 0xff, 0xe2, 0xfe,
-    0xaf, 0x3e, 0x5d, 0xff, 0xdc, 0xeb, 0xfe, 0xbd, 0x69, 0xf6, 0x16, 0x7b,
-    0x4b, 0x4f, 0xee, 0xd1, 0xfe, 0xf6, 0xb7, 0x5a, 0x5b, 0x62, 0x61, 0x86,
-    0x19, 0xd8, 0x76, 0x98, 0xbe, 0x92, 0xcf, 0xed, 0xb3, 0xb6, 0xaa, 0xb2,
-    0xa2, 0xca, 0x9f, 0xdb, 0x67, 0x6d, 0x55, 0x65, 0x45, 0xa7, 0x3e, 0x36,
-    0xe6, 0xdb, 0x74, 0x5d, 0x17, 0x52, 0xd3, 0xfd, 0x75, 0xf0, 0x5d, 0x0d,
-    0x55, 0x96, 0x9f, 0xeb, 0xaf, 0xe9, 0xf3, 0xda, 0x1d, 0x2d, 0x3f, 0xff,
-    0x0f, 0x28, 0xbc, 0xfc, 0xee, 0x31, 0x16, 0x79, 0x69, 0xf5, 0xca, 0x0e,
-    0x1d, 0x68, 0x79, 0xfe, 0xe2, 0xac, 0xfe, 0xcd, 0x7c, 0xef, 0x7f, 0xe2,
-    0xd3, 0xff, 0xe6, 0x2b, 0x70, 0x78, 0x3d, 0x67, 0x1d, 0xce, 0x2d, 0x3c,
-    0xdf, 0x5b, 0x8b, 0x4f, 0x5a, 0xaa, 0xca, 0x8b, 0x72, 0x7f, 0xe6, 0xce,
-    0xe1, 0x7c, 0xe6, 0x6e, 0xea, 0xd1, 0xba, 0x25, 0x3a, 0x45, 0xa2, 0xd9,
-    0xc7, 0x21, 0x5a, 0x44, 0xb4, 0xff, 0x73, 0xfa, 0xd6, 0x61, 0x18, 0xb4,
-    0xfb, 0x55, 0xbd, 0x05, 0x69, 0x08, 0x4f, 0x7f, 0xc7, 0x10, 0xc8, 0xaf,
-    0xc1, 0xae, 0x37, 0x4f, 0xf3, 0x17, 0xe7, 0x6d, 0x78, 0x56, 0x9e, 0x0b,
-    0x67, 0x56, 0x9f, 0x7c, 0xdf, 0x42, 0x62, 0xd2, 0xab, 0xcf, 0x2f, 0x72,
-    0x09, 0xed, 0x00, 0x7c, 0xb4, 0x51, 0xe5, 0x7d, 0x29, 0x9f, 0xfb, 0xc2,
-    0x06, 0x78, 0x78, 0xc5, 0x65, 0xa1, 0x69, 0xdf, 0xd7, 0x96, 0x9b, 0xf6,
-    0x5a, 0x1e, 0x6c, 0xbc, 0x39, 0x0b, 0x4f, 0x6f, 0x61, 0xea, 0xd3, 0x98,
-    0xfb, 0x62, 0x22, 0x77, 0x3c, 0x39, 0x0f, 0x82, 0xa1, 0x93, 0x1a, 0x18,
-    0x65, 0xce, 0x2f, 0x5d, 0xad, 0x3f, 0xcf, 0xdb, 0x3b, 0x6a, 0xab, 0x2a,
-    0x28, 0x78, 0x13, 0xe3, 0xa1, 0xe9, 0xf0, 0x1a, 0xd8, 0x75, 0xa7, 0x99,
-    0xcc, 0x0a, 0xd2, 0x6e, 0x9e, 0x3e, 0x89, 0xa7, 0xfd, 0x41, 0x60, 0xf0,
-    0x48, 0x4e, 0xb4, 0xff, 0xda, 0x62, 0x73, 0x08, 0x15, 0xec, 0x5a, 0x0e,
-    0x7f, 0x9c, 0x3b, 0x9f, 0xfb, 0xf7, 0xf2, 0xbb, 0xbf, 0x98, 0x6f, 0x5a,
-    0x7f, 0x99, 0xed, 0xdb, 0xdb, 0xb7, 0xad, 0x3e, 0x1f, 0x6a, 0x85, 0x69,
-    0xfe, 0xe8, 0x3b, 0x45, 0xec, 0x02, 0xd0, 0x03, 0xdc, 0xfc, 0x96, 0x7f,
-    0xb0, 0x8a, 0xbd, 0xf5, 0xac, 0xb4, 0xff, 0x87, 0x7d, 0x7c, 0xf7, 0xc0,
-    0xe1, 0x2d, 0x3e, 0xad, 0xf5, 0xe1, 0x5a, 0x38, 0x8a, 0x02, 0x37, 0xd2,
-    0x14, 0xfa, 0xbf, 0x31, 0xbe, 0xad, 0x3e, 0xba, 0xf3, 0xad, 0xa5, 0xa1,
-    0xc3, 0xd5, 0x22, 0xa9, 0xfe, 0xad, 0x33, 0x9b, 0xbf, 0x2e, 0x2d, 0x3f,
-    0xfe, 0x0f, 0x1b, 0xee, 0xde, 0x2a, 0x06, 0xb4, 0xc0, 0x4a, 0x60, 0xe2,
-    0xd1, 0x87, 0xd8, 0x2a, 0xf3, 0xfb, 0x94, 0x07, 0x09, 0x82, 0xb4, 0xb6,
-    0x36, 0x59, 0x50, 0xd7, 0x52, 0x21, 0xb1, 0x3d, 0x68, 0x5e, 0x3c, 0x84,
-    0x26, 0xd9, 0x0e, 0x8b, 0x43, 0x80, 0x4b, 0x9c, 0x86, 0x67, 0x63, 0x3d,
-    0x3c, 0x22, 0xb8, 0xcf, 0x50, 0xa3, 0x01, 0x11, 0x23, 0x6a, 0x12, 0xbe,
-    0x86, 0x1f, 0xf0, 0x84, 0xb8, 0x45, 0x77, 0x0a, 0x7f, 0xa4, 0x13, 0xfb,
-    0x6c, 0xed, 0xaa, 0xac, 0xa8, 0xbc, 0xe1, 0x9b, 0x7f, 0xf7, 0xad, 0x85,
-    0x5f, 0x27, 0xb7, 0xf7, 0x8f, 0xff, 0xb1, 0xad, 0x9d, 0x4f, 0x87, 0xe5,
-    0x4a, 0xc5, 0xb9, 0x1b, 0xf4, 0xfe, 0xdb, 0x3b, 0x6a, 0xab, 0x2a, 0x29,
-    0x69, 0xf7, 0x6d, 0x55, 0x65, 0x45, 0x85, 0x3f, 0xfe, 0x6c, 0x20, 0xb7,
-    0x1b, 0x7f, 0x61, 0x51, 0xd6, 0x9f, 0xbf, 0xe8, 0xdf, 0x47, 0x5a, 0x5b,
-    0x62, 0x2c, 0x8e, 0x67, 0x76, 0xa3, 0x3f, 0xb6, 0xce, 0xda, 0xaa, 0xca,
-    0x8b, 0x2e, 0x7b, 0x63, 0x0d, 0x89, 0xb2, 0xb4, 0xed, 0xbe, 0x9d, 0x69,
-    0x6a, 0xc7, 0x9d, 0xf9, 0x7c, 0x80, 0xb4, 0xc6, 0x5e, 0xb4, 0xd5, 0xd7,
-    0x9a, 0x8c, 0x10, 0x9f, 0xd7, 0xef, 0xa6, 0x0f, 0x85, 0x69, 0xf3, 0x65,
-    0xc6, 0xd2, 0xd3, 0x13, 0x51, 0xed, 0xba, 0x69, 0x3d, 0x4f, 0x78, 0x56,
-    0x9f, 0xab, 0xad, 0xea, 0xe2, 0xd3, 0x9d, 0x75, 0xd4, 0xa7, 0xf9, 0x9f,
-    0xbf, 0xba, 0xd9, 0xba, 0x5b, 0x17, 0xf3, 0x36, 0x96, 0x80, 0xa3, 0x27,
-    0x84, 0x24, 0x95, 0x71, 0x26, 0x7e, 0x1a, 0xd0, 0x35, 0xfa, 0xd3, 0xff,
-    0xf7, 0x07, 0xdc, 0xcd, 0x16, 0x1f, 0xfd, 0x72, 0x9e, 0xb4, 0xfe, 0x67,
-    0xfa, 0xb9, 0x41, 0x5a, 0x31, 0x11, 0x7d, 0x5a, 0x93, 0xd6, 0x93, 0xd6,
-    0x93, 0xd6, 0x86, 0x36, 0x06, 0x08, 0x08, 0x84, 0xff, 0xfb, 0xda, 0x1b,
-    0x61, 0x75, 0x8b, 0x03, 0x86, 0x2d, 0x2d, 0xd6, 0x9b, 0x5f, 0xad, 0x18,
-    0x7f, 0x5a, 0x52, 0xf0, 0x8c, 0xc2, 0xcb, 0x4f, 0xc4, 0xc7, 0x26, 0xc5,
-    0xa6, 0x7b, 0x2d, 0x01, 0x3d, 0x27, 0x05, 0x3f, 0x29, 0x9f, 0xff, 0xfe,
-    0xe3, 0x7b, 0x43, 0xad, 0x37, 0xb8, 0x2d, 0xd0, 0x1e, 0x9e, 0xff, 0x18,
-    0xb4, 0xcc, 0x75, 0xa7, 0xff, 0xe7, 0xb1, 0x7e, 0xf7, 0xb7, 0xb9, 0x87,
-    0xfa, 0xc0, 0x5a, 0x6b, 0x6c, 0xcb, 0xab, 0x57, 0xa8, 0x86, 0x10, 0xd9,
-    0x0f, 0x5b, 0x1f, 0x76, 0x17, 0x14, 0xa4, 0x50, 0xa7, 0xd4, 0x20, 0x3c,
-    0x63, 0x76, 0xfb, 0xf4, 0x56, 0x7f, 0xf6, 0xc7, 0xa7, 0xed, 0x9d, 0xb5,
-    0x55, 0x95, 0x14, 0x64, 0xfa, 0xe3, 0x75, 0x80, 0xb4, 0xf8, 0xa8, 0x0d,
-    0xf5, 0x69, 0x6c, 0xc7, 0x9f, 0xc2, 0x88, 0x7b, 0x22, 0xbf, 0xb0, 0xf1,
-    0x39, 0xcd, 0x4e, 0xf3, 0xea, 0x1a, 0x1e, 0x85, 0x34, 0xff, 0xdb, 0x53,
-    0xf6, 0xce, 0xda, 0xaa, 0xca, 0x88, 0xe6, 0x7f, 0xf6, 0xc7, 0xa7, 0xed,
-    0x9d, 0xb5, 0x55, 0x95, 0x13, 0x94, 0xfe, 0xdb, 0x3b, 0x6a, 0xab, 0x2a,
-    0x2c, 0xc9, 0xfe, 0x7e, 0xa8, 0xfb, 0x73, 0xc0, 0x5a, 0x7f, 0x8d, 0x80,
-    0x70, 0xed, 0xbb, 0x1d, 0x69, 0xfe, 0x07, 0x5b, 0xdc, 0xad, 0xde, 0xb4,
-    0xfe, 0xcd, 0x77, 0xb9, 0xbe, 0x96, 0x96, 0xc6, 0xca, 0x2a, 0x98, 0xf9,
-    0xe7, 0x33, 0xfb, 0x6c, 0xed, 0xaa, 0xac, 0xa8, 0xb7, 0x67, 0xe2, 0xad,
-    0xbb, 0x7f, 0x16, 0x9c, 0x3b, 0x81, 0x69, 0xff, 0x53, 0xf6, 0xce, 0xda,
-    0xaa, 0xca, 0x8a, 0x42, 0x5b, 0x59, 0x12, 0x9d, 0x2e, 0x38, 0xe4, 0xff,
-    0xdb, 0x53, 0xf6, 0xce, 0xda, 0xaa, 0xca, 0x89, 0x4a, 0x2f, 0x56, 0xc2,
-    0xe2, 0x89, 0xd5, 0xe8, 0xfc, 0x10, 0xe4, 0x23, 0xbf, 0x43, 0x4c, 0xd1,
-    0xbc, 0xfb, 0x61, 0xd7, 0xe7, 0x5a, 0x7f, 0xd4, 0xfd, 0xb3, 0xb6, 0xaa,
-    0xb2, 0xa2, 0x76, 0x9a, 0xf3, 0x75, 0xa7, 0xff, 0xc2, 0x1f, 0xce, 0xc6,
-    0xa8, 0x24, 0xc5, 0x96, 0x5a, 0x7f, 0x99, 0xed, 0xdb, 0xdb, 0xb7, 0xad,
-    0x2d, 0x8e, 0x8f, 0x1e, 0x25, 0x50, 0xd1, 0x2a, 0x4f, 0xff, 0x6d, 0xf6,
-    0xee, 0x88, 0x19, 0xe6, 0x21, 0x02, 0xd3, 0xff, 0x51, 0xf9, 0x96, 0xae,
-    0x37, 0xd7, 0xad, 0x3f, 0xf1, 0x67, 0x2a, 0xfc, 0xd1, 0x56, 0xeb, 0x4d,
-    0x77, 0xb0, 0x51, 0x0d, 0xa4, 0x48, 0x7a, 0xa6, 0x73, 0xc6, 0x35, 0xa4,
-    0x2b, 0xb8, 0x6c, 0x4f, 0xff, 0xc1, 0xaf, 0x6d, 0x9a, 0x62, 0xdc, 0x1a,
-    0xd3, 0x01, 0x69, 0xf7, 0x6d, 0x55, 0x65, 0x44, 0x59, 0x3f, 0xea, 0x7e,
-    0xd9, 0xdb, 0x55, 0x59, 0x51, 0x2e, 0xcf, 0xff, 0xd8, 0x1e, 0x37, 0xdd,
-    0xbc, 0x54, 0x0d, 0x69, 0x80, 0x94, 0xb6, 0xc4, 0x6c, 0x9c, 0xce, 0xed,
-    0x2a, 0x7f, 0xf6, 0xc7, 0xa7, 0xed, 0x9d, 0xb5, 0x55, 0x95, 0x13, 0x14,
-    0xfb, 0xb6, 0xaa, 0xb2, 0xa2, 0xa9, 0x96, 0x2d, 0x18, 0x78, 0x46, 0x19,
-    0xcf, 0xff, 0xfe, 0xed, 0x73, 0x77, 0xe7, 0xb6, 0xe5, 0x6b, 0xa2, 0xef,
-    0xb8, 0x3d, 0x7a, 0xd1, 0xb2, 0x27, 0x28, 0x8a, 0x7f, 0xf6, 0xc7, 0xa7,
-    0xed, 0x9d, 0xb5, 0x55, 0x95, 0x13, 0xa4, 0xfe, 0x1a, 0xeb, 0x3e, 0xae,
-    0x2d, 0x3e, 0x71, 0x9c, 0x6d, 0x2d, 0x3f, 0x3b, 0x83, 0x73, 0x09, 0x68,
-    0x13, 0xd5, 0xd1, 0x44, 0xe1, 0xe3, 0x2d, 0xb1, 0xa1, 0x9f, 0xfb, 0xfd,
-    0x79, 0xb7, 0xdb, 0xf7, 0x04, 0xeb, 0x41, 0xcf, 0xd3, 0x85, 0x73, 0xfe,
-    0xa7, 0xed, 0x9d, 0xb5, 0x55, 0x95, 0x13, 0xbc, 0xfb, 0xdf, 0xd1, 0xc5,
-    0x29, 0xff, 0x13, 0x7b, 0x35, 0x99, 0xbb, 0xd6, 0x96, 0xc1, 0x4f, 0xaf,
-    0x23, 0x1c, 0x39, 0x15, 0x25, 0x78, 0x9e, 0x7f, 0xf6, 0xc7, 0xa7, 0xed,
-    0x9d, 0xb5, 0x55, 0x95, 0x14, 0x2c, 0xff, 0xff, 0xf0, 0xf3, 0xf3, 0x9e,
-    0x9f, 0xb5, 0xb9, 0xff, 0x98, 0xb2, 0xf3, 0x3f, 0x67, 0x16, 0x9f, 0xfd,
-    0xb1, 0xe9, 0xfb, 0x67, 0x6d, 0x55, 0x65, 0x45, 0x25, 0x3f, 0xff, 0xb3,
-    0x5b, 0x7d, 0xc7, 0x39, 0x47, 0xf7, 0x1b, 0xdf, 0x9d, 0x68, 0x65, 0xef,
-    0x3b, 0xe3, 0x34, 0x79, 0xcd, 0xa3, 0x35, 0xe9, 0x19, 0xe5, 0x21, 0x01,
-    0x5b, 0xca, 0xff, 0xc2, 0x0e, 0xed, 0x5e, 0x7f, 0x6d, 0x9d, 0xb5, 0x55,
-    0x95, 0x11, 0x24, 0xff, 0xed, 0x8f, 0x4f, 0xdb, 0x3b, 0x6a, 0xab, 0x2a,
-    0x25, 0xe9, 0xee, 0xff, 0xed, 0x2d, 0x3e, 0xe8, 0x0e, 0x3a, 0x5a, 0x7f,
-    0x09, 0x7b, 0xe9, 0xc9, 0x96, 0x9f, 0xfd, 0xcb, 0x8c, 0x40, 0x37, 0xc0,
-    0xe7, 0x77, 0x5a, 0x66, 0xf2, 0xd3, 0xff, 0xbf, 0x08, 0xf7, 0xeb, 0x86,
-    0xbf, 0xa2, 0x71, 0x68, 0x7a, 0x39, 0x84, 0xc8, 0x09, 0xda, 0x15, 0x9f,
-    0xfa, 0x9c, 0xd3, 0x5c, 0xae, 0x36, 0xee, 0x2d, 0x3f, 0xf3, 0x9f, 0x3e,
-    0x93, 0x5c, 0xab, 0x8c, 0xe2, 0xd0, 0xb4, 0x31, 0xeb, 0x62, 0x64, 0xdd,
-    0x65, 0xa0, 0x2a, 0x8f, 0x84, 0x8d, 0xc8, 0xc3, 0x7a, 0x79, 0x72, 0x13,
-    0xa6, 0x88, 0x27, 0xf8, 0x68, 0xbf, 0xf3, 0x8c, 0x62, 0xd3, 0xc3, 0x78,
-    0x0d, 0xd6, 0x9e, 0xb5, 0x55, 0x95, 0x14, 0xbc, 0x38, 0x7a, 0x5d, 0x25,
-    0x9f, 0x17, 0xaf, 0xc7, 0x56, 0x9f, 0xf3, 0x13, 0x73, 0xe7, 0xe5, 0xfd,
-    0x96, 0x9d, 0xfd, 0x69, 0x69, 0xed, 0x67, 0xb4, 0xb4, 0x04, 0xff, 0x5c,
-    0x40, 0xf0, 0xe4, 0xff, 0x03, 0x5d, 0x6d, 0xde, 0x27, 0x5a, 0x7f, 0xaa,
-    0xff, 0x97, 0xfe, 0xe3, 0x1b, 0xad, 0x0c, 0x7f, 0x5f, 0x9c, 0xcf, 0xf0,
-    0xe9, 0xc1, 0x2f, 0x30, 0x16, 0x87, 0x9e, 0xc9, 0xc8, 0xa7, 0xfe, 0xed,
-    0xc6, 0x07, 0xce, 0x31, 0xe8, 0x96, 0x8c, 0x3e, 0x81, 0x22, 0x9d, 0xd6,
-    0x3a, 0xd3, 0xf3, 0x13, 0x9e, 0x13, 0x16, 0x9f, 0xba, 0x06, 0xb6, 0x1d,
-    0x69, 0x9f, 0x8b, 0x4e, 0x60, 0x69, 0x68, 0x63, 0xdc, 0x09, 0x63, 0xa2,
-    0xb3, 0xee, 0x7e, 0x66, 0x12, 0xd3, 0xfc, 0xdc, 0xd5, 0x79, 0xba, 0x69,
-    0x69, 0xff, 0x1e, 0x83, 0xf5, 0xc7, 0xb1, 0x6e, 0xb4, 0x04, 0xfe, 0x84,
-    0xe6, 0x7b, 0xa0, 0xfb, 0x71, 0x69, 0xc2, 0xef, 0x96, 0x8e, 0x1e, 0x16,
-    0x89, 0xa0, 0x29, 0x93, 0xf2, 0x14, 0x5e, 0x63, 0x9f, 0xff, 0x8e, 0xcf,
-    0x26, 0xbf, 0xeb, 0x9a, 0xe6, 0x1a, 0xe8, 0x16, 0x9c, 0xd7, 0x34, 0xb4,
-    0xec, 0xee, 0x96, 0x8b, 0x1b, 0x8b, 0x83, 0xb3, 0xfc, 0x06, 0x07, 0xdb,
-    0x8c, 0x46, 0x96, 0x8c, 0x3e, 0x01, 0x23, 0x9f, 0xff, 0xfb, 0x8d, 0xdd,
-    0xec, 0x3b, 0xfc, 0x32, 0xbe, 0x6b, 0x95, 0x66, 0x20, 0xad, 0x3f, 0xb9,
-    0x4e, 0x0f, 0x5a, 0xf5, 0xa6, 0xc3, 0xad, 0x01, 0x45, 0xfd, 0x3b, 0xdc,
-    0x33, 0x9f, 0x1a, 0x13, 0xb6, 0x96, 0x9f, 0x55, 0xcc, 0xee, 0x96, 0x80,
-    0x9e, 0x81, 0xca, 0x27, 0xdc, 0xa2, 0x13, 0xad, 0x0c, 0x78, 0xf8, 0x45,
-    0x30, 0x2c, 0xb4, 0xb4, 0xb4, 0xc2, 0x66, 0x8d, 0x37, 0xe2, 0xd2, 0xd9,
-    0x99, 0x11, 0x21, 0x68, 0xc8, 0x45, 0xee, 0x46, 0x30, 0xa5, 0x72, 0x36,
-    0xbe, 0x90, 0x1c, 0x6f, 0x90, 0x89, 0xa8, 0xd5, 0x80, 0x6c, 0x50, 0xf8,
-    0xd4, 0x37, 0xfd, 0x0c, 0x8b, 0xb4, 0x69, 0xfd, 0xb6, 0x76, 0xd5, 0x56,
-    0x54, 0x53, 0x93, 0xfe, 0x1e, 0xd6, 0xb9, 0x98, 0x56, 0x5a, 0x7f, 0x09,
-    0xc2, 0xda, 0xfc, 0x96, 0x9f, 0xf8, 0xc1, 0xdf, 0x45, 0x81, 0xe5, 0x3a,
-    0xb4, 0xff, 0xb3, 0x8d, 0xdc, 0xd9, 0xd7, 0x5d, 0x4a, 0x61, 0x75, 0x69,
-    0xaf, 0xd8, 0x29, 0x84, 0xf0, 0xef, 0xc6, 0x57, 0x68, 0xa6, 0x90, 0x67,
-    0xdd, 0xb5, 0x55, 0x95, 0x15, 0xe4, 0xff, 0xfd, 0x81, 0xe3, 0x7d, 0xdb,
-    0xc5, 0x40, 0xd6, 0x98, 0x09, 0x4b, 0x6c, 0x44, 0x7d, 0xd9, 0x9c, 0xff,
-    0xdb, 0x53, 0xf6, 0xce, 0xda, 0xaa, 0xca, 0x89, 0x1e, 0x70, 0x81, 0x96,
-    0x9d, 0x6c, 0x3a, 0x5b, 0x17, 0x53, 0xee, 0xda, 0xaa, 0xca, 0x89, 0x22,
-    0x7f, 0xfe, 0x61, 0xe8, 0x9a, 0x62, 0xbd, 0xbc, 0x3c, 0xab, 0xd6, 0x9e,
-    0xda, 0x9f, 0xb3, 0x22, 0xe3, 0x0a, 0xf8, 0x67, 0x3f, 0xf6, 0xd4, 0xfd,
-    0xb3, 0xb6, 0xaa, 0xb2, 0xa2, 0x4a, 0x9f, 0x76, 0xd5, 0x56, 0x54, 0x5e,
-    0x33, 0xed, 0x6b, 0xd9, 0x65, 0xa7, 0xf9, 0xfb, 0x67, 0x6d, 0x55, 0x65,
-    0x44, 0x9b, 0x2d, 0xb1, 0x13, 0xfd, 0x33, 0xa2, 0x79, 0x9d, 0xe2, 0xd3,
-    0x00, 0x96, 0x9a, 0xef, 0x66, 0x35, 0x9f, 0x45, 0xe1, 0x9b, 0x1a, 0xcb,
-    0xcf, 0xdf, 0x4b, 0x1e, 0x0c, 0x60, 0x23, 0x1a, 0x43, 0x90, 0xed, 0x39,
-    0x67, 0x23, 0x23, 0xf2, 0x3f, 0xf0, 0xf0, 0xfa, 0xc3, 0x0d, 0x2a, 0x9d,
-    0x56, 0xf9, 0x47, 0xcf, 0x9c, 0x22, 0x0c, 0xb2, 0x2c, 0xbe, 0x00, 0x43,
-    0x25, 0x87, 0x5a, 0xdc, 0xc3, 0x6f, 0x4b, 0x26, 0x1a, 0x41, 0xc1, 0xbc,
-    0xa1, 0xb7, 0x2b, 0xfc, 0x9e, 0xd6, 0xa4, 0xc7, 0xc7, 0x7b, 0x57, 0x29,
-    0x0c, 0x55, 0x68, 0x28, 0xc1, 0x3a, 0xb3, 0x74, 0xc6, 0xa8, 0x54, 0xb6,
-    0xbd, 0x53, 0xa2, 0x3d, 0x6d, 0x15, 0x3f, 0xaf, 0xbe, 0xee, 0x52, 0x58,
-    0x9d, 0x97, 0xa5, 0x77, 0x2b, 0x9b, 0xec, 0xfa, 0x01, 0xaa, 0xc9, 0x5a,
-    0x00,
+    0xfe, 0xbb, 0x3b, 0x6a, 0xab, 0x1a, 0x22, 0x59, 0xcd, 0x15, 0x73, 0xa6,
+    0xdf, 0xc7, 0x4f, 0xff, 0x3f, 0x1d, 0xa3, 0x4a, 0x6e, 0xd7, 0xcf, 0x1d,
+    0x35, 0x68, 0xe8, 0x69, 0xfd, 0x04, 0x5d, 0x13, 0xa7, 0xff, 0x6b, 0xf5,
+    0xf0, 0x73, 0x7f, 0x0d, 0x70, 0xe9, 0xd5, 0x56, 0x34, 0x45, 0xb0, 0xd3,
+    0xf1, 0xb2, 0x54, 0xdd, 0xd1, 0xd1, 0xd3, 0x71, 0xa2, 0x29, 0xfe, 0x64,
+    0x53, 0x48, 0x3b, 0xb4, 0xe9, 0xc1, 0x4d, 0x8e, 0x84, 0x3d, 0x4a, 0x38,
+    0x9f, 0xfc, 0xf6, 0xeb, 0xa8, 0xe3, 0xe5, 0x62, 0xac, 0x55, 0x93, 0xa7,
+    0xff, 0x20, 0x8b, 0xef, 0xf7, 0x3b, 0xac, 0x64, 0xe9, 0xb3, 0x72, 0xa4,
+    0xe5, 0x48, 0x1d, 0x34, 0xa0, 0x16, 0x9f, 0xde, 0xce, 0x81, 0x69, 0xa2,
+    0xae, 0x34, 0xf3, 0xf3, 0x78, 0x97, 0xb1, 0x83, 0xa1, 0xcf, 0xca, 0x90,
+    0xe7, 0xee, 0x25, 0x9d, 0x68, 0x74, 0xfe, 0x70, 0x6d, 0x4d, 0x75, 0x73,
+    0xa4, 0x2e, 0x7c, 0x02, 0x57, 0x2b, 0x95, 0x82, 0xe0, 0x5b, 0xc2, 0x63,
+    0x21, 0xaf, 0xc7, 0x51, 0x20, 0xd2, 0xd5, 0xfc, 0x61, 0x1f, 0x61, 0x01,
+    0x3f, 0xff, 0xf5, 0x2e, 0xe4, 0xef, 0x7f, 0xef, 0x5c, 0x71, 0x44, 0xe7,
+    0x33, 0xe9, 0xd3, 0xee, 0xda, 0xaa, 0xc6, 0x8a, 0x8a, 0x7f, 0xfd, 0x4d,
+    0x17, 0xd6, 0x6f, 0x61, 0xac, 0xde, 0xc7, 0x4a, 0xec, 0x44, 0x35, 0xe3,
+    0x39, 0xff, 0x07, 0x17, 0x75, 0xfe, 0x0a, 0x78, 0xe9, 0xfd, 0x99, 0xb0,
+    0x5f, 0x02, 0x74, 0xd5, 0xf9, 0xd3, 0xdc, 0x4e, 0x5c, 0xa1, 0xe3, 0xb2,
+    0x63, 0x3e, 0xed, 0xaa, 0xac, 0x68, 0xaf, 0x67, 0xc8, 0xaa, 0xdf, 0xec,
+    0x74, 0xce, 0x03, 0xa5, 0x76, 0x1f, 0x9f, 0x4c, 0xc0, 0x57, 0x3f, 0xf5,
+    0xd4, 0xdb, 0xb3, 0xb6, 0xaa, 0xb1, 0xa2, 0x46, 0x9f, 0xfd, 0x72, 0xe9,
+    0xb7, 0x67, 0x6d, 0x55, 0x63, 0x44, 0xf1, 0x3f, 0xfa, 0xe5, 0xd3, 0x6e,
+    0xce, 0xda, 0xaa, 0xc6, 0x89, 0xfe, 0x7f, 0xf5, 0xcb, 0xa6, 0xdd, 0x9d,
+    0xb5, 0x55, 0x8d, 0x14, 0x34, 0xff, 0xcb, 0xa6, 0xdd, 0x9d, 0xb5, 0x55,
+    0x8d, 0x14, 0x44, 0xff, 0x9b, 0x77, 0xfa, 0xf8, 0xfa, 0x76, 0x9d, 0x17,
+    0x22, 0x49, 0xd4, 0x27, 0xfc, 0xc2, 0x73, 0x7c, 0xf0, 0x71, 0x67, 0x4f,
+    0xbb, 0x6a, 0xab, 0x1a, 0x29, 0x19, 0xfe, 0x76, 0xbf, 0x76, 0x7e, 0xec,
+    0x74, 0xea, 0x6d, 0xd8, 0x7d, 0x82, 0x67, 0x3f, 0xff, 0x60, 0x78, 0xff,
+    0x6e, 0xf0, 0xd0, 0x35, 0xa7, 0x01, 0x52, 0xb9, 0xd3, 0x39, 0x5c, 0x2a,
+    0xef, 0xcc, 0xa7, 0xfe, 0xba, 0x9b, 0x76, 0x76, 0xd5, 0x56, 0x34, 0x4a,
+    0x11, 0xb3, 0x2d, 0x19, 0xb3, 0x89, 0x41, 0x84, 0xc5, 0xa1, 0xf4, 0x85,
+    0x6a, 0xf0, 0x87, 0xec, 0x2b, 0xd6, 0x6b, 0xc5, 0x10, 0x2b, 0xdf, 0x4a,
+    0xfa, 0x87, 0x4f, 0xf1, 0xae, 0x2a, 0x3f, 0x9f, 0xfd, 0x72, 0xe9, 0xb7,
+    0x67, 0x6d, 0x55, 0x63, 0x44, 0xe7, 0x3f, 0xfa, 0xe5, 0xd3, 0x6e, 0xce,
+    0xda, 0xaa, 0xc6, 0x8a, 0x26, 0x7e, 0x4d, 0x30, 0xd4, 0x01, 0xd3, 0xf9,
+    0xf6, 0xfb, 0x7f, 0x42, 0x03, 0xa7, 0x75, 0xb7, 0x70, 0xf9, 0x3e, 0x96,
+    0xc7, 0x53, 0x49, 0xd2, 0xbf, 0xf0, 0xbb, 0x9f, 0x76, 0xd5, 0x56, 0x34,
+    0x43, 0x93, 0xf7, 0xf6, 0xea, 0x38, 0x9d, 0x2b, 0xb0, 0xf7, 0xf8, 0x67,
+    0x3f, 0xcf, 0xdc, 0xb7, 0x1f, 0x76, 0x9d, 0x3d, 0x6a, 0xab, 0x1a, 0x22,
+    0xf9, 0xf6, 0x30, 0xda, 0xd1, 0xd1, 0xd3, 0xd4, 0xfa, 0x5b, 0x3f, 0xb5,
+    0x81, 0xe6, 0x02, 0x8e, 0x98, 0x76, 0x3a, 0x7f, 0xbc, 0x2e, 0xbf, 0xa1,
+    0xe3, 0x9d, 0x0e, 0x79, 0xe8, 0x2d, 0x36, 0xb7, 0x3a, 0x7b, 0xcd, 0x75,
+    0x0a, 0x85, 0x9b, 0x9a, 0x17, 0x9f, 0x56, 0xde, 0xce, 0x1d, 0x2b, 0xb6,
+    0x4f, 0x43, 0x21, 0x18, 0xc1, 0x27, 0x21, 0x00, 0x2b, 0x37, 0xe4, 0x13,
+    0xff, 0xae, 0x5d, 0x36, 0xec, 0xed, 0xaa, 0xac, 0x68, 0x99, 0x27, 0xf5,
+    0xd9, 0xdb, 0x55, 0x58, 0xd1, 0x6f, 0x4f, 0xfe, 0xb9, 0x74, 0xdb, 0xb3,
+    0xb6, 0xaa, 0xb1, 0xa2, 0x93, 0x99, 0x5a, 0xbe, 0x0e, 0x9f, 0xb7, 0x07,
+    0xde, 0xd0, 0x0e, 0x9b, 0x97, 0x5f, 0x27, 0xa1, 0x44, 0x10, 0xea, 0xf5,
+    0x1b, 0x1f, 0xc6, 0x36, 0x69, 0x5e, 0xf1, 0xff, 0xd8, 0x53, 0xcf, 0xeb,
+    0xb3, 0xb6, 0xaa, 0xb1, 0xa2, 0x1d, 0x9f, 0x76, 0xd5, 0x56, 0x34, 0x4b,
+    0x13, 0xd8, 0x05, 0xa1, 0xd3, 0xeb, 0x97, 0x4d, 0xbb, 0x0f, 0x4e, 0xfc,
+    0xce, 0x7f, 0x5d, 0x9d, 0xb5, 0x55, 0x8d, 0x11, 0x84, 0xf5, 0xcd, 0xcd,
+    0x1d, 0x3f, 0xf9, 0xfc, 0x80, 0x76, 0x87, 0x8e, 0x36, 0x3a, 0x7d, 0xdb,
+    0x55, 0x58, 0xd1, 0x1e, 0xcf, 0x6a, 0xb7, 0xbc, 0x74, 0xcd, 0xbb, 0x0f,
+    0x5f, 0xc6, 0x72, 0xbb, 0xa8, 0xcc, 0xa8, 0x4f, 0x4f, 0xbb, 0x6a, 0xab,
+    0x1a, 0x2c, 0x39, 0xfc, 0xd1, 0x7c, 0xd6, 0x09, 0xd2, 0xbb, 0x0f, 0x8b,
+    0x73, 0x39, 0xfd, 0x76, 0x76, 0xd5, 0x56, 0x34, 0x5c, 0xf0, 0xea, 0xbe,
+    0xb6, 0x84, 0x93, 0x50, 0xec, 0x7e, 0x90, 0xee, 0x5c, 0x24, 0x3c, 0x53,
+    0x3f, 0xae, 0xce, 0xda, 0xaa, 0xc6, 0x88, 0x7a, 0x7d, 0xdb, 0x55, 0x58,
+    0xd1, 0x13, 0x4f, 0xff, 0x9f, 0xa0, 0xe3, 0xde, 0x61, 0xdd, 0x7a, 0xc0,
+    0x9d, 0x3f, 0xdc, 0xe3, 0xde, 0x6e, 0x75, 0xce, 0x97, 0xb8, 0x88, 0xfa,
+    0x56, 0x9f, 0xe4, 0xf2, 0x7b, 0x00, 0xfd, 0x3a, 0x30, 0xf7, 0xa8, 0xa2,
+    0x7f, 0xfe, 0xf7, 0x1f, 0xa0, 0xd6, 0x07, 0xdf, 0xd5, 0xb3, 0xa7, 0x4d,
+    0xe5, 0x9d, 0x3f, 0xfb, 0x39, 0xf7, 0x6d, 0x3a, 0x6f, 0xe7, 0x59, 0xd1,
+    0x88, 0xbd, 0xdd, 0x6f, 0x82, 0xd3, 0xde, 0xfe, 0xbe, 0x9a, 0x21, 0x79,
+    0xf8, 0x3c, 0xcd, 0xbf, 0x13, 0xa5, 0x76, 0x2a, 0x8c, 0xe4, 0x64, 0x1a,
+    0x86, 0xef, 0xe6, 0x17, 0x8c, 0x67, 0xf3, 0x83, 0x57, 0x7b, 0x5f, 0x9d,
+    0x37, 0xfc, 0x3a, 0x78, 0x38, 0x2c, 0x1d, 0x32, 0x78, 0xe9, 0x79, 0x0d,
+    0xb7, 0x08, 0x67, 0xfa, 0xb7, 0xf6, 0xed, 0xfc, 0x54, 0x3a, 0x7f, 0xff,
+    0xee, 0x7e, 0x14, 0xce, 0xb0, 0x39, 0x7b, 0x98, 0x17, 0xd6, 0x9d, 0x43,
+    0xa7, 0xff, 0x23, 0x0d, 0xcd, 0xdb, 0xf1, 0x75, 0x42, 0x74, 0xd4, 0xa8,
+    0xe9, 0x5f, 0x38, 0x99, 0xc2, 0x84, 0xd6, 0x3c, 0xe3, 0xa5, 0x25, 0xcd,
+    0x7e, 0xa1, 0xd3, 0xee, 0x57, 0xa9, 0xa7, 0x4f, 0xe6, 0xe9, 0xf4, 0xad,
+    0x8a, 0xd2, 0xb4, 0x74, 0xf2, 0x69, 0x00, 0x74, 0xe6, 0x59, 0x64, 0xa9,
+    0xf5, 0x0f, 0xb9, 0x85, 0x5c, 0x5f, 0xcf, 0xab, 0xcc, 0x67, 0x8e, 0x80,
+    0xa2, 0x6c, 0x07, 0xe2, 0x6b, 0x3d, 0xca, 0xaa, 0x3a, 0x7f, 0xe0, 0x23,
+    0x1f, 0x38, 0xe9, 0xdf, 0xd5, 0xce, 0x9f, 0xf2, 0x28, 0xe2, 0xfa, 0x74,
+    0x59, 0xd3, 0xf6, 0x5e, 0xfd, 0xb9, 0xa3, 0xa7, 0xb0, 0x39, 0xb1, 0xd3,
+    0xca, 0xff, 0x1d, 0x59, 0x3a, 0x6e, 0xb9, 0xd1, 0x8a, 0x9a, 0x37, 0x26,
+    0x48, 0x6f, 0xab, 0x97, 0xb0, 0x3f, 0xc4, 0xa1, 0x3b, 0xf1, 0x7d, 0xe2,
+    0x15, 0x45, 0x73, 0xf6, 0x32, 0xf8, 0x14, 0x3a, 0x73, 0xfe, 0x03, 0xa7,
+    0xff, 0xff, 0x08, 0xee, 0xea, 0x0e, 0x07, 0x88, 0xc7, 0xcd, 0x66, 0xed,
+    0xee, 0x32, 0x74, 0xf9, 0x3d, 0xfb, 0xec, 0x74, 0xff, 0xfe, 0xcd, 0xdb,
+    0xa5, 0xe0, 0xfc, 0x54, 0x9c, 0xd9, 0x33, 0xa7, 0x4f, 0xff, 0xf9, 0x9f,
+    0x83, 0x96, 0xe2, 0x0e, 0x7f, 0xbf, 0xbe, 0x53, 0x38, 0xa1, 0xd3, 0xfb,
+    0x76, 0xe9, 0x4f, 0xdf, 0x73, 0xa7, 0xf5, 0x33, 0xfb, 0x0f, 0xea, 0x3a,
+    0x1d, 0x1b, 0xa8, 0xe4, 0x26, 0xf3, 0xc0, 0xf2, 0x6c, 0x74, 0xfe, 0xf7,
+    0x10, 0x41, 0xf5, 0x67, 0x4f, 0xed, 0x9d, 0x62, 0xfb, 0x80, 0xe9, 0x3b,
+    0x4f, 0x9e, 0x8d, 0x21, 0xd5, 0x60, 0x63, 0xda, 0x14, 0x76, 0x34, 0x1a,
+    0x2d, 0x18, 0x44, 0xcf, 0xff, 0x75, 0x3f, 0xbe, 0x9f, 0xe6, 0xbf, 0x02,
+    0xf3, 0xc7, 0x4d, 0xfb, 0x4e, 0x9f, 0x38, 0x35, 0xb7, 0x8e, 0x9d, 0x5e,
+    0xd1, 0xd3, 0x7f, 0xb1, 0xd3, 0x87, 0xcc, 0x34, 0xd9, 0xf4, 0x6e, 0x7e,
+    0xfe, 0xdf, 0x03, 0xbb, 0x27, 0x43, 0x9f, 0x32, 0x19, 0xcf, 0xff, 0xbf,
+    0x7f, 0x7c, 0x1f, 0xd5, 0x7c, 0xcf, 0x5f, 0xe7, 0x8e, 0x9f, 0xfb, 0x8e,
+    0xa7, 0xcf, 0x0d, 0x79, 0xfc, 0x74, 0xfe, 0xf9, 0xbb, 0x53, 0x9f, 0xac,
+    0xe8, 0x01, 0xfe, 0x0a, 0x2c, 0xff, 0xba, 0xc7, 0xcd, 0x3a, 0x6d, 0x5e,
+    0x3a, 0x1c, 0xf8, 0xbf, 0x21, 0x9f, 0xff, 0xfe, 0xfc, 0x75, 0xd1, 0x76,
+    0x3e, 0x7d, 0xf2, 0x37, 0x37, 0xf6, 0x5e, 0x1c, 0xd1, 0xd0, 0x74, 0xcc,
+    0x34, 0xe8, 0x73, 0x43, 0xd0, 0xa9, 0xfa, 0xba, 0x9a, 0x7d, 0xce, 0x9f,
+    0xf5, 0x33, 0xd7, 0x1f, 0x73, 0x15, 0x1d, 0x0d, 0x3e, 0xbe, 0x96, 0x4f,
+    0xf7, 0x13, 0xac, 0x72, 0xb3, 0xa7, 0x4f, 0xff, 0xff, 0xc0, 0xd0, 0xe5,
+    0x6f, 0xf0, 0x3c, 0xff, 0xe0, 0xe6, 0xed, 0xcf, 0xf6, 0x1c, 0xad, 0xce,
+    0x8b, 0x23, 0x1d, 0x0e, 0x27, 0x55, 0x58, 0xd1, 0x4c, 0x46, 0x1e, 0x4d,
+    0x88, 0xa7, 0xfd, 0x83, 0xbb, 0x75, 0xe7, 0xeb, 0x07, 0x4e, 0xc4, 0x01,
+    0xd2, 0xc3, 0xa7, 0x6e, 0x38, 0x03, 0x53, 0x78, 0x6a, 0x11, 0x13, 0x94,
+    0xd1, 0x3f, 0xd5, 0xf3, 0x76, 0x8b, 0xe6, 0x8e, 0x9f, 0xff, 0x01, 0x35,
+    0xf3, 0x95, 0xaf, 0x3b, 0x1a, 0xe6, 0x1d, 0x39, 0xaf, 0xb9, 0xd3, 0xf9,
+    0x61, 0xe3, 0xed, 0x8c, 0x9d, 0x1b, 0x9e, 0x85, 0x0e, 0x4f, 0xff, 0xe1,
+    0xcb, 0x7b, 0xcf, 0xed, 0x30, 0x38, 0xcf, 0xc7, 0x56, 0x4e, 0x9f, 0xf5,
+    0x9d, 0x7c, 0xcd, 0x62, 0x09, 0xd0, 0xe8, 0xa2, 0xe3, 0x3c, 0xfb, 0xaf,
+    0x79, 0xfa, 0x74, 0xfd, 0x43, 0xf0, 0x2e, 0x27, 0x46, 0x1f, 0xb2, 0x11,
+    0x7e, 0x51, 0x0e, 0xc8, 0x36, 0xd9, 0x61, 0xa2, 0xe1, 0x86, 0x0a, 0x84,
+    0x16, 0x8c, 0xf7, 0x72, 0x24, 0x85, 0x23, 0x10, 0x8b, 0xec, 0x66, 0x4b,
+    0x85, 0xef, 0x08, 0x40, 0x72, 0x30, 0xa7, 0xf4, 0x67, 0x53, 0xfd, 0xda,
+    0x67, 0xe5, 0x06, 0xb6, 0x3a, 0x7f, 0xff, 0x9c, 0x39, 0xb5, 0x0f, 0xb4,
+    0xf6, 0xf8, 0xb5, 0xa0, 0xd8, 0xe9, 0xfe, 0x76, 0x38, 0x8e, 0xba, 0x09,
+    0xd0, 0xa2, 0x36, 0x04, 0xef, 0xf6, 0x69, 0xec, 0x15, 0x15, 0xce, 0x9f,
+    0xff, 0xff, 0x71, 0x3d, 0xcc, 0xeb, 0xde, 0xf8, 0xbf, 0xd5, 0x7c, 0xcd,
+    0xdb, 0x9f, 0x88, 0x34, 0x74, 0xbc, 0x88, 0xb1, 0xd1, 0x24, 0xff, 0x9e,
+    0xdf, 0x06, 0xb4, 0xb7, 0x13, 0xa7, 0xff, 0xd9, 0x9c, 0x4b, 0x73, 0x3e,
+    0x6b, 0xfe, 0x3a, 0xb9, 0xd3, 0xff, 0xde, 0xe6, 0x03, 0xe2, 0xdf, 0x3c,
+    0x1c, 0x13, 0xa7, 0xfb, 0x7f, 0x8b, 0x7c, 0x1f, 0x5f, 0x9d, 0x2d, 0x62,
+    0x23, 0x29, 0x3e, 0x48, 0xb4, 0xd2, 0x44, 0xf7, 0xd0, 0xe5, 0x9f, 0x35,
+    0xf7, 0x6e, 0x8e, 0x9f, 0xff, 0xff, 0xf6, 0x0a, 0x9f, 0x13, 0x9f, 0xdc,
+    0xc2, 0x79, 0xd6, 0x34, 0xa7, 0x12, 0xec, 0xe6, 0xe0, 0x70, 0x95, 0x3f,
+    0xff, 0xf5, 0x91, 0x90, 0xff, 0xdf, 0x9f, 0xbe, 0xda, 0xb7, 0x3f, 0xe6,
+    0xf4, 0xc9, 0xd3, 0x7f, 0xb6, 0xe9, 0xa1, 0xa1, 0x46, 0xa1, 0x3f, 0x0e,
+    0xac, 0xcb, 0x91, 0xb8, 0x8c, 0x6f, 0xb3, 0xfa, 0x9b, 0x8b, 0xa1, 0x01,
+    0xd3, 0xd9, 0xc7, 0x60, 0xe9, 0xcb, 0xb7, 0xce, 0x1e, 0x8d, 0x18, 0x4f,
+    0xff, 0xff, 0x67, 0x6c, 0x39, 0x7b, 0xe6, 0x93, 0x04, 0x1f, 0x07, 0x2f,
+    0x0e, 0x6a, 0xf1, 0xd3, 0xff, 0xe4, 0x1f, 0x73, 0x15, 0x79, 0x8c, 0x57,
+    0xa1, 0x01, 0xd3, 0xe7, 0x67, 0xe6, 0x98, 0x3a, 0x7f, 0xe7, 0x1d, 0x87,
+    0x2f, 0x6b, 0xf7, 0xdc, 0xe8, 0x44, 0xd2, 0xf5, 0x08, 0x2f, 0x2c, 0x7e,
+    0x57, 0x3d, 0x9e, 0xcb, 0xe8, 0xe9, 0xd7, 0xf9, 0xc3, 0xa6, 0xc0, 0x9d,
+    0x1b, 0x2a, 0x1b, 0x6c, 0x70, 0x1a, 0x43, 0xf1, 0x2d, 0xe1, 0xe9, 0xf2,
+    0x7b, 0x58, 0x03, 0xa7, 0xe0, 0xb8, 0xf2, 0x9a, 0x74, 0xe7, 0x0b, 0x9d,
+    0x3f, 0x37, 0x3d, 0xaa, 0x63, 0xe1, 0xe2, 0xac, 0xae, 0x7f, 0xfd, 0xdf,
+    0xfb, 0xd7, 0x1c, 0x51, 0x39, 0xcc, 0xfa, 0x74, 0xf7, 0xf5, 0xbf, 0x8e,
+    0x86, 0xa6, 0x58, 0xc3, 0x5f, 0x51, 0xf8, 0xaf, 0x07, 0x4f, 0xda, 0xb5,
+    0xa8, 0x54, 0x3a, 0x15, 0x89, 0xb7, 0xf0, 0x54, 0xdb, 0x6e, 0x74, 0xfb,
+    0x94, 0xae, 0xe0, 0x3a, 0x28, 0xf0, 0x55, 0x0c, 0x4f, 0xee, 0xb0, 0x39,
+    0xca, 0xf1, 0xd0, 0xe8, 0xbd, 0xc6, 0x84, 0x23, 0x9f, 0x27, 0x43, 0x82,
+    0x74, 0xf8, 0x19, 0xef, 0xbb, 0x1d, 0x3f, 0x99, 0xf6, 0x73, 0xe6, 0xfa,
+    0x3a, 0x1c, 0xf8, 0x68, 0xaa, 0x1a, 0x8d, 0x3e, 0x16, 0x8c, 0x21, 0xa7,
+    0xfb, 0xdc, 0xc6, 0xd0, 0xe6, 0xe7, 0x4f, 0xff, 0xf0, 0xd0, 0x35, 0xb6,
+    0x20, 0xf8, 0x72, 0xf7, 0xcd, 0x32, 0x27, 0x40, 0xa2, 0x7f, 0xc6, 0xf3,
+    0xfe, 0x4c, 0x63, 0xe6, 0x9f, 0x94, 0xae, 0x74, 0xff, 0x6f, 0x8f, 0xbb,
+    0x02, 0xeb, 0x3a, 0x7f, 0x56, 0xfa, 0xe6, 0x57, 0x4e, 0x80, 0xa2, 0xb7,
+    0x88, 0x5e, 0x39, 0x9f, 0xec, 0xee, 0xce, 0x9d, 0xc1, 0x3a, 0x4b, 0x3b,
+    0xe1, 0xb6, 0x9c, 0x38, 0x13, 0xa1, 0xcd, 0xe6, 0xe4, 0x53, 0xf6, 0xfa,
+    0xcc, 0x15, 0x0e, 0x9e, 0x5f, 0xd7, 0x01, 0xd1, 0x87, 0xa0, 0x85, 0xb3,
+    0xfa, 0xbd, 0xca, 0x63, 0xea, 0xce, 0x9d, 0xfe, 0xe0, 0x3a, 0x1d, 0x52,
+    0xae, 0x43, 0x3d, 0x21, 0x45, 0xd7, 0x1a, 0x20, 0x13, 0x59, 0xfd, 0xe4,
+    0xdb, 0x39, 0xff, 0x8e, 0x93, 0x07, 0x4f, 0xd9, 0xfe, 0x72, 0xdb, 0x1d,
+    0x36, 0x6e, 0xe6, 0xff, 0x42, 0x33, 0xf7, 0x29, 0xab, 0xea, 0x1d, 0x3f,
+    0xf9, 0xd4, 0x52, 0xbd, 0xaf, 0x0b, 0xee, 0xd3, 0xa6, 0x4d, 0x1d, 0x3b,
+    0xb9, 0xb9, 0xd0, 0x13, 0x62, 0x01, 0x59, 0xf2, 0x6b, 0x4e, 0xb3, 0xa1,
+    0x0f, 0x1e, 0xf1, 0x0c, 0x28, 0x9d, 0x8a, 0x39, 0x80, 0xb0, 0x4b, 0x3f,
+    0x86, 0x1c, 0xf8, 0x28, 0x34, 0x13, 0xa7, 0xff, 0xcd, 0xe6, 0x31, 0xc7,
+    0x15, 0x07, 0x3d, 0xcf, 0xce, 0x84, 0x3f, 0xbe, 0x92, 0xcf, 0xff, 0xe4,
+    0xcd, 0xdb, 0xaf, 0x71, 0xd6, 0xe8, 0x1f, 0x8e, 0xac, 0x9d, 0x3f, 0xa8,
+    0x7e, 0x5b, 0x40, 0x09, 0xd3, 0xfe, 0xff, 0x5f, 0x17, 0xf7, 0x95, 0xc7,
+    0x3a, 0x7d, 0x9e, 0xff, 0x37, 0x3a, 0x72, 0x99, 0xb9, 0xd3, 0x3b, 0x1f,
+    0x0f, 0x17, 0xc5, 0x10, 0x28, 0xb8, 0xfe, 0x11, 0x13, 0xff, 0xff, 0xef,
+    0xc7, 0xe3, 0x35, 0xbb, 0x7b, 0x40, 0xf9, 0xaf, 0xdf, 0x7e, 0x62, 0x0e,
+    0x28, 0x74, 0xff, 0xfb, 0xfe, 0xf7, 0x3d, 0xae, 0x26, 0x7c, 0xe0, 0x1c,
+    0xe8, 0xc4, 0x70, 0xf2, 0x11, 0x53, 0xec, 0x1b, 0x7d, 0x59, 0xd3, 0xff,
+    0x73, 0x1c, 0x58, 0x1c, 0xf6, 0xa8, 0xe9, 0x37, 0xc7, 0xd2, 0xa8, 0xa2,
+    0x7f, 0xfc, 0x1c, 0x5f, 0xc5, 0x5e, 0x7d, 0x30, 0xda, 0xee, 0xc7, 0x4f,
+    0xff, 0xde, 0x4d, 0xb0, 0x3f, 0x17, 0x4d, 0xea, 0x6d, 0x4b, 0x3a, 0x7f,
+    0x6d, 0x4b, 0x17, 0xeb, 0x07, 0x4f, 0xf6, 0xf8, 0xa0, 0x17, 0x9f, 0x3b,
+    0x88, 0x90, 0x45, 0xd9, 0xfe, 0xc1, 0xdb, 0xe0, 0x2a, 0x98, 0x3a, 0x7f,
+    0xbb, 0xb3, 0xed, 0xb7, 0xfd, 0xd8, 0xe9, 0xfe, 0xfc, 0x7e, 0x6b, 0xfb,
+    0xff, 0xfa, 0x74, 0x39, 0xff, 0xe8, 0xfa, 0x7f, 0xf6, 0xdf, 0x35, 0xcf,
+    0xfe, 0x7b, 0x5a, 0x7e, 0x9d, 0x3f, 0xff, 0xec, 0xdf, 0x49, 0x8c, 0xfc,
+    0xe6, 0x7b, 0x59, 0xb7, 0xcc, 0x40, 0x9d, 0x18, 0x8c, 0x14, 0x51, 0x8d,
+    0x97, 0x83, 0xc2, 0xcc, 0xa4, 0x3b, 0x2d, 0x18, 0x4e, 0xf0, 0x90, 0x42,
+    0xae, 0xc3, 0xad, 0x6a, 0x7a, 0x85, 0xcf, 0xa1, 0xc5, 0x3f, 0xbc, 0x39,
+    0xee, 0x66, 0xc7, 0x4f, 0xfa, 0xbb, 0xcc, 0xf3, 0x8a, 0x00, 0xe9, 0xe6,
+    0xf9, 0x36, 0x3a, 0x7f, 0xb1, 0x9d, 0xdb, 0xaf, 0x9e, 0x43, 0xa7, 0xff,
+    0x98, 0xe2, 0x08, 0x7e, 0x7d, 0xb0, 0xe7, 0x30, 0xe9, 0xfe, 0xe2, 0x2d,
+    0xf0, 0x7d, 0xa3, 0xa7, 0xff, 0xf7, 0xfe, 0xef, 0xec, 0x7c, 0xf3, 0x1c,
+    0xfc, 0x1e, 0x4c, 0x54, 0x74, 0xf3, 0xd9, 0xd7, 0xf1, 0x1e, 0x76, 0x52,
+    0x13, 0x68, 0x75, 0x40, 0xb6, 0x32, 0xa3, 0xb1, 0x22, 0x55, 0x19, 0x7c,
+    0xf2, 0x79, 0x1c, 0xe9, 0xff, 0xff, 0xc2, 0x8a, 0x72, 0x98, 0xf8, 0x3f,
+    0xaa, 0xf9, 0x9b, 0xb7, 0x3f, 0x10, 0x68, 0xe9, 0xf7, 0x11, 0xc7, 0x63,
+    0xa6, 0xf3, 0xad, 0x14, 0xd7, 0xa1, 0x01, 0x0d, 0x47, 0xd2, 0x43, 0x16,
+    0x1d, 0x94, 0xad, 0x93, 0xc6, 0x09, 0x2a, 0xd2, 0xa3, 0x4b, 0x9f, 0x38,
+    0xf9, 0x2f, 0x1d, 0x3d, 0xed, 0x50, 0x0e, 0x9f, 0xfb, 0x89, 0xf1, 0x3b,
+    0xfe, 0xd5, 0xdb, 0x1d, 0x3c, 0x9c, 0xad, 0x8e, 0x9e, 0xbc, 0xfe, 0x73,
+    0xa7, 0xda, 0xcf, 0x26, 0x8e, 0x9f, 0x7f, 0x7d, 0x0d, 0x78, 0xe9, 0xfb,
+    0x95, 0xb7, 0xc6, 0xf8, 0xe9, 0xf7, 0xd1, 0x6b, 0x56, 0x74, 0xfa, 0xba,
+    0x3b, 0xa1, 0xd0, 0xe8, 0xab, 0x42, 0xc0, 0x18, 0x78, 0xa6, 0x02, 0x9e,
+    0xf6, 0x13, 0xa8, 0x43, 0x64, 0x74, 0x21, 0x60, 0x8b, 0xd0, 0xd1, 0x9f,
+    0xdc, 0x74, 0x1a, 0xea, 0x87, 0x4f, 0xce, 0x83, 0x5d, 0x50, 0xe9, 0xfc,
+    0x0a, 0x07, 0x7a, 0x9d, 0xf8, 0x7b, 0x9c, 0x31, 0x9f, 0x9f, 0xbb, 0x3f,
+    0x76, 0x3a, 0x77, 0xf5, 0xa3, 0xa1, 0xa7, 0x95, 0xf4, 0xba, 0x7f, 0xfe,
+    0x4e, 0xfc, 0xc4, 0xc1, 0x53, 0x89, 0x8b, 0xcb, 0x1d, 0x3f, 0xff, 0xc9,
+    0xb7, 0x5d, 0x7a, 0xfd, 0xfe, 0x3f, 0x5c, 0x3c, 0x75, 0x9d, 0x18, 0x8c,
+    0x1e, 0xac, 0xcf, 0xfb, 0xb9, 0xbf, 0x37, 0x75, 0xec, 0xe7, 0x4f, 0xff,
+    0xfe, 0xef, 0x53, 0x6f, 0x9c, 0xcf, 0x0b, 0xb1, 0xcc, 0xd9, 0xf7, 0xf7,
+    0xf6, 0x3a, 0x7f, 0xff, 0xe7, 0x53, 0x8f, 0xf0, 0x73, 0xf5, 0x3e, 0x6e,
+    0xdd, 0x20, 0xfd, 0x7d, 0x8e, 0x9f, 0x6f, 0xa4, 0xc1, 0x3a, 0x31, 0x14,
+    0x1f, 0xbd, 0x42, 0x26, 0x81, 0xc8, 0xc7, 0x67, 0xfe, 0x6e, 0x91, 0x4e,
+    0x3a, 0x6c, 0xea, 0x1d, 0x3f, 0xc3, 0xfb, 0x03, 0x9c, 0xaf, 0x1d, 0x3f,
+    0xc1, 0xe3, 0xb2, 0x1e, 0x52, 0xce, 0x9f, 0xff, 0xea, 0xef, 0x33, 0xc9,
+    0x83, 0xb6, 0x9f, 0x04, 0x3c, 0x73, 0xa7, 0xbd, 0xf3, 0x6e, 0x9d, 0x1b,
+    0xa2, 0x1e, 0x98, 0xa7, 0xff, 0xfd, 0xbe, 0x6d, 0xfa, 0xaf, 0x9b, 0xb7,
+    0xce, 0xcf, 0xcc, 0xe8, 0x00, 0xe7, 0x4f, 0xfe, 0x66, 0x87, 0x65, 0xfe,
+    0x81, 0x41, 0x43, 0xa7, 0xe6, 0x37, 0x6f, 0xef, 0xe3, 0xa7, 0xfb, 0x94,
+    0xb1, 0xce, 0x57, 0x8e, 0x9e, 0xce, 0x81, 0x93, 0xa1, 0xd1, 0x11, 0xa3,
+    0x0f, 0x1b, 0x4f, 0xd9, 0xee, 0xf7, 0x1a, 0x74, 0xfc, 0x39, 0xc1, 0xcb,
+    0x1d, 0x3c, 0x39, 0xaf, 0x8c, 0x1e, 0xb7, 0x8b, 0x27, 0xfb, 0x17, 0xc7,
+    0x4e, 0xfe, 0xae, 0x74, 0x05, 0x75, 0xb9, 0x42, 0x2b, 0x47, 0x01, 0xb9,
+    0x4a, 0x22, 0xf4, 0xe3, 0x90, 0xc0, 0xa2, 0x3d, 0x3b, 0xfa, 0x1a, 0x37,
+    0xa1, 0x0b, 0xf4, 0xee, 0x7f, 0xc3, 0x9f, 0x3b, 0x9c, 0x1c, 0x60, 0xe9,
+    0xff, 0xfd, 0xca, 0x06, 0xbe, 0x0e, 0x5e, 0x1c, 0xd6, 0x2d, 0xec, 0x74,
+    0x0a, 0x27, 0xf4, 0x7d, 0x0e, 0xbf, 0xab, 0x93, 0xca, 0x75, 0x1b, 0x04,
+    0xfd, 0xcc, 0x1f, 0x03, 0xf3, 0xa7, 0xc2, 0xeb, 0xa0, 0x9d, 0x3f, 0xb1,
+    0x8e, 0x67, 0x9c, 0x27, 0x4f, 0xe7, 0x1f, 0x52, 0xd3, 0xc7, 0x4e, 0x1b,
+    0x39, 0xd3, 0xff, 0xff, 0xdc, 0xcf, 0x6a, 0x98, 0xf8, 0x39, 0xbb, 0x73,
+    0xfd, 0x87, 0x03, 0xc4, 0x60, 0xe9, 0xbf, 0x50, 0xe8, 0x44, 0x59, 0xf4,
+    0x6b, 0xd0, 0x81, 0x9f, 0xb3, 0x61, 0xcd, 0xf4, 0x74, 0xff, 0xff, 0xf9,
+    0xba, 0xd7, 0xef, 0xe4, 0x0e, 0x0b, 0x1f, 0x07, 0x3a, 0xe3, 0xee, 0x62,
+    0xa3, 0xa7, 0xfe, 0xdd, 0xba, 0xc5, 0xee, 0xfc, 0xe3, 0x9d, 0x1b, 0xa3,
+    0x2b, 0xb0, 0x85, 0x96, 0x8e, 0x8f, 0xcd, 0xcf, 0xd2, 0x99, 0xfb, 0x37,
+    0x6b, 0x81, 0xce, 0x9f, 0x0e, 0x72, 0xbc, 0x74, 0x9f, 0x73, 0xd1, 0x59,
+    0x64, 0xf7, 0xcb, 0x6c, 0xc9, 0xd3, 0xff, 0xfe, 0xf0, 0xb8, 0x37, 0x6e,
+    0xbf, 0x7f, 0x0e, 0x05, 0x33, 0xac, 0x1d, 0x01, 0x57, 0xf4, 0x85, 0xac,
+    0x12, 0xf0, 0xca, 0xa1, 0xc6, 0x26, 0x9a, 0x8c, 0xc3, 0xf7, 0x5b, 0xc5,
+    0x1f, 0x49, 0xa7, 0xcd, 0x4e, 0xe6, 0xe7, 0x4e, 0xd7, 0x30, 0xe9, 0xf6,
+    0x6b, 0x6c, 0x64, 0xe8, 0xdc, 0xfa, 0x98, 0x27, 0xe0, 0xdc, 0xff, 0xf9,
+    0x36, 0xcb, 0x07, 0x89, 0x8a, 0x7c, 0x53, 0xf7, 0x3a, 0x7f, 0xf3, 0xee,
+    0xdd, 0x7a, 0xb6, 0x54, 0x39, 0xb9, 0xd3, 0xff, 0x35, 0xf9, 0xb2, 0x60,
+    0xee, 0xdd, 0x1d, 0x3c, 0xab, 0xd9, 0xc3, 0xa6, 0x45, 0x9d, 0x3f, 0xff,
+    0xed, 0xdb, 0x5b, 0xfc, 0x1f, 0xd5, 0x7c, 0xcd, 0xdb, 0x9f, 0x88, 0x34,
+    0x74, 0x2d, 0x11, 0x6a, 0x85, 0x63, 0x64, 0x69, 0xe4, 0x2b, 0xa7, 0xff,
+    0xff, 0xcf, 0xbe, 0xbf, 0x7d, 0xfe, 0x73, 0x03, 0xf0, 0x73, 0xf5, 0x3e,
+    0x68, 0x00, 0x4f, 0x1d, 0x3e, 0x71, 0xde, 0xb6, 0x3a, 0x7f, 0xff, 0xff,
+    0xe5, 0xe5, 0x9f, 0x8e, 0xbf, 0x66, 0xb4, 0xfd, 0xeb, 0x8e, 0x6d, 0x9f,
+    0xeb, 0xf6, 0x05, 0xd6, 0x74, 0xfa, 0x81, 0xf6, 0xb6, 0x3a, 0x31, 0x19,
+    0x09, 0x09, 0xf9, 0xc8, 0x07, 0x3a, 0x7e, 0x08, 0xe7, 0x2b, 0xc7, 0x4f,
+    0xbd, 0xbb, 0x53, 0xa7, 0x46, 0x1e, 0x9e, 0x8a, 0xe3, 0x64, 0x47, 0x01,
+    0xb6, 0x7f, 0x6d, 0xfb, 0xf9, 0x69, 0xe3, 0xa7, 0xfc, 0xea, 0x2a, 0xff,
+    0x05, 0x8f, 0xab, 0x3a, 0x30, 0xfe, 0x37, 0x34, 0x9f, 0xf6, 0x60, 0x35,
+    0xf3, 0xba, 0x0e, 0x8e, 0x9f, 0xdd, 0xcb, 0x71, 0x3a, 0xc1, 0xd3, 0x67,
+    0x82, 0x7e, 0x78, 0x81, 0x3d, 0xb2, 0x0f, 0x8e, 0x87, 0x5d, 0xc4, 0xc3,
+    0x15, 0x16, 0x77, 0x4d, 0x48, 0xc5, 0xfa, 0x50, 0xb8, 0x46, 0xf2, 0x1d,
+    0xf5, 0x0b, 0x41, 0x84, 0xe6, 0xa1, 0x2b, 0xf9, 0x64, 0xea, 0xb6, 0x1d,
+    0x3f, 0xe6, 0x3e, 0x78, 0x71, 0x9c, 0x4d, 0x1d, 0x17, 0xd9, 0xed, 0x38,
+    0xd4, 0x1d, 0x38, 0x3f, 0x18, 0x3a, 0x7f, 0xfb, 0x76, 0x8b, 0xfc, 0x58,
+    0xba, 0x9e, 0x4d, 0x8e, 0x87, 0x3f, 0xbc, 0x0a, 0x41, 0xf9, 0xf7, 0x7e,
+    0x0d, 0xe6, 0x4e, 0x9e, 0xe5, 0x01, 0xce, 0x87, 0x3c, 0xca, 0x2c, 0x9f,
+    0xb6, 0x61, 0xb7, 0xdf, 0x76, 0x3a, 0x7c, 0xb4, 0x0e, 0x04, 0xe9, 0x30,
+    0x74, 0xce, 0xb3, 0xa5, 0xe3, 0xa3, 0xa6, 0x96, 0x85, 0x60, 0x27, 0xad,
+    0xc3, 0x69, 0xef, 0x6a, 0xb7, 0x3a, 0x66, 0x28, 0xe9, 0xfd, 0xc4, 0xee,
+    0xed, 0x17, 0x3a, 0x15, 0xa4, 0xcf, 0x9c, 0xdb, 0x1f, 0x10, 0x89, 0x64,
+    0x5f, 0x8b, 0x4f, 0xe6, 0x71, 0xa3, 0xfd, 0x68, 0xe9, 0xf6, 0xec, 0xd0,
+    0x80, 0xe9, 0x85, 0x43, 0xa5, 0xa4, 0x37, 0xdf, 0x94, 0x4f, 0xff, 0xce,
+    0xb1, 0xcb, 0x6f, 0xe1, 0xae, 0x2d, 0xf3, 0xc7, 0x4f, 0xff, 0x9f, 0xaf,
+    0x6c, 0x5b, 0xd9, 0xa9, 0xaf, 0xd6, 0x74, 0x3a, 0x68, 0x8c, 0x38, 0xf0,
+    0x9e, 0xfd, 0x62, 0x7e, 0xee, 0x3a, 0x8e, 0x27, 0x4e, 0x1a, 0x59, 0xd3,
+    0x01, 0xce, 0x86, 0x9e, 0xd2, 0x15, 0x88, 0xd4, 0x5f, 0x0f, 0x92, 0xbd,
+    0x7d, 0xc7, 0x0a, 0xad, 0xd5, 0x5e, 0x54, 0x16, 0xd0, 0x98, 0x69, 0x58,
+    0x65, 0x6e, 0x65, 0x22, 0x55, 0x48, 0xf5, 0x2d, 0x38, 0x29, 0xbc, 0xaa,
+    0x84, 0x8e, 0x05, 0x89, 0x40, 0xdd, 0x96, 0x50, 0xb9, 0x41, 0xfc, 0xa5,
+    0x90, 0xd4, 0xa3, 0x00, 0x43, 0x18, 0x69, 0x0d, 0x7a, 0x9c, 0x38, 0xf4,
+    0xf6, 0x4f, 0xf1, 0x8f, 0xde, 0x85, 0x0b, 0x2f, 0x17, 0xf1, 0xaf, 0x7d,
+    0x8e, 0x7d, 0x54, 0x26, 0xe7, 0xff, 0xef, 0xed, 0x76, 0xfe, 0xeb, 0xe6,
+    0xf7, 0xd8, 0x6a, 0x94, 0x3a, 0x2e, 0x55, 0x12, 0x92, 0x89, 0x67, 0xf5,
+    0xd9, 0xdb, 0x55, 0x58, 0xd1, 0x4e, 0xcf, 0xbb, 0x6a, 0xab, 0x1a, 0x2a,
+    0x39, 0xff, 0x53, 0x6e, 0xce, 0xda, 0xaa, 0xc6, 0x89, 0xa2, 0x30, 0xff,
+    0x56, 0x67, 0x3f, 0xbe, 0xd5, 0xeb, 0xbc, 0x9b, 0x1d, 0x17, 0x1e, 0xcb,
+    0x90, 0xcf, 0xbb, 0x6a, 0xab, 0x1a, 0x2a, 0xf9, 0xfb, 0x2f, 0x38, 0xf3,
+    0xf3, 0xa5, 0x76, 0x1f, 0x0f, 0x4c, 0xe7, 0xdd, 0xb5, 0x55, 0x8d, 0x15,
+    0xb4, 0xff, 0x36, 0xec, 0xed, 0xaa, 0xac, 0x68, 0x90, 0x65, 0x76, 0x1f,
+    0xc5, 0x19, 0xcf, 0xfd, 0x75, 0x36, 0xec, 0xed, 0xaa, 0xac, 0x68, 0x90,
+    0xe7, 0xfe, 0x7d, 0x5d, 0x9e, 0x40, 0xe0, 0xb0, 0x74, 0xff, 0x9b, 0xc7,
+    0xf6, 0x95, 0x9d, 0x5f, 0x02, 0x74, 0xff, 0xe5, 0x60, 0xac, 0x15, 0x9e,
+    0x3a, 0xc6, 0xb8, 0x9d, 0x3a, 0x5b, 0x9d, 0x32, 0x09, 0xd0, 0x13, 0x4a,
+    0xc0, 0x8c, 0xfb, 0x30, 0x41, 0xa3, 0xa7, 0xd4, 0x1f, 0xae, 0x27, 0x4f,
+    0xfb, 0xbe, 0xfa, 0x35, 0x6c, 0x1b, 0x1d, 0x3d, 0x6a, 0xab, 0x1a, 0x2c,
+    0x49, 0xdf, 0x8b, 0x4e, 0x8d, 0x91, 0x5d, 0x84, 0xfd, 0x3e, 0xf1, 0x6c,
+    0xfb, 0x3a, 0xe2, 0xa1, 0xd3, 0xef, 0xb7, 0xf9, 0xd7, 0x3a, 0x76, 0x9c,
+    0x4e, 0x97, 0x1c, 0xf1, 0x50, 0xae, 0x7f, 0xe7, 0xcd, 0x60, 0x85, 0x00,
+    0xe2, 0x74, 0xe1, 0x7d, 0x8e, 0x93, 0x44, 0xf6, 0xbf, 0x3f, 0x9d, 0x7e,
+    0x80, 0x3a, 0x7c, 0x97, 0xbf, 0xad, 0x1d, 0x3f, 0xc1, 0xe6, 0x2f, 0x2b,
+    0xbb, 0x1d, 0x3e, 0xf7, 0xa9, 0xba, 0x3a, 0x7f, 0xdf, 0xe6, 0xe1, 0xbd,
+    0xcc, 0xa6, 0x0e, 0x8d, 0xcf, 0xa6, 0xf1, 0x3c, 0xce, 0xd3, 0xa1, 0xd1,
+    0xb7, 0x90, 0xa1, 0xe9, 0x2c, 0xff, 0x3e, 0xbe, 0xe7, 0x73, 0x18, 0x3a,
+    0x7f, 0x67, 0x5a, 0x0c, 0xc6, 0x0e, 0x9e, 0x6f, 0xde, 0x39, 0xd3, 0xba,
+    0xed, 0x3a, 0x28, 0xdf, 0x5e, 0x23, 0x9f, 0x9d, 0x78, 0x9d, 0x60, 0xe9,
+    0xf6, 0x07, 0x8f, 0xc3, 0xa7, 0xba, 0x8c, 0xab, 0x9d, 0x2d, 0x09, 0xe5,
+    0xe8, 0x9a, 0x1d, 0x33, 0x04, 0x70, 0xe1, 0x15, 0x3b, 0xcf, 0xfe, 0x75,
+    0xbb, 0x42, 0x2f, 0xca, 0xce, 0x9d, 0x07, 0x43, 0x4f, 0x42, 0xfd, 0x1a,
+    0x7f, 0x58, 0x72, 0xf0, 0xe6, 0x8e, 0x9f, 0xed, 0xdb, 0x58, 0x39, 0xed,
+    0x1d, 0x1b, 0xa2, 0x3b, 0x84, 0xa2, 0x65, 0x3a, 0x9b, 0x7e, 0x74, 0xfc,
+    0xf9, 0xe4, 0x16, 0x4a, 0x8a, 0x3c, 0x90, 0x0f, 0x4f, 0xfe, 0xcf, 0x3b,
+    0x3f, 0x76, 0xd6, 0x2d, 0xd5, 0xce, 0x9f, 0xfb, 0x94, 0x9e, 0x6e, 0x28,
+    0x38, 0x03, 0xa7, 0xc2, 0xc3, 0xf1, 0xce, 0x9f, 0x67, 0x37, 0xa5, 0x73,
+    0xa7, 0x81, 0xa7, 0x13, 0xa7, 0xf7, 0x79, 0x49, 0xa4, 0xbc, 0x74, 0x39,
+    0xe9, 0xe1, 0x04, 0x22, 0x60, 0xb4, 0x84, 0x24, 0xda, 0x7d, 0x9f, 0x99,
+    0x7e, 0xf6, 0x98, 0x3a, 0x7f, 0xdf, 0xd7, 0x71, 0x69, 0x7e, 0xeb, 0x3a,
+    0x7d, 0xb7, 0x9f, 0x76, 0x9d, 0x0e, 0x89, 0x7c, 0x2e, 0xa4, 0x09, 0xfa,
+    0xf7, 0x69, 0xd2, 0xfc, 0xe9, 0x61, 0xd0, 0xb3, 0x7e, 0x26, 0x13, 0xf8,
+    0x3f, 0x03, 0xf6, 0xbb, 0xd3, 0xa7, 0xf9, 0xd0, 0x3e, 0x1a, 0xdf, 0x47,
+    0x43, 0x9f, 0x70, 0x9b, 0xc5, 0xf0, 0xca, 0xbc, 0x56, 0xc4, 0x87, 0x7e,
+    0x09, 0x16, 0x43, 0x4d, 0x43, 0xdb, 0x35, 0xef, 0x08, 0x04, 0x28, 0x60,
+    0x7b, 0xb1, 0x82, 0x2c, 0xcf, 0x91, 0xb4, 0xd4, 0x63, 0x20, 0x79, 0x12,
+    0x1d, 0x46, 0xa9, 0xe8, 0x69, 0x7e, 0xd9, 0xf6, 0x11, 0xd3, 0xff, 0x71,
+    0x1f, 0xdc, 0xa5, 0x30, 0x40, 0x74, 0xff, 0xf6, 0x6e, 0xdf, 0x7f, 0xb5,
+    0xdc, 0xa5, 0xa6, 0x8e, 0x9f, 0xef, 0xeb, 0x02, 0x9b, 0x8d, 0x1d, 0x3b,
+    0xc2, 0xe7, 0x4d, 0xcb, 0xb1, 0x1c, 0xc2, 0x85, 0xa5, 0x3f, 0xa6, 0xf1,
+    0x72, 0xa7, 0xa7, 0x94, 0x61, 0x3f, 0x67, 0x6d, 0x55, 0x63, 0x45, 0x9b,
+    0x3e, 0x55, 0x77, 0x1f, 0x87, 0x45, 0xc7, 0xc5, 0x47, 0x13, 0xf9, 0x77,
+    0x3a, 0x2f, 0xef, 0x4e, 0x9b, 0x02, 0x74, 0xff, 0xa9, 0xb7, 0x67, 0x6d,
+    0x55, 0x63, 0x45, 0x01, 0x3f, 0x91, 0x6e, 0xaf, 0xcc, 0xd8, 0xe9, 0x5d,
+    0x88, 0x94, 0x58, 0xaf, 0x12, 0xa7, 0xea, 0xf6, 0x9a, 0x80, 0x3a, 0x7e,
+    0x6d, 0xd8, 0xc3, 0xb4, 0xe8, 0xb8, 0xf6, 0x9c, 0xb2, 0x6f, 0xf8, 0x74,
+    0xfd, 0xa7, 0x58, 0xbb, 0x07, 0x4b, 0x87, 0x4e, 0xfa, 0x2c, 0x1d, 0x36,
+    0x7b, 0x0d, 0x70, 0x04, 0x20, 0x08, 0x85, 0x15, 0xa9, 0xbe, 0x68, 0xe9,
+    0xdf, 0x87, 0x0e, 0x9f, 0xd9, 0xdf, 0x0b, 0xaf, 0x47, 0x4a, 0xfc, 0xe8,
+    0x43, 0xe0, 0xe0, 0xe0, 0x0c, 0x67, 0xad, 0x55, 0x63, 0x45, 0xbf, 0x3f,
+    0x7d, 0xf5, 0x5a, 0xba, 0x74, 0x74, 0xf6, 0xc0, 0x5b, 0x3d, 0x82, 0x8c,
+    0x1d, 0x3e, 0xf3, 0x75, 0xf7, 0x47, 0x4e, 0xd7, 0x02, 0x74, 0xfb, 0xef,
+    0x85, 0xc0, 0x74, 0x2c, 0xf1, 0x2f, 0x0e, 0x4f, 0xfd, 0xed, 0x26, 0x9c,
+    0x73, 0xdc, 0x43, 0xa7, 0x0e, 0x70, 0xe8, 0x59, 0xed, 0xde, 0x41, 0x9f,
+    0x05, 0xd5, 0xff, 0x59, 0xd0, 0xe8, 0xce, 0xc7, 0xf4, 0x24, 0x9e, 0xa4,
+    0x1f, 0x1d, 0x3b, 0xaf, 0xe3, 0xa7, 0xe6, 0x28, 0x3c, 0x45, 0x9d, 0x3f,
+    0x79, 0x30, 0x2e, 0xb3, 0xa3, 0xc7, 0xb0, 0xc9, 0x6c, 0xda, 0x13, 0xa7,
+    0xed, 0xf4, 0xf6, 0xc5, 0x9d, 0x1d, 0x46, 0xc5, 0x39, 0xe8, 0x8f, 0xf1,
+    0x59, 0xee, 0x28, 0x15, 0x9d, 0x36, 0x34, 0xe8, 0xc3, 0x70, 0x24, 0x71,
+    0x7c, 0x2e, 0x7a, 0xbc, 0x27, 0x1a, 0x44, 0x17, 0x8c, 0x84, 0x4a, 0x11,
+    0x74, 0x83, 0x91, 0x9e, 0x00, 0xb4, 0x61, 0xef, 0xe7, 0x59, 0xfa, 0xb7,
+    0xb9, 0x75, 0xe3, 0xa2, 0xe4, 0x6f, 0x8c, 0x2c, 0x66, 0x56, 0xaf, 0x83,
+    0xa7, 0xbb, 0xdc, 0xfa, 0x74, 0xfc, 0x9a, 0xdb, 0x19, 0xb9, 0x59, 0x3c,
+    0x3a, 0x20, 0x9f, 0x76, 0xd5, 0x56, 0x34, 0x52, 0x93, 0xff, 0xd5, 0xe1,
+    0xcd, 0xba, 0xfc, 0x4e, 0x67, 0x4e, 0x9d, 0x4d, 0xbb, 0x11, 0x00, 0x03,
+    0x39, 0xfe, 0x6d, 0xd9, 0xdb, 0x55, 0x58, 0xd1, 0x27, 0x4a, 0xe5, 0x9f,
+    0xcd, 0x1a, 0x43, 0xbf, 0x4b, 0x96, 0xd2, 0xb2, 0xda, 0xc0, 0x1b, 0xcc,
+    0x1c, 0xc2, 0xcb, 0x46, 0x2a, 0x90, 0x83, 0x57, 0x85, 0x03, 0x04, 0xfd,
+    0x51, 0x5d, 0x35, 0xe7, 0x90, 0x8e, 0xa2, 0x20, 0x43, 0x24, 0x61, 0x21,
+    0xa9, 0xdf, 0x6f, 0x35, 0xde, 0x8d, 0x12, 0x7d, 0xdb, 0x55, 0x58, 0xd1,
+    0x0f, 0xcf, 0xfa, 0x9b, 0x76, 0x76, 0xd5, 0x56, 0x34, 0x4a, 0x72, 0xbb,
+    0x0f, 0xf5, 0x66, 0x73, 0xfa, 0xec, 0xed, 0xaa, 0xac, 0x68, 0x89, 0xe7,
+    0xe6, 0x13, 0xda, 0xfd, 0x67, 0x4f, 0xbb, 0x6a, 0xab, 0x1a, 0x23, 0x19,
+    0x5c, 0xe7, 0xc5, 0x85, 0xf3, 0xff, 0xae, 0x5d, 0x36, 0xec, 0xed, 0xaa,
+    0xac, 0x68, 0x9e, 0x67, 0xeb, 0x80, 0xe2, 0xdd, 0x1d, 0x0e, 0x9b, 0xa6,
+    0xc5, 0x0d, 0x85, 0x0f, 0x09, 0xfc, 0xaf, 0x3e, 0xed, 0xaa, 0xac, 0x68,
+    0x88, 0x27, 0xfd, 0x4d, 0xbb, 0x3b, 0x6a, 0xab, 0x1a, 0x25, 0x49, 0x5d,
+    0x87, 0xfa, 0xb3, 0x39, 0xfd, 0x76, 0x76, 0xd5, 0x56, 0x34, 0x45, 0x13,
+    0xfa, 0xec, 0xed, 0xaa, 0xac, 0x68, 0x8c, 0xa7, 0xff, 0x5c, 0xba, 0x6d,
+    0xd9, 0xdb, 0x55, 0x58, 0xd1, 0x32, 0xcf, 0xeb, 0xb3, 0xb6, 0xaa, 0xb1,
+    0xa2, 0xa4, 0x9f, 0xd7, 0x67, 0x6d, 0x55, 0x63, 0x45, 0x75, 0x3f, 0xae,
+    0xce, 0xda, 0xaa, 0xc6, 0x8b, 0x16, 0x7f, 0xe5, 0xd3, 0x6e, 0xce, 0xda,
+    0xaa, 0xc6, 0x89, 0xea, 0x7f, 0x99, 0xba, 0x9d, 0x2f, 0xd1, 0x51, 0xd3,
+    0xff, 0xe6, 0x05, 0xd7, 0x76, 0x69, 0x19, 0x0d, 0x52, 0x87, 0x4f, 0xfb,
+    0xfd, 0x72, 0x9b, 0x75, 0xf1, 0xaf, 0x1d, 0x3e, 0xcf, 0x69, 0x16, 0x74,
+    0xff, 0xe7, 0xdf, 0xd8, 0xc2, 0x77, 0xda, 0xfd, 0x5c, 0xe9, 0xd5, 0xbd,
+    0xc2, 0x7e, 0xbe, 0x26, 0x97, 0xb1, 0x34, 0x5e, 0xab, 0x6a, 0x17, 0x71,
+    0x72, 0xa0, 0xd7, 0x50, 0x48, 0xe0, 0xa7, 0xd9, 0xe4, 0xff, 0x47, 0x4c,
+    0xac, 0xab, 0x61, 0xd0, 0xad, 0x87, 0x92, 0xac, 0x49, 0xe7, 0xfa, 0xfb,
+    0xfa, 0x39, 0xde, 0xbd, 0x8e, 0x9e, 0xea, 0xfd, 0xb9, 0xd3, 0xad, 0x9c,
+    0x2a, 0x72, 0xdf, 0x47, 0x4f, 0xff, 0xdc, 0x1a, 0x51, 0x3a, 0xed, 0x6e,
+    0x68, 0x00, 0x73, 0xa7, 0xff, 0xee, 0xa2, 0xaa, 0x5d, 0xcf, 0xde, 0xa2,
+    0xab, 0x7f, 0xb1, 0xd3, 0xc9, 0xcf, 0xab, 0x3a, 0x7f, 0xf2, 0x29, 0xf3,
+    0x06, 0xb7, 0xd2, 0x8a, 0x51, 0xd1, 0x63, 0xf0, 0x12, 0x39, 0xff, 0xd5,
+    0xa1, 0xc0, 0x5d, 0xc4, 0xb5, 0x74, 0xe9, 0xf8, 0x38, 0xa7, 0xb2, 0xc7,
+    0x4f, 0x71, 0xd7, 0x63, 0xa2, 0x8f, 0x3b, 0xc5, 0xb3, 0xff, 0x87, 0xe3,
+    0xb8, 0xba, 0xfe, 0x7c, 0xe5, 0xf9, 0xd3, 0xfe, 0xe6, 0x31, 0xc4, 0xe3,
+    0xf5, 0xce, 0x9a, 0xb7, 0x3a, 0x7f, 0x56, 0xab, 0x9f, 0x8e, 0xc7, 0x40,
+    0x9e, 0x4f, 0xe2, 0xd1, 0xb2, 0xb1, 0x54, 0x1b, 0xea, 0xca, 0xe1, 0xa3,
+    0xc2, 0x11, 0x84, 0xb7, 0x88, 0x7e, 0xa8, 0x2a, 0x84, 0x34, 0xe1, 0xaf,
+    0x1d, 0x38, 0x53, 0x47, 0x49, 0x9b, 0xe4, 0xda, 0x38, 0xd4, 0xf7, 0x6f,
+    0x52, 0xce, 0x9f, 0x2c, 0x6b, 0xda, 0x3a, 0x7c, 0xde, 0x3e, 0x74, 0xe8,
+    0xdc, 0xf3, 0x3a, 0x4d, 0x18, 0x8b, 0xe4, 0x2c, 0xfd, 0xbe, 0x7f, 0xb9,
+    0x5e, 0x76, 0x34, 0x8b, 0x3a, 0x7f, 0x3b, 0x47, 0x37, 0xf6, 0x1d, 0x3b,
+    0x9f, 0xac, 0xe8, 0x44, 0x43, 0x74, 0xe3, 0xf3, 0x19, 0xf0, 0xa8, 0x99,
+    0xa3, 0xa7, 0xcc, 0xd7, 0xaa, 0xc7, 0x4f, 0xfd, 0x8c, 0xd0, 0x32, 0xdc,
+    0xa0, 0x68, 0xe9, 0xff, 0x6a, 0xb7, 0x71, 0xa0, 0xe2, 0x87, 0x42, 0x23,
+    0x37, 0x84, 0xc2, 0x4f, 0xe4, 0x39, 0xcb, 0x7e, 0x1d, 0x3c, 0x21, 0xf8,
+    0xa1, 0xd3, 0xf6, 0x69, 0x9a, 0x1d, 0x8e, 0x8c, 0x3e, 0xca, 0x1b, 0x12,
+    0x49, 0xf7, 0xea, 0x68, 0x2e, 0x74, 0xfc, 0xfb, 0xb7, 0x48, 0x27, 0x46,
+    0x26, 0x50, 0x90, 0xa7, 0xe1, 0x60, 0x94, 0xcf, 0xff, 0xf9, 0x3b, 0xd7,
+    0xfb, 0xe4, 0x1f, 0xdb, 0x9a, 0x0f, 0xf5, 0xd6, 0x9d, 0x3f, 0xff, 0x0e,
+    0x29, 0x83, 0xf3, 0x5e, 0xe6, 0x2f, 0xeb, 0x80, 0xe9, 0x71, 0xd1, 0x97,
+    0x8d, 0xd3, 0xd5, 0xbf, 0x96, 0x74, 0xfb, 0x60, 0xf5, 0x19, 0x3a, 0x7e,
+    0x0d, 0x74, 0x17, 0xf8, 0x74, 0xf3, 0x79, 0xf6, 0xf1, 0xd3, 0xfe, 0x14,
+    0x6f, 0xb9, 0x9d, 0x4d, 0x1d, 0x3f, 0xea, 0xc0, 0x38, 0xd0, 0x71, 0x43,
+    0xa1, 0xa7, 0xee, 0x03, 0xc9, 0xfd, 0x5b, 0xeb, 0xde, 0xc5, 0x73, 0xa7,
+    0xff, 0x3e, 0x6f, 0xee, 0x3f, 0x85, 0xc1, 0xa3, 0xa7, 0x6b, 0x8b, 0x3a,
+    0x3c, 0x7c, 0x9f, 0xa4, 0x4e, 0xd9, 0x3a, 0x74, 0xfd, 0xfe, 0xbd, 0xac,
+    0xf1, 0xd3, 0x99, 0x65, 0x92, 0xa7, 0xff, 0x79, 0x3d, 0xae, 0x25, 0xff,
+    0xde, 0xbb, 0x4a, 0xb8, 0xbf, 0x85, 0x11, 0x8e, 0x83, 0x9f, 0xa6, 0xcf,
+    0xff, 0xf2, 0x79, 0xae, 0x39, 0xee, 0x26, 0x79, 0xd6, 0x9d, 0x69, 0xd0,
+    0xd5, 0x6e, 0xe1, 0x27, 0xc2, 0x24, 0x29, 0x60, 0xbf, 0xb0, 0x9d, 0x59,
+    0x10, 0xc2, 0x6b, 0xd0, 0xea, 0xbc, 0x63, 0x3f, 0xdb, 0xb7, 0x5a, 0xc0,
+    0xd7, 0x8e, 0x96, 0x1d, 0x0e, 0x79, 0x0a, 0x1c, 0xca, 0x8e, 0x9c, 0xfc,
+    0xd1, 0xd1, 0xb9, 0xaa, 0x40, 0xf9, 0xff, 0xfa, 0xbc, 0x9c, 0xa5, 0xfc,
+    0xcd, 0x3e, 0x77, 0x04, 0xe9, 0x27, 0x4f, 0xe4, 0x48, 0x67, 0xbc, 0xfb,
+    0xb2, 0x74, 0x70, 0xf2, 0x59, 0x26, 0x99, 0x9e, 0x1d, 0x3f, 0xf9, 0xc6,
+    0xdf, 0x7b, 0x40, 0x4f, 0x71, 0xce, 0x9f, 0xc8, 0xce, 0xb3, 0x07, 0x63,
+    0xa7, 0x9f, 0x4f, 0x78, 0xe9, 0xff, 0x9c, 0x6b, 0xcd, 0x75, 0x29, 0x9f,
+    0x1d, 0x1c, 0x3e, 0x5f, 0xc8, 0xa7, 0x7c, 0xab, 0x1d, 0x16, 0x4c, 0xdc,
+    0x02, 0xfa, 0x49, 0xf4, 0x25, 0xd5, 0x11, 0xcf, 0x2f, 0xeb, 0x89, 0xd3,
+    0xf3, 0x2a, 0x55, 0x08, 0x0e, 0x9b, 0xf5, 0x9d, 0x08, 0x78, 0x9c, 0x2d,
+    0x9f, 0xcf, 0x5d, 0xe3, 0x34, 0x12, 0xa6, 0x65, 0x92, 0xa0, 0x27, 0x94,
+    0xc9, 0x94, 0xef, 0x22, 0xb9, 0x57, 0x1a, 0x39, 0xfb, 0x7b, 0x26, 0xb8,
+    0x87, 0x4f, 0x7e, 0xdf, 0xfc, 0x74, 0x22, 0x6e, 0x8c, 0x33, 0x6a, 0x11,
+    0xde, 0x2f, 0xbf, 0x2d, 0x99, 0x9d, 0x1d, 0x2c, 0x3a, 0x5b, 0xe1, 0xa6,
+    0xf0, 0xbc, 0xf6, 0xed, 0xbe, 0x77, 0x3a, 0x7f, 0xed, 0x68, 0x22, 0xe1,
+    0xe3, 0xfb, 0x47, 0x43, 0xa2, 0x4f, 0x09, 0xff, 0x29, 0x9f, 0xf7, 0x93,
+    0xb4, 0x05, 0x5e, 0xce, 0x1d, 0x3f, 0xc8, 0xc8, 0xe7, 0x93, 0xf0, 0x1d,
+    0x3f, 0xab, 0xbe, 0xd0, 0xa2, 0x87, 0x4f, 0xfe, 0xd6, 0x29, 0x9f, 0xf6,
+    0x82, 0xfc, 0x73, 0xa1, 0xa9, 0x90, 0xa1, 0x7a, 0xb9, 0xfd, 0x1c, 0x68,
+    0xca, 0x76, 0x27, 0x4e, 0x9f, 0xcd, 0x45, 0xf3, 0x7a, 0x57, 0x3a, 0x7a,
+    0xba, 0xed, 0x3a, 0x36, 0x3f, 0x0d, 0xc6, 0x96, 0x6d, 0x3f, 0xce, 0xbc,
+    0xf9, 0xc5, 0x74, 0x59, 0xd3, 0xfe, 0x7d, 0xf8, 0xeb, 0xb7, 0x11, 0x83,
+    0xa3, 0x11, 0x58, 0x86, 0x3d, 0x3c, 0x9f, 0x5a, 0xb6, 0xc6, 0x4e, 0x9f,
+    0x3f, 0x43, 0x82, 0x74, 0x09, 0xe6, 0xf8, 0xa2, 0x7f, 0xe7, 0x03, 0xf1,
+    0x63, 0x4a, 0x71, 0x0e, 0x9f, 0xc1, 0xe3, 0x8b, 0x35, 0xb9, 0xd3, 0xff,
+    0x20, 0x78, 0xf6, 0x70, 0x50, 0x80, 0xe9, 0xff, 0xfe, 0x5d, 0x0e, 0xed,
+    0xb9, 0x9c, 0x4b, 0xd8, 0x38, 0x1a, 0x69, 0xe2, 0xf5, 0x9e, 0xf0, 0xff,
+    0xb1, 0xd0, 0x88, 0x97, 0x17, 0x48, 0x74, 0xe3, 0xfa, 0x43, 0x48, 0x5a,
+    0x33, 0xfe, 0x1b, 0x13, 0xcd, 0xbe, 0xd5, 0x9b, 0xe0, 0xe9, 0xf0, 0x50,
+    0x68, 0x27, 0x46, 0xe7, 0xac, 0x86, 0x33, 0xff, 0xd9, 0xed, 0x63, 0x1c,
+    0x7b, 0xd9, 0xce, 0x39, 0xd3, 0xff, 0xff, 0xe4, 0xcd, 0xf4, 0x98, 0xcf,
+    0xcc, 0xdd, 0xba, 0x4f, 0x69, 0x37, 0x08, 0x7f, 0xd8, 0xe9, 0xff, 0xf2,
+    0x08, 0x7e, 0x7d, 0xf2, 0x6a, 0x90, 0x7f, 0x69, 0xd0, 0x29, 0x98, 0x79,
+    0x42, 0xf4, 0x22, 0x67, 0xf6, 0xd5, 0xe0, 0x7d, 0x16, 0x9d, 0x39, 0x4c,
+    0x09, 0xd3, 0xf7, 0x2b, 0xb6, 0x7f, 0x1d, 0x35, 0x04, 0xe9, 0xfb, 0xb5,
+    0xae, 0x53, 0x4e, 0x96, 0xe7, 0x4c, 0x8c, 0x9d, 0x37, 0xd0, 0x1d, 0x0c,
+    0x1a, 0xe0, 0x0b, 0x4e, 0x6d, 0x04, 0xe9, 0x99, 0x64, 0xe8, 0x6a, 0x35,
+    0x70, 0x56, 0xc5, 0x88, 0x7f, 0xa2, 0x26, 0x46, 0xe7, 0x7b, 0xe8, 0x0a,
+    0xb8, 0xf5, 0xa7, 0xff, 0xfb, 0x9f, 0xd2, 0x8b, 0xa0, 0xe6, 0x0a, 0x9a,
+    0xd6, 0x08, 0x0e, 0x9f, 0xff, 0x9b, 0x5a, 0xd3, 0xe6, 0xdf, 0xb4, 0x3d,
+    0x1a, 0x64, 0xe9, 0xbc, 0xe1, 0x46, 0x12, 0x33, 0x43, 0x55, 0x49, 0x04,
+    0x73, 0x78, 0xd5, 0xd2, 0x1e, 0x53, 0xfd, 0x9e, 0xe3, 0xf7, 0xd9, 0x63,
+    0xa7, 0x3f, 0x58, 0x3a, 0x1d, 0x73, 0xb7, 0x23, 0x52, 0x43, 0x7a, 0x95,
+    0x8e, 0x29, 0x57, 0xe6, 0xf3, 0xb5, 0x4c, 0x1d, 0x3d, 0x9e, 0xa5, 0x47,
+    0x46, 0xe6, 0xf8, 0x47, 0x27, 0xfd, 0x42, 0x1c, 0x1f, 0xdb, 0x9a, 0x3a,
+    0x79, 0xf3, 0xe8, 0x4e, 0x9f, 0xca, 0x27, 0xab, 0x8c, 0xab, 0x9d, 0x3f,
+    0xdd, 0xc6, 0x39, 0x9a, 0xa1, 0x3a, 0x7f, 0xb9, 0x8d, 0xcf, 0xef, 0xaa,
+    0x13, 0xa7, 0xff, 0xf2, 0x0e, 0x6f, 0xe5, 0x2b, 0xdc, 0x7e, 0x65, 0xea,
+    0x69, 0xd1, 0x64, 0xcb, 0x50, 0x8b, 0xa6, 0xfe, 0x37, 0xbc, 0x79, 0x3f,
+    0xe7, 0xd5, 0x71, 0x03, 0x64, 0xd8, 0xe8, 0xc4, 0x44, 0xfe, 0x99, 0x39,
+    0xc7, 0xc7, 0x4f, 0x57, 0x5d, 0xa7, 0x4f, 0xff, 0xc8, 0x34, 0x82, 0x0e,
+    0xbf, 0x29, 0x3c, 0xfc, 0x3a, 0x04, 0xfd, 0x7c, 0x41, 0x3e, 0x4f, 0x6b,
+    0xfd, 0x8e, 0x9f, 0xfe, 0x71, 0x40, 0x7b, 0x7b, 0x27, 0x7e, 0xb8, 0x4e,
+    0x84, 0x44, 0xd2, 0xc8, 0x7c, 0x53, 0x3e, 0xef, 0xf6, 0xe3, 0x9d, 0x3f,
+    0x75, 0x86, 0xa7, 0xb4, 0x74, 0x85, 0xcf, 0x5b, 0x0a, 0x27, 0xc8, 0xa7,
+    0x29, 0xa7, 0x4f, 0xc8, 0xeb, 0xdb, 0x19, 0x3a, 0x66, 0x59, 0x3a, 0x2c,
+    0x7d, 0x9d, 0x27, 0x64, 0xb6, 0x7f, 0xb1, 0x8a, 0x62, 0xb7, 0x6e, 0x8a,
+    0xb8, 0xd8, 0x4f, 0xec, 0xdb, 0x07, 0x6c, 0x64, 0xe9, 0xf3, 0xf7, 0xb9,
+    0xc3, 0xa7, 0xe1, 0xa5, 0x1d, 0x6e, 0x74, 0x34, 0xf4, 0x7f, 0x26, 0x9e,
+    0x7d, 0x94, 0x50, 0xe9, 0xca, 0xe9, 0x78, 0xe9, 0xc1, 0x75, 0x9d, 0x3f,
+    0xb0, 0x18, 0xc3, 0xef, 0xa3, 0xa1, 0xcf, 0x3b, 0x06, 0xe7, 0xee, 0x53,
+    0x5f, 0x4d, 0x3a, 0x7f, 0xb3, 0x89, 0xbe, 0xb9, 0xfe, 0x8e, 0x9b, 0x06,
+    0xc7, 0xcc, 0x02, 0xc9, 0xf8, 0x68, 0x01, 0xc1, 0x3a, 0x7e, 0x5a, 0x5f,
+    0xe7, 0x54, 0x3a, 0x73, 0x2c, 0xb2, 0x54, 0xff, 0xcf, 0xd1, 0xfe, 0xbe,
+    0xe3, 0x0e, 0xb3, 0xae, 0x2f, 0xe1, 0xd7, 0x5c, 0xf2, 0x32, 0x95, 0x78,
+    0x42, 0xb1, 0x0c, 0x1e, 0xa5, 0xae, 0x10, 0x9c, 0x23, 0xa2, 0x41, 0x6e,
+    0xd4, 0x21, 0xbc, 0x59, 0xf9, 0x53, 0x29, 0xf3, 0xdd, 0xee, 0x70, 0xe9,
+    0xfb, 0x88, 0xa9, 0x57, 0xea, 0x1d, 0x0e, 0x7a, 0x96, 0x21, 0x95, 0xf4,
+    0x74, 0x90, 0xe9, 0xfe, 0xf3, 0xf7, 0x5c, 0x71, 0xf1, 0xd2, 0xbe, 0x8e,
+    0x9f, 0xef, 0x3f, 0x75, 0xc7, 0x1f, 0x1d, 0x36, 0x9c, 0xe9, 0xcb, 0x0b,
+    0x9d, 0x3f, 0x87, 0xd4, 0xc6, 0x9f, 0xc7, 0x42, 0x1e, 0x6d, 0x0d, 0xcf,
+    0x25, 0x65, 0x8e, 0x9f, 0xf6, 0x5e, 0x1c, 0xd3, 0x02, 0xe1, 0x3a, 0x7a,
+    0xc1, 0x7d, 0x8e, 0x98, 0x0e, 0x74, 0xed, 0x27, 0x4e, 0x8c, 0x3d, 0x20,
+    0x11, 0x78, 0x56, 0x7f, 0x37, 0x05, 0x03, 0x82, 0x74, 0xef, 0x6a, 0xe7,
+    0x4f, 0x6b, 0x05, 0x58, 0x37, 0xe3, 0x10, 0x08, 0x04, 0x7f, 0x50, 0x90,
+    0xf1, 0x74, 0xda, 0x73, 0xa7, 0x2c, 0x2e, 0x74, 0xfe, 0x1f, 0x53, 0x1a,
+    0x7f, 0x1d, 0x08, 0x79, 0xb4, 0x37, 0x3c, 0x95, 0x96, 0x3a, 0x7f, 0xd9,
+    0x78, 0x73, 0x4c, 0x0b, 0x84, 0xe9, 0xeb, 0x05, 0xf6, 0x3a, 0x7e, 0x60,
+    0x08, 0xaf, 0x4c, 0x1d, 0x30, 0x1c, 0xe9, 0xda, 0x4e, 0x9d, 0x18, 0x88,
+    0x3b, 0x11, 0x00, 0xc7, 0xc2, 0xb3, 0xf9, 0xb8, 0x28, 0x1c, 0x13, 0xa7,
+    0xe1, 0xa0, 0xe2, 0x97, 0x3a, 0xe4, 0x50, 0x45, 0x70, 0x3e, 0xd2, 0x84,
+    0x58, 0x84, 0x47, 0x18, 0x80, 0x40, 0x23, 0xfa, 0x86, 0x0f, 0x8f, 0x27,
+    0xff, 0xd4, 0x1c, 0xc1, 0x53, 0xe8, 0xb8, 0xec, 0x9d, 0x3a, 0x75, 0x77,
+    0x63, 0xc8, 0x25, 0x3c, 0xdc, 0xdd, 0xa7, 0x90, 0x4a, 0x76, 0x90, 0x27,
+    0x90, 0x4a, 0x66, 0x59, 0x3c, 0x82, 0x51, 0x64, 0x52, 0xb0, 0x53, 0xe2,
+    0xf6, 0x4a, 0x26, 0xaf, 0x16, 0x41, 0x25, 0xc6, 0xfe, 0x7e, 0xce, 0x66,
+    0x0a, 0x87, 0x4e, 0xa1, 0x07, 0xc5, 0xf0, 0x27, 0x9c, 0xab, 0x5c, 0x30,
+    0x06, 0x33, 0x8f, 0x1a, 0x4f, 0x5f, 0xe5, 0x70, 0xe9, 0x62, 0xba, 0x24,
+    0xc0, 0xe1, 0x26, 0x9d, 0x3f, 0x98, 0x6f, 0xfb, 0x79, 0x36, 0x2a, 0x7f,
+    0x23, 0x7f, 0xad, 0x71, 0x0e, 0x9f, 0xb2, 0xf5, 0x2f, 0x38, 0x74, 0x9a,
+    0x54, 0xea, 0xee, 0xc5, 0x41, 0x50, 0xe6, 0xda, 0xc2, 0x0b, 0x1c, 0x9c,
+    0xe0, 0xb1, 0x57, 0x1a, 0xd8, 0x5a, 0x2f, 0x06, 0x12, 0x10, 0xe9, 0x8a,
+    0xe4, 0x3b, 0xa7, 0xbf, 0xae, 0xb4, 0xe9, 0x2c, 0xe9, 0xb1, 0xa1, 0x36,
+    0x4c, 0x11, 0x4f, 0x99, 0xc6, 0x11, 0x67, 0x4f, 0xd6, 0x76, 0x1a, 0xe0,
+    0x2a, 0x48, 0x74, 0xff, 0x6d, 0xfb, 0x43, 0xcf, 0xe8, 0x4e, 0x9f, 0x91,
+    0xd7, 0xb6, 0x32, 0x74, 0xfb, 0x36, 0x5e, 0x2c, 0xe9, 0xda, 0x4e, 0x9d,
+    0x02, 0x78, 0x5e, 0x27, 0x9f, 0x86, 0x80, 0x0f, 0xf4, 0x74, 0xfc, 0x8a,
+    0x7d, 0x75, 0xdc, 0x14, 0xc1, 0xf0, 0x3f, 0xa7, 0x7a, 0x6f, 0xf1, 0x0c,
+    0x62, 0x79, 0x88, 0x50, 0x31, 0x9a, 0x4f, 0x0e, 0x6d, 0xf9, 0xd0, 0xd5,
+    0xc2, 0xf0, 0x95, 0xe0, 0x87, 0x23, 0x4c, 0x15, 0x9d, 0x47, 0xf3, 0xe3,
+    0x49, 0xff, 0xf6, 0xdd, 0xee, 0x06, 0x97, 0xca, 0xf0, 0xbb, 0x07, 0x4f,
+    0xff, 0xfe, 0xff, 0xbf, 0xb0, 0x34, 0x0d, 0x6b, 0x14, 0xcf, 0xfb, 0x41,
+    0x7e, 0x39, 0xd3, 0xca, 0xb9, 0xff, 0xd3, 0xa7, 0x32, 0xcb, 0x25, 0x4c,
+    0xd7, 0x2a, 0xe2, 0xfe, 0x1d, 0x33, 0xad, 0x95, 0x77, 0x7a, 0xea, 0x34,
+    0xfc, 0xa3, 0xf7, 0xb9, 0xc3, 0xa7, 0xed, 0x98, 0x6d, 0xf7, 0xdd, 0x8e,
+    0x9e, 0xe5, 0x6e, 0xc9, 0xd3, 0xed, 0xba, 0x8e, 0xb3, 0xa7, 0xff, 0x9f,
+    0xef, 0x85, 0xc1, 0x5e, 0x07, 0xd1, 0x69, 0xd0, 0xad, 0x23, 0x45, 0x0d,
+    0xa8, 0x8f, 0xc4, 0xf3, 0xbe, 0x85, 0x83, 0xa7, 0x35, 0x04, 0xe9, 0xed,
+    0xbe, 0xaa, 0x64, 0xe9, 0xfb, 0xce, 0xc0, 0xff, 0xa3, 0xa7, 0xea, 0x10,
+    0x67, 0x94, 0x3a, 0x36, 0x45, 0xdb, 0x47, 0xe8, 0x6b, 0xc5, 0x17, 0xe5,
+    0xd3, 0x56, 0x8e, 0x9b, 0xfb, 0xe8, 0xe8, 0x13, 0x63, 0xf8, 0xac, 0xd5,
+    0x75, 0xf0, 0xed, 0xa6, 0xaf, 0xb2, 0xf5, 0x6e, 0x7c, 0xac, 0x08, 0xde,
+    0x59, 0x86, 0xd1, 0xc2, 0x36, 0x16, 0xa1, 0x94, 0x4b, 0x93, 0x90, 0x4a,
+    0x43, 0x92, 0xd1, 0x87, 0x6f, 0x1a, 0xd2, 0x47, 0x8c, 0xc4, 0xa2, 0xde,
+    0xc6, 0xd0, 0xb9, 0x41, 0x5c, 0x9d, 0x92, 0xa8, 0x51, 0x80, 0x84, 0x63,
+    0xf2, 0xd4, 0xec, 0xb7, 0xa9, 0x9d, 0x3f, 0xc7, 0x56, 0xc9, 0xfd, 0xfc,
+    0x3f, 0xbe, 0xc3, 0xed, 0x53, 0xf4, 0xf9, 0x78, 0x94, 0x03, 0xa7, 0xdd,
+    0xb5, 0x55, 0x8d, 0x14, 0x54, 0xfa, 0xe5, 0xd3, 0x6e, 0x73, 0xd8, 0xc2,
+    0x59, 0xfd, 0x76, 0x76, 0xd5, 0x56, 0x34, 0x5d, 0x13, 0xff, 0x5d, 0x4d,
+    0xbb, 0x3b, 0x6a, 0xab, 0x1a, 0x24, 0xb9, 0xf7, 0x6d, 0x55, 0x63, 0x45,
+    0xe5, 0x35, 0x5e, 0x3a, 0x57, 0x61, 0xe5, 0x5f, 0x99, 0xc3, 0xbb, 0xe9,
+    0x5d, 0x8a, 0x1a, 0x7f, 0x87, 0xf6, 0x57, 0x60, 0xfd, 0x67, 0xfc, 0x94,
+    0x98, 0x36, 0xdc, 0x6b, 0x52, 0x9c, 0x3c, 0x7f, 0xf9, 0xfd, 0xe8, 0x4d,
+    0xcf, 0xfe, 0xb9, 0x74, 0xdb, 0xb3, 0xb6, 0xaa, 0xb1, 0xa2, 0x59, 0x9b,
+    0xfe, 0x1d, 0x3d, 0xc7, 0x57, 0x59, 0xd3, 0xbf, 0xb5, 0x1d, 0x0a, 0xe7,
+    0x81, 0xf4, 0x92, 0x7e, 0x0f, 0xbf, 0xa6, 0xe8, 0xe9, 0xff, 0x71, 0xf8,
+    0x8a, 0x7b, 0x54, 0x03, 0xa7, 0xad, 0x55, 0x63, 0x44, 0x67, 0x3f, 0x23,
+    0xaf, 0x6c, 0x64, 0xe9, 0x85, 0xa7, 0x49, 0x67, 0x4f, 0x93, 0xbc, 0xab,
+    0xba, 0x7a, 0x4b, 0x2d, 0xfa, 0x2b, 0x3f, 0x53, 0x53, 0xb5, 0xd3, 0xa7,
+    0xfe, 0xd2, 0x7f, 0xac, 0x1f, 0xdb, 0x9a, 0x3a, 0x76, 0x9f, 0x73, 0xa1,
+    0xa9, 0xcb, 0x74, 0xf9, 0x6f, 0xe2, 0x9d, 0xa2, 0xbf, 0x22, 0x4f, 0xf3,
+    0x75, 0x8f, 0xf1, 0xf4, 0xb3, 0xa7, 0xfe, 0xf2, 0x76, 0x81, 0xf3, 0x76,
+    0xba, 0xce, 0x9f, 0x0b, 0xb7, 0x54, 0x74, 0x21, 0xf5, 0xde, 0x46, 0x9f,
+    0x29, 0xef, 0x3a, 0xce, 0x9b, 0xeb, 0x4e, 0x84, 0x3c, 0x0a, 0x28, 0x9f,
+    0xfe, 0xff, 0xda, 0xdd, 0xae, 0x20, 0xd7, 0xcf, 0xc4, 0xe9, 0xcf, 0xe7,
+    0x3a, 0x48, 0x13, 0xee, 0xbc, 0xa9, 0x37, 0x18, 0x3a, 0x7f, 0x6f, 0xa1,
+    0xce, 0x85, 0xce, 0x84, 0x3c, 0x9a, 0x17, 0x9e, 0xf7, 0x3f, 0xbf, 0x3a,
+    0x7f, 0xbc, 0x8c, 0xe9, 0xf9, 0x4a, 0xe7, 0x4b, 0x10, 0xf8, 0x56, 0x4d,
+    0x3f, 0xee, 0x3a, 0x71, 0x1c, 0x58, 0xfc, 0xe9, 0x91, 0x93, 0xa6, 0x55,
+    0x87, 0x46, 0x8d, 0x6f, 0x85, 0xa7, 0xf6, 0x69, 0xfd, 0xae, 0x21, 0xd3,
+    0xc0, 0x4d, 0xda, 0x74, 0xfe, 0x71, 0xf2, 0x6c, 0x2e, 0x74, 0x00, 0xf4,
+    0x84, 0x8a, 0x57, 0x5f, 0x0b, 0xce, 0xce, 0xaf, 0xb1, 0x3e, 0x47, 0x89,
+    0xba, 0xbb, 0x10, 0xa4, 0xe3, 0x1d, 0x42, 0x38, 0x0e, 0x43, 0x08, 0x1d,
+    0x13, 0x5e, 0x6a, 0xbf, 0x21, 0xfb, 0x08, 0x39, 0xff, 0xd7, 0x2e, 0x9b,
+    0x76, 0x76, 0xd5, 0x56, 0x34, 0x4d, 0x33, 0xff, 0xae, 0x5d, 0x36, 0xec,
+    0xed, 0xaa, 0xac, 0x68, 0x9c, 0x67, 0xff, 0x5c, 0xba, 0x6d, 0xd9, 0xdb,
+    0x55, 0x58, 0xd1, 0x40, 0xcf, 0xbb, 0x6a, 0xab, 0x1a, 0x2e, 0x09, 0xf8,
+    0x73, 0xd6, 0x4d, 0x1d, 0x33, 0xa1, 0xd3, 0xf8, 0x5a, 0xe8, 0x1c, 0x59,
+    0xd1, 0x88, 0xa2, 0x59, 0x9f, 0x0a, 0xff, 0x14, 0x9f, 0x36, 0xe5, 0x2f,
+    0x95, 0x0e, 0x8b, 0x8f, 0xb5, 0xcf, 0x67, 0xec, 0x61, 0xae, 0x2d, 0x3a,
+    0x79, 0xc1, 0x8c, 0x9d, 0x32, 0x5c, 0x27, 0x9b, 0xf4, 0xb2, 0x7f, 0x9b,
+    0x76, 0x76, 0xd5, 0x56, 0x34, 0x49, 0x32, 0xbb, 0x87, 0xe9, 0x45, 0xf3,
+    0x32, 0x03, 0xa7, 0xf5, 0x78, 0x73, 0x6a, 0x13, 0xa7, 0xe7, 0x5f, 0x70,
+    0x3e, 0x3a, 0x6a, 0xb8, 0x27, 0xe6, 0xa0, 0xbe, 0x8c, 0x23, 0x66, 0x5c,
+    0x4b, 0x67, 0xb3, 0x6d, 0x0e, 0xe6, 0x15, 0xc0, 0xaf, 0xa8, 0xd9, 0xbd,
+    0x0e, 0x3b, 0xd0, 0x9b, 0x9f, 0xf2, 0x95, 0x76, 0x76, 0xd5, 0x56, 0x34,
+    0x5a, 0x93, 0xfe, 0xa6, 0xdd, 0x9d, 0xb5, 0x55, 0x8d, 0x12, 0xac, 0xc8,
+    0xc9, 0xd0, 0x74, 0xae, 0x51, 0x16, 0xab, 0x4b, 0xf2, 0x52, 0xa1, 0x69,
+    0xfd, 0x76, 0x76, 0xd5, 0x56, 0x34, 0x45, 0x33, 0xfa, 0xec, 0xed, 0xaa,
+    0xac, 0x68, 0x8d, 0x26, 0xff, 0x87, 0x4f, 0xf8, 0x38, 0xb4, 0xee, 0x69,
+    0x87, 0x3a, 0x7f, 0xff, 0xab, 0xfd, 0x73, 0x03, 0xf7, 0xee, 0x93, 0xef,
+    0x93, 0x4c, 0x7d, 0x3a, 0x11, 0x15, 0xaa, 0xe7, 0xb3, 0xd6, 0xaa, 0xb1,
+    0xa2, 0x9f, 0x9b, 0xce, 0x74, 0x74, 0xf0, 0xbc, 0x5b, 0x3f, 0xef, 0x30,
+    0xfe, 0xe5, 0x31, 0xf3, 0x0e, 0x9f, 0xfc, 0x8b, 0x1f, 0xf8, 0x9d, 0xcd,
+    0x30, 0xe7, 0x4f, 0xfd, 0xff, 0xbb, 0xfb, 0x1a, 0xb5, 0x31, 0xa3, 0xa7,
+    0xfe, 0xc6, 0x3f, 0x1d, 0xb5, 0x6a, 0x63, 0x47, 0x4a, 0xeb, 0xe1, 0x53,
+    0x3b, 0xc3, 0x13, 0x19, 0xd0, 0x8a, 0x90, 0x45, 0x27, 0xc9, 0x33, 0xff,
+    0xae, 0x5d, 0x36, 0xec, 0xed, 0xaa, 0xac, 0x68, 0x9a, 0xa7, 0xf5, 0xd9,
+    0xdb, 0x55, 0x58, 0xd1, 0x5d, 0xcf, 0x5a, 0xaa, 0xc6, 0x8a, 0xfa, 0x73,
+    0x2c, 0xb2, 0x54, 0x84, 0xab, 0x8b, 0xf8, 0xe9, 0xf5, 0xad, 0x32, 0x73,
+    0x5f, 0x73, 0xa7, 0x31, 0x9c, 0x3a, 0x7f, 0xd9, 0xc6, 0x6b, 0xda, 0x7c,
+    0xd8, 0xe9, 0x78, 0xe9, 0xfe, 0x4e, 0xe6, 0xc8, 0xdc, 0x09, 0xd1, 0xd3,
+    0xc7, 0xa1, 0x09, 0xf6, 0xea, 0xb9, 0xff, 0xd3, 0xa5, 0xd3, 0xa0, 0xe9,
+    0x71, 0x0b, 0xae, 0x88, 0x4a, 0xec, 0x4d, 0xb5, 0x82, 0x2a, 0x1c, 0x11,
+    0xcd, 0x42, 0x17, 0xf2, 0x1b, 0xf4, 0x89, 0xff, 0xd7, 0x2e, 0x9b, 0x76,
+    0x76, 0xd5, 0x56, 0x34, 0x4f, 0x73, 0xee, 0x3a, 0xaa, 0xdc, 0xe9, 0xf7,
+    0x6d, 0x55, 0x63, 0x45, 0xc3, 0x2b, 0x9c, 0xf7, 0x30, 0xa6, 0x7f, 0xeb,
+    0xa9, 0xb7, 0x67, 0x6d, 0x55, 0x63, 0x44, 0x9f, 0x0e, 0xbf, 0x55, 0xb2,
+    0x3b, 0x4f, 0xd4, 0x95, 0x4d, 0x67, 0x26, 0x15, 0xfb, 0x28, 0x5f, 0x8e,
+    0x7a, 0x85, 0x9d, 0xe2, 0x79, 0xfd, 0x76, 0x76, 0xd5, 0x56, 0x34, 0x45,
+    0x53, 0xee, 0xda, 0xaa, 0xc6, 0x8a, 0x66, 0x7e, 0x4e, 0x65, 0x6e, 0x03,
+    0xa5, 0x76, 0x1e, 0xfd, 0xf9, 0x9c, 0xff, 0xeb, 0x97, 0x4d, 0xbb, 0x3b,
+    0x6a, 0xab, 0x1a, 0x26, 0x79, 0xff, 0xd7, 0x2e, 0x9b, 0x76, 0x76, 0xd5,
+    0x56, 0x34, 0x51, 0xb1, 0xb2, 0x6e, 0xe1, 0x84, 0xf2, 0x85, 0x7e, 0x57,
+    0x9f, 0xf5, 0x36, 0xec, 0xed, 0xaa, 0xac, 0x68, 0x8e, 0xa7, 0xfe, 0xee,
+    0xd7, 0x68, 0x73, 0xda, 0x75, 0x9d, 0x17, 0x22, 0x3d, 0xd2, 0xa6, 0xff,
+    0x87, 0x4f, 0x5a, 0xdf, 0xd8, 0xe9, 0xf6, 0x08, 0x73, 0x63, 0xa7, 0xf3,
+    0xbd, 0xb3, 0xbd, 0xc3, 0xa1, 0x0f, 0x58, 0x49, 0xa7, 0xfc, 0x38, 0xa5,
+    0x31, 0xae, 0x38, 0x4e, 0x9e, 0xb5, 0x55, 0x8d, 0x14, 0xd4, 0xfb, 0x37,
+    0x66, 0xb8, 0x74, 0x22, 0x24, 0xfa, 0x7c, 0x25, 0xb3, 0xff, 0xfd, 0x83,
+    0xed, 0x25, 0xb0, 0x75, 0x6e, 0x27, 0x2d, 0xf7, 0x63, 0xa7, 0xfb, 0x55,
+    0xbe, 0x30, 0xfc, 0xd1, 0xd3, 0x71, 0x05, 0x14, 0x1e, 0x67, 0x9f, 0xf9,
+    0xbc, 0x41, 0xdb, 0x5f, 0xbf, 0x58, 0x3a, 0x7f, 0xb5, 0xab, 0x27, 0x7a,
+    0x9b, 0x1d, 0x33, 0xa8, 0x74, 0xfc, 0x8e, 0xbd, 0xb1, 0x93, 0xa7, 0xff,
+    0xb3, 0xdc, 0xc6, 0xf6, 0x87, 0xdc, 0xa6, 0x9d, 0x33, 0x80, 0xe9, 0xfd,
+    0x5b, 0xbd, 0x92, 0xd7, 0x75, 0x11, 0xe2, 0x5b, 0xf5, 0x36, 0x38, 0x8f,
+    0xfd, 0x42, 0x96, 0x7d, 0xee, 0x33, 0x5b, 0x1d, 0x2b, 0xaf, 0x85, 0xc0,
+    0xd7, 0x17, 0x0b, 0xce, 0x42, 0xce, 0xd0, 0xce, 0xdc, 0xb7, 0xa8, 0xde,
+    0x8c, 0xe3, 0xe9, 0x44, 0xfb, 0xb6, 0xaa, 0xb1, 0xa2, 0xaa, 0x9f, 0xf5,
+    0x36, 0xec, 0xed, 0xaa, 0xac, 0x68, 0x9b, 0x65, 0x76, 0x1f, 0xea, 0xcc,
+    0xe7, 0xf5, 0xd9, 0xdb, 0x55, 0x58, 0xd1, 0x5f, 0xcf, 0xbb, 0x6a, 0xab,
+    0x1a, 0x2c, 0x69, 0x95, 0x34, 0xe9, 0x5d, 0x87, 0x96, 0xc1, 0x9c, 0xfb,
+    0x56, 0xe3, 0xa8, 0x74, 0xff, 0x67, 0xbd, 0x9d, 0x0e, 0x09, 0xd3, 0x94,
+    0x6e, 0x1d, 0x2b, 0x84, 0xf4, 0xb4, 0x6d, 0x24, 0xb9, 0x14, 0x5d, 0x7a,
+    0x9f, 0x76, 0xd5, 0x56, 0x34, 0x5a, 0xb3, 0xfe, 0xa6, 0xdd, 0x9d, 0xb5,
+    0x55, 0x8d, 0x14, 0x14, 0xae, 0xc3, 0xfd, 0x59, 0x9c, 0xe5, 0x5d, 0x73,
+    0xa7, 0xad, 0x55, 0x63, 0x45, 0xc5, 0x3f, 0x7f, 0x5b, 0x87, 0x3a, 0x74,
+    0x74, 0xf6, 0xf4, 0x5b, 0x3b, 0xae, 0xb3, 0xa7, 0xa9, 0x52, 0x6c, 0x74,
+    0xfb, 0x9f, 0xa9, 0x82, 0x74, 0xe5, 0x49, 0x63, 0xa0, 0x27, 0x8a, 0xa8,
+    0xa2, 0x7f, 0x3a, 0xea, 0xf3, 0xf5, 0x51, 0xd3, 0xf6, 0x76, 0xbd, 0xfb,
+    0x9d, 0x3f, 0xfd, 0x42, 0xe8, 0xab, 0x49, 0xac, 0xe6, 0x5f, 0x9d, 0x26,
+    0x02, 0x7f, 0x97, 0x8b, 0x25, 0x73, 0xaa, 0x1d, 0xc7, 0x8e, 0x91, 0x70,
+    0x6e, 0x9a, 0x3c, 0x49, 0xf6, 0x16, 0x33, 0xeb, 0xed, 0x5b, 0x81, 0x47,
+    0x3a, 0x7d, 0xdb, 0x55, 0x58, 0xd1, 0x74, 0xcf, 0x9c, 0x68, 0x2e, 0x74,
+    0xae, 0x56, 0x28, 0x8a, 0xc3, 0x34, 0x33, 0x9f, 0xfe, 0xc1, 0xf2, 0x2f,
+    0x8e, 0x83, 0x5d, 0x50, 0xe9, 0xff, 0xcd, 0x7e, 0x83, 0xe6, 0xb8, 0xeb,
+    0xa1, 0x3a, 0x7e, 0x6d, 0x36, 0x86, 0xc7, 0x4c, 0xbb, 0xb0, 0xfd, 0x58,
+    0x4a, 0x9e, 0xc6, 0x55, 0xa5, 0x9d, 0x3f, 0xc9, 0xd1, 0x7d, 0xd7, 0x5e,
+    0x3a, 0x7f, 0xff, 0xbf, 0xeb, 0x75, 0xca, 0x4e, 0xf7, 0xbf, 0xee, 0x9d,
+    0xad, 0x1d, 0x3f, 0xff, 0x70, 0x7f, 0xa5, 0x7c, 0x6f, 0x31, 0x4c, 0x0b,
+    0x1f, 0x9d, 0x35, 0xb0, 0xe8, 0x73, 0xf5, 0x51, 0x82, 0x7f, 0xcd, 0xce,
+    0xf6, 0x9b, 0xb6, 0x32, 0x74, 0xff, 0xd8, 0x17, 0x6b, 0xf5, 0xfe, 0xd0,
+    0x9d, 0x3f, 0xeb, 0xd8, 0xd5, 0x85, 0x2f, 0x38, 0x4e, 0x85, 0xa2, 0x0e,
+    0x90, 0xa6, 0xab, 0xb6, 0x4f, 0x93, 0xb0, 0xde, 0xf1, 0x17, 0xd8, 0x61,
+    0x47, 0x15, 0x39, 0x0c, 0xa1, 0xb9, 0xff, 0x79, 0x2c, 0x81, 0xa1, 0x51,
+    0xce, 0x9f, 0xe7, 0xdf, 0x95, 0xaf, 0x3b, 0x27, 0x43, 0x9f, 0xaf, 0x4f,
+    0x26, 0xff, 0x87, 0x4f, 0x87, 0x39, 0x5e, 0x3a, 0x7e, 0x6d, 0x65, 0xe7,
+    0x09, 0xd1, 0x7c, 0x9e, 0x92, 0xb6, 0x92, 0xcf, 0x27, 0xed, 0x73, 0xa7,
+    0xd4, 0xc3, 0x53, 0xc7, 0x43, 0x4f, 0x20, 0x04, 0x33, 0xff, 0xfc, 0xe1,
+    0xe6, 0x6f, 0xe1, 0xae, 0x02, 0xb5, 0xaa, 0xed, 0x8e, 0x9f, 0xd9, 0x98,
+    0xa2, 0x94, 0xd3, 0xa1, 0x44, 0x4b, 0xf9, 0x96, 0x7d, 0x79, 0x3b, 0x81,
+    0x3a, 0x7f, 0xfb, 0x5c, 0x4d, 0x7b, 0x98, 0x14, 0xd6, 0x09, 0xd3, 0xb8,
+    0xe3, 0x87, 0xeb, 0xf9, 0x44, 0xea, 0xab, 0x1a, 0x24, 0xc9, 0xca, 0x93,
+    0x47, 0x45, 0x8f, 0x11, 0x51, 0x3c, 0xfa, 0xca, 0xc6, 0xfb, 0x56, 0xaf,
+    0x93, 0xa7, 0xf6, 0x6f, 0xef, 0x53, 0x74, 0x74, 0x39, 0xf8, 0x74, 0xf6,
+    0x1a, 0x99, 0x5f, 0x5d, 0x97, 0x09, 0x49, 0xf8, 0x20, 0xbe, 0x74, 0x0b,
+    0xf3, 0xa7, 0x69, 0x02, 0x74, 0xfc, 0x2f, 0xba, 0xeb, 0xc7, 0x4f, 0xf3,
+    0xdb, 0xdf, 0xf3, 0xae, 0xc9, 0xd3, 0xfd, 0xbd, 0x93, 0xba, 0x61, 0xe8,
+    0xe9, 0xb8, 0x8c, 0x22, 0xeb, 0xa3, 0x6b, 0x2c, 0xf1, 0xd4, 0xf7, 0x91,
+    0x74, 0x74, 0xfe, 0x4e, 0x69, 0xfc, 0xe1, 0x3a, 0x30, 0xf4, 0x7c, 0x41,
+    0x3f, 0xcf, 0xcf, 0x26, 0xcb, 0x7b, 0x1d, 0x3f, 0xfe, 0xab, 0x75, 0xf8,
+    0x39, 0xec, 0xb9, 0x96, 0x59, 0x2a, 0x1a, 0x8b, 0x0d, 0x10, 0xf8, 0xe2,
+    0x7e, 0xb5, 0xbf, 0xb0, 0xb9, 0xd3, 0xfe, 0xaf, 0x3f, 0x75, 0xc7, 0x1f,
+    0x1d, 0x3e, 0xc6, 0xa5, 0x5e, 0x3a, 0x5f, 0x89, 0xf1, 0xe8, 0xf2, 0x7f,
+    0xfe, 0xbc, 0x9c, 0x17, 0x6f, 0x7b, 0xfe, 0xe9, 0xda, 0xd1, 0xd3, 0xca,
+    0x9f, 0x9a, 0x3a, 0x1d, 0x10, 0x18, 0xbb, 0x3e, 0xa6, 0xfd, 0xc6, 0x0e,
+    0x9f, 0xf9, 0x9a, 0x1d, 0xb9, 0x4b, 0x4d, 0x21, 0xd3, 0x99, 0x65, 0x92,
+    0xa7, 0xb6, 0x5a, 0x68, 0xab, 0x8b, 0xf9, 0x9c, 0x27, 0x4b, 0xb4, 0x78,
+    0xe2, 0x65, 0x3f, 0x9a, 0xfd, 0xd9, 0xfb, 0xb1, 0xd3, 0xf6, 0xb4, 0x98,
+    0x20, 0x3a, 0x77, 0x71, 0x5c, 0xe9, 0xff, 0x3b, 0x3f, 0x76, 0xd6, 0x2d,
+    0xd5, 0xce, 0x8e, 0xa2, 0x35, 0x65, 0x7e, 0x1e, 0x87, 0x47, 0x8e, 0x43,
+    0x06, 0x7c, 0x9e, 0xdb, 0x19, 0x3a, 0x7f, 0x9e, 0xdc, 0x1f, 0xfc, 0xfa,
+    0x3a, 0x7f, 0xfd, 0xee, 0x63, 0x7e, 0x5b, 0x89, 0xed, 0xec, 0x9d, 0x3a,
+    0x3a, 0x8b, 0x85, 0x94, 0x09, 0xc4, 0xff, 0x2d, 0xfb, 0x7b, 0x3a, 0xec,
+    0x1d, 0x3f, 0xf3, 0xf6, 0xcb, 0x7d, 0xf5, 0x97, 0xb0, 0xe9, 0xfe, 0xca,
+    0x07, 0xcc, 0x0d, 0x34, 0xe9, 0xfe, 0xf8, 0x3f, 0x35, 0xb5, 0x57, 0x0e,
+    0x9f, 0xfd, 0x5b, 0x71, 0x1c, 0x71, 0x84, 0xea, 0x1d, 0x18, 0x9b, 0x48,
+    0x0b, 0xf4, 0x75, 0xe4, 0x5f, 0xce, 0x19, 0x3c, 0x9f, 0x0e, 0x72, 0xbc,
+    0x74, 0xff, 0x9a, 0xe3, 0xb7, 0xde, 0x8f, 0xed, 0x3a, 0x15, 0xcf, 0x99,
+    0x82, 0x59, 0xef, 0x6d, 0x81, 0x3a, 0x7f, 0x91, 0x4f, 0xbd, 0x02, 0xd3,
+    0x47, 0x43, 0x07, 0xbb, 0x7e, 0x45, 0x39, 0x96, 0x59, 0x3a, 0x7f, 0xfd,
+    0x8b, 0xf0, 0xb8, 0x30, 0x3a, 0xc5, 0xbd, 0x8a, 0xb8, 0xbf, 0x9f, 0xdd,
+    0x7f, 0x25, 0x90, 0x27, 0x4b, 0xa7, 0x42, 0xb2, 0x78, 0x3f, 0x4c, 0x63,
+    0x13, 0x94, 0x48, 0x41, 0xf1, 0x17, 0x50, 0xa3, 0x9d, 0xe6, 0xf0, 0xe9,
+    0x21, 0xd3, 0xf7, 0x1f, 0xe5, 0x93, 0x63, 0xa7, 0xee, 0xd7, 0x45, 0xda,
+    0x74, 0xff, 0xf5, 0x7b, 0x99, 0x7b, 0x89, 0xf3, 0x5a, 0x45, 0x9d, 0x3f,
+    0xe4, 0x6a, 0x77, 0x77, 0x17, 0xd1, 0xd0, 0xad, 0xd1, 0xee, 0x10, 0xfe,
+    0x97, 0x89, 0x5f, 0x94, 0xa6, 0x6d, 0xd7, 0xc3, 0x3e, 0x02, 0xfb, 0x69,
+    0x77, 0x66, 0xc2, 0xe7, 0x23, 0xc4, 0x50, 0xda, 0xd0, 0xf0, 0xde, 0x34,
+    0xa4, 0x30, 0x62, 0x12, 0x1d, 0x85, 0x42, 0xc8, 0x78, 0x53, 0x50, 0xa9,
+    0x18, 0xc5, 0xf5, 0x29, 0x1f, 0xd2, 0x94, 0xef, 0xd1, 0xbe, 0xc6, 0x27,
+    0x3f, 0xfb, 0xb8, 0xc8, 0x79, 0x8c, 0x0e, 0x75, 0xa7, 0x4e, 0xee, 0x2b,
+    0x9d, 0x3f, 0xe7, 0x67, 0xee, 0xda, 0xc5, 0xba, 0xb9, 0xd1, 0xd4, 0x56,
+    0x2d, 0x2b, 0xc3, 0xd3, 0xff, 0xd4, 0xb7, 0xed, 0xbb, 0xfa, 0x9d, 0xfe,
+    0xb4, 0x74, 0x62, 0x20, 0xbf, 0x30, 0x9f, 0xdd, 0xb7, 0xf4, 0x15, 0xb9,
+    0xd3, 0xff, 0x3f, 0x7e, 0xf9, 0x3d, 0xcc, 0x0a, 0x1d, 0x3f, 0xee, 0x0b,
+    0xed, 0xf7, 0x9c, 0xa5, 0x73, 0xa1, 0xd1, 0x75, 0xb1, 0x9e, 0x22, 0x4f,
+    0xd5, 0x6b, 0x99, 0x65, 0x93, 0xa7, 0xe7, 0xed, 0x35, 0x38, 0x74, 0xfb,
+    0x17, 0xca, 0x09, 0xd2, 0xb9, 0xdb, 0x7e, 0x3c, 0x86, 0x0a, 0x85, 0xf6,
+    0x95, 0x33, 0xd8, 0x50, 0x55, 0x3e, 0x84, 0x65, 0x45, 0xea, 0x1b, 0xb7,
+    0x8b, 0xd9, 0x31, 0x54, 0x57, 0x0d, 0x74, 0x73, 0x01, 0x9c, 0x30, 0xde,
+    0x31, 0xbe, 0x94, 0x2e, 0x11, 0x5c, 0x86, 0x58, 0x21, 0x4d, 0xa9, 0x48,
+    0xbe, 0x87, 0xdf, 0xf5, 0xc0, 0xf4, 0xff, 0xfa, 0xef, 0xaf, 0xb6, 0x79,
+    0xc5, 0x01, 0x9b, 0xf8, 0xe9, 0xfd, 0x76, 0x76, 0xd5, 0x56, 0x34, 0x46,
+    0xb3, 0xee, 0xda, 0xaa, 0xc6, 0x8a, 0x96, 0x6a, 0xb1, 0xa2, 0x1a, 0x95,
+    0xd8, 0x7a, 0xb4, 0x67, 0x3e, 0xed, 0xaa, 0xac, 0x68, 0x8f, 0xa7, 0xff,
+    0x86, 0xbc, 0xd7, 0x53, 0xe3, 0xfb, 0x4e, 0x03, 0xa7, 0x53, 0x6e, 0xc4,
+    0x41, 0xfd, 0x33, 0x9f, 0xfc, 0xbc, 0xbb, 0xeb, 0xf7, 0x07, 0xd9, 0xc3,
+    0xa2, 0xe4, 0x40, 0x39, 0xb4, 0xff, 0xff, 0x37, 0xfe, 0xa9, 0x5a, 0xc0,
+    0xbe, 0xfa, 0xfb, 0xe5, 0x11, 0x43, 0xa7, 0xef, 0xf7, 0xdd, 0xb9, 0xe3,
+    0xa7, 0xdd, 0xb5, 0x55, 0x8d, 0x16, 0x3c, 0xd5, 0xa3, 0xa7, 0xed, 0xbe,
+    0xf7, 0xb9, 0xd3, 0xa1, 0xa7, 0x8b, 0x42, 0xb3, 0xfc, 0x34, 0xa7, 0x11,
+    0xc7, 0x63, 0xa7, 0xec, 0x4f, 0x79, 0x3c, 0x74, 0xfb, 0x3b, 0x98, 0xc1,
+    0xd2, 0xb9, 0xd3, 0xbe, 0xd9, 0xb7, 0x0c, 0x11, 0xe1, 0x82, 0x1d, 0x1b,
+    0xfd, 0x2b, 0x9c, 0xac, 0x56, 0xa1, 0xd3, 0xf5, 0xf2, 0x39, 0xca, 0xf1,
+    0xd3, 0xfc, 0x34, 0x0d, 0x57, 0xbd, 0x47, 0x4f, 0x01, 0x69, 0xd3, 0xa7,
+    0xff, 0xf9, 0xfa, 0x38, 0x1c, 0xe7, 0x12, 0xdc, 0x4f, 0x6a, 0xb7, 0x3a,
+    0x11, 0x10, 0xbc, 0x21, 0x9f, 0x9f, 0xa0, 0xbf, 0xff, 0xc7, 0x4f, 0xf3,
+    0x8f, 0xaf, 0xba, 0xf7, 0xee, 0x74, 0xff, 0xe7, 0xe3, 0xae, 0xdc, 0x4f,
+    0x66, 0x2c, 0xe9, 0xd5, 0x56, 0x34, 0x5a, 0x13, 0xfe, 0xa6, 0x55, 0x5a,
+    0xbb, 0xb6, 0x32, 0x74, 0xfc, 0x07, 0x17, 0xf6, 0x8e, 0x8b, 0x22, 0x53,
+    0xa4, 0xe0, 0x42, 0x9f, 0xff, 0xfe, 0x4e, 0xf2, 0x85, 0x1f, 0xc9, 0xc7,
+    0xd7, 0x33, 0x5d, 0xcb, 0x67, 0x8e, 0x86, 0xa7, 0xe0, 0x13, 0x1b, 0x1e,
+    0x76, 0x1b, 0x7c, 0x30, 0x9f, 0xfd, 0x55, 0xbd, 0xee, 0x2b, 0xa7, 0x85,
+    0xd6, 0x74, 0xff, 0xfd, 0xc4, 0xf6, 0xab, 0x7d, 0x6b, 0x38, 0x9a, 0xff,
+    0x63, 0xa7, 0xff, 0xbf, 0xef, 0x5c, 0x71, 0x44, 0xe7, 0x33, 0xe9, 0xd2,
+    0xbe, 0x8e, 0x97, 0x7a, 0x7c, 0xdf, 0xa8, 0xcf, 0x86, 0xd5, 0xa4, 0x3a,
+    0x7f, 0xfe, 0xe8, 0xbb, 0xef, 0xf3, 0x5e, 0x17, 0x0f, 0x1f, 0xc7, 0x4c,
+    0x9c, 0x3a, 0x79, 0xa3, 0x5f, 0x4e, 0x9f, 0xe4, 0x0d, 0x03, 0xbd, 0xa0,
+    0x1d, 0x0e, 0x8e, 0xec, 0x25, 0x57, 0x5b, 0xa1, 0x5f, 0xc8, 0xa7, 0x52,
+    0xba, 0x1d, 0x3f, 0xef, 0xbe, 0x51, 0x14, 0x7c, 0x17, 0x3a, 0x7d, 0xf7,
+    0xc2, 0xe0, 0x3a, 0x37, 0x44, 0x27, 0x47, 0x6f, 0x1f, 0xcf, 0x9f, 0xd9,
+    0xc7, 0x3a, 0x7f, 0xff, 0xf7, 0x10, 0x38, 0x9b, 0x71, 0xdf, 0xe6, 0x6e,
+    0xdd, 0x27, 0xa8, 0x70, 0xe9, 0xff, 0xec, 0xf6, 0xb1, 0x8e, 0x3d, 0xec,
+    0xe7, 0x1c, 0xe9, 0xfe, 0x17, 0x76, 0x32, 0xf2, 0x74, 0xe8, 0xd9, 0x32,
+    0x3b, 0x12, 0x8b, 0xb7, 0x94, 0x21, 0xd3, 0x94, 0xc8, 0xd5, 0xa7, 0xff,
+    0xfb, 0xdc, 0x71, 0xc0, 0x6b, 0x03, 0xc7, 0xd9, 0x7f, 0x88, 0x4e, 0x9f,
+    0xff, 0x9d, 0x8c, 0x0f, 0x1e, 0xf7, 0x33, 0xc2, 0xee, 0xb3, 0xa7, 0xed,
+    0xf5, 0xf7, 0x6f, 0xc4, 0xe9, 0xfe, 0x7b, 0x71, 0x18, 0xaa, 0xd8, 0xe8,
+    0x5a, 0x31, 0x29, 0x68, 0x06, 0x53, 0xf9, 0xaf, 0xdd, 0x9f, 0xbb, 0x1d,
+    0x3f, 0xc9, 0xf8, 0xb7, 0xaf, 0x81, 0x3a, 0x7f, 0xff, 0xb9, 0x8d, 0xb7,
+    0x13, 0x8f, 0x9d, 0x6f, 0x85, 0xd7, 0xa3, 0xa3, 0x48, 0x9b, 0xf1, 0xbc,
+    0x3a, 0x3c, 0xb2, 0x19, 0xf3, 0xf7, 0x5f, 0xdb, 0x63, 0x27, 0x4f, 0xbd,
+    0xca, 0x15, 0x0e, 0x9f, 0xe1, 0xff, 0x60, 0xf3, 0x05, 0xce, 0x96, 0x61,
+    0xef, 0xd8, 0x9e, 0x7f, 0xf7, 0x41, 0x60, 0x0e, 0x7b, 0x55, 0x42, 0x74,
+    0x22, 0x3e, 0x86, 0x11, 0xbf, 0x93, 0x4f, 0xec, 0xe3, 0x09, 0xc4, 0x59,
+    0xd3, 0xf9, 0xb9, 0xdd, 0x0b, 0xec, 0x74, 0xec, 0xe5, 0x1d, 0x3e, 0x60,
+    0x3f, 0xfe, 0x27, 0x40, 0x4f, 0x12, 0x86, 0xa7, 0xf6, 0x33, 0x96, 0xb6,
+    0x32, 0x74, 0xe5, 0x1b, 0xf9, 0xd3, 0xfe, 0xdd, 0x9f, 0xe8, 0x79, 0x94,
+    0xc1, 0xd0, 0x87, 0xbd, 0x43, 0xd1, 0x88, 0xb1, 0x18, 0x48, 0xc6, 0x27,
+    0x41, 0xb9, 0x95, 0x3b, 0x6a, 0x1a, 0x53, 0xd9, 0xca, 0xf1, 0xd3, 0xf2,
+    0x0f, 0xed, 0xcd, 0x1d, 0x3f, 0xec, 0xf3, 0xee, 0x0a, 0xe7, 0x10, 0xe9,
+    0x2c, 0xe9, 0xf9, 0x07, 0xf6, 0xe6, 0xbe, 0x1e, 0x6d, 0xe3, 0xd8, 0x51,
+    0x18, 0x3e, 0x79, 0x95, 0xd7, 0xc3, 0x3a, 0xa2, 0xfb, 0x23, 0x73, 0x00,
+    0xc2, 0xef, 0x25, 0x09, 0x28, 0xa1, 0x64, 0xd4, 0x86, 0x1a, 0xe3, 0x17,
+    0xe4, 0xa6, 0x3a, 0x28, 0x04, 0x65, 0x43, 0x19, 0x0e, 0xa3, 0x20, 0xf4,
+    0x7a, 0x97, 0xe8, 0x5f, 0x61, 0xc3, 0x3f, 0x2a, 0x40, 0x8b, 0xb0, 0x74,
+    0xe7, 0xa1, 0x3a, 0x7b, 0x39, 0x5e, 0x3a, 0x57, 0xce, 0x1f, 0x3f, 0x0b,
+    0x84, 0x66, 0x72, 0xf4, 0xa1, 0xd3, 0xd9, 0xa0, 0x21, 0xd3, 0xee, 0xda,
+    0xaa, 0xc6, 0x8b, 0x5a, 0x7e, 0xc5, 0x5a, 0xa1, 0xb1, 0xd3, 0xba, 0xeb,
+    0x3a, 0x7e, 0xe6, 0x69, 0xf6, 0x54, 0x74, 0xff, 0x36, 0xec, 0xed, 0xaa,
+    0xac, 0x68, 0xa0, 0xe3, 0x0f, 0xd2, 0x8b, 0xe7, 0xb1, 0x87, 0xf1, 0xd3,
+    0xfc, 0xed, 0x7e, 0xec, 0xfd, 0xd8, 0xe9, 0x5d, 0x7d, 0xa7, 0xbc, 0xe7,
+    0x0d, 0x1d, 0xc2, 0x06, 0x0c, 0xfa, 0x5a, 0xb8, 0x47, 0xf0, 0x80, 0x48,
+    0x67, 0xff, 0x5c, 0xba, 0x6d, 0xd9, 0xdb, 0x55, 0x58, 0xd1, 0x45, 0xcf,
+    0xeb, 0xb3, 0xb6, 0xaa, 0xb1, 0xa2, 0xea, 0x87, 0x6d, 0xea, 0xda, 0xaf,
+    0x68, 0x4a, 0x24, 0x65, 0x4b, 0x8f, 0x87, 0x94, 0xf1, 0x50, 0x4b, 0x7c,
+    0xd4, 0x23, 0xbc, 0xaf, 0x3e, 0xed, 0xaa, 0xac, 0x68, 0x88, 0x67, 0x73,
+    0x02, 0x74, 0xf6, 0x5e, 0x4e, 0x9d, 0x2b, 0xb0, 0xfc, 0x37, 0x33, 0x57,
+    0x1b, 0x9f, 0xd7, 0x67, 0x6d, 0x55, 0x63, 0x44, 0x6d, 0x3f, 0xae, 0xce,
+    0xda, 0xaa, 0xc6, 0x8a, 0x6e, 0x7d, 0xdb, 0x55, 0x58, 0xd1, 0x50, 0x4e,
+    0xcd, 0xd9, 0x3a, 0x57, 0x61, 0xe8, 0x70, 0xce, 0x7f, 0x5d, 0x9d, 0xb5,
+    0x55, 0x8d, 0x15, 0x34, 0xfb, 0xb6, 0xaa, 0xb1, 0xa2, 0xb0, 0x9f, 0x23,
+    0x21, 0xff, 0xa7, 0x4f, 0xf3, 0x6e, 0xce, 0xda, 0xaa, 0xc6, 0x88, 0xfe,
+    0x76, 0x3e, 0xc7, 0x4f, 0xec, 0xdd, 0xb4, 0xd4, 0x13, 0xa6, 0xaf, 0x1d,
+    0x2b, 0xb1, 0x30, 0x2b, 0x19, 0xd1, 0x48, 0xa2, 0xf8, 0x6e, 0xfc, 0xc6,
+    0x7f, 0xf5, 0xcb, 0xa6, 0xdd, 0x9d, 0xb5, 0x55, 0x8d, 0x13, 0x7c, 0xff,
+    0xcb, 0xa6, 0xdd, 0x9d, 0xb5, 0x55, 0x8d, 0x13, 0xf4, 0xc3, 0x63, 0xa7,
+    0xf5, 0xb8, 0x9e, 0xcc, 0x59, 0xd3, 0x5e, 0xb1, 0xe3, 0x02, 0x87, 0x3e,
+    0xbd, 0x0a, 0xf8, 0xc6, 0x7f, 0x2b, 0x05, 0x64, 0x73, 0x67, 0xdc, 0xe9,
+    0xf2, 0xb5, 0x7c, 0xdf, 0xe6, 0xe7, 0x4d, 0x7a, 0xc7, 0x8c, 0x06, 0x5c,
+    0x3a, 0x15, 0xa4, 0x54, 0x2b, 0x27, 0xde, 0x35, 0xfc, 0x96, 0x7f, 0x95,
+    0x87, 0x2b, 0xde, 0xaa, 0x64, 0xe9, 0xff, 0xfc, 0xad, 0x5f, 0x3a, 0xeb,
+    0xa7, 0xb9, 0x81, 0x4d, 0x60, 0x80, 0xe9, 0xf7, 0x12, 0x80, 0xac, 0x0e,
+    0x85, 0x65, 0x12, 0x9e, 0x68, 0x9f, 0x5f, 0x6a, 0xdc, 0x0a, 0x39, 0xd3,
+    0xff, 0xce, 0xee, 0xee, 0xee, 0xee, 0xfb, 0xe8, 0xe9, 0xf7, 0x53, 0x6a,
+    0x59, 0x53, 0x32, 0xc9, 0x51, 0x86, 0xfd, 0x92, 0x79, 0x7e, 0x55, 0xc6,
+    0x86, 0x1d, 0x19, 0x7a, 0x85, 0x4c, 0xfa, 0xa8, 0x5d, 0x51, 0xd3, 0xff,
+    0x71, 0xd3, 0xbf, 0x8f, 0xfe, 0xff, 0xc7, 0x4f, 0x74, 0x51, 0xce, 0x9f,
+    0x9b, 0xaf, 0x60, 0xa8, 0x74, 0xe6, 0x69, 0x93, 0xa7, 0xff, 0x7b, 0xb5,
+    0xb0, 0x78, 0xfa, 0xf7, 0xfc, 0x3a, 0x6c, 0x5f, 0x0f, 0xa7, 0x43, 0xb3,
+    0xea, 0xb7, 0x13, 0xa7, 0x4f, 0xff, 0xfe, 0x1a, 0x51, 0x3a, 0xed, 0xf9,
+    0xc4, 0x58, 0x5f, 0xe5, 0xff, 0xfc, 0x4e, 0x9d, 0x3d, 0x4d, 0x4d, 0xce,
+    0x80, 0xa3, 0xcb, 0xa5, 0xbc, 0x26, 0x17, 0xe9, 0x39, 0xd3, 0xff, 0xcf,
+    0xbb, 0x68, 0x41, 0xf0, 0x09, 0xd4, 0x50, 0xe8, 0xbf, 0x3e, 0x05, 0x41,
+    0xf3, 0xdb, 0x2d, 0x1a, 0x74, 0xfb, 0x43, 0xfd, 0x34, 0xe9, 0xfd, 0xc7,
+    0x5d, 0xc0, 0x03, 0x9d, 0x0e, 0x7f, 0x98, 0x44, 0x84, 0xf3, 0xf3, 0x09,
+    0xcf, 0x65, 0x8e, 0x8e, 0x9e, 0xcd, 0x16, 0x4f, 0xf6, 0xe1, 0xfa, 0xea,
+    0xfc, 0xff, 0x47, 0x4f, 0xff, 0x83, 0xc7, 0xea, 0x01, 0xfe, 0xbb, 0x02,
+    0xeb, 0x3a, 0x7f, 0x28, 0xe3, 0xed, 0x57, 0x0e, 0x84, 0x44, 0x3d, 0x2a,
+    0xc3, 0xa3, 0xa0, 0x61, 0x8f, 0x3b, 0x31, 0x83, 0xa4, 0xae, 0x74, 0xef,
+    0x37, 0x0e, 0x9b, 0x58, 0x74, 0x21, 0xe1, 0xd0, 0x98, 0x06, 0xe7, 0xfe,
+    0x0b, 0xfa, 0xb5, 0x9c, 0xe2, 0x2c, 0xe9, 0xde, 0x46, 0x0e, 0x87, 0x3d,
+    0xed, 0x21, 0x4f, 0x9d, 0x5d, 0x19, 0xb1, 0xd0, 0xeb, 0xc6, 0xbb, 0x13,
+    0x84, 0x9b, 0x11, 0xb7, 0x1f, 0x48, 0xe2, 0x18, 0x84, 0xe7, 0x61, 0xf8,
+    0xb8, 0xc2, 0x40, 0x4c, 0x2b, 0xde, 0x84, 0x5f, 0xd2, 0x19, 0xcc, 0x7d,
+    0x59, 0xd3, 0xfd, 0x9e, 0xd6, 0x7b, 0x98, 0x03, 0xa2, 0x8f, 0x58, 0x47,
+    0xe6, 0xa1, 0x3a, 0x3a, 0x6d, 0x16, 0x41, 0x3f, 0x67, 0x9c, 0x50, 0x07,
+    0x4f, 0xee, 0xe7, 0x76, 0x7f, 0x68, 0xe9, 0xcc, 0xb2, 0xc9, 0xd3, 0xdb,
+    0x0a, 0x39, 0x57, 0x17, 0xf3, 0x6e, 0xd3, 0xa7, 0xf2, 0x8f, 0xed, 0x72,
+    0xbf, 0x3a, 0x7c, 0x9b, 0x66, 0xfe, 0x3a, 0x64, 0xb1, 0xd2, 0xdd, 0xd1,
+    0x10, 0xa0, 0xba, 0xcd, 0x3c, 0x51, 0x0e, 0x9c, 0xc8, 0x48, 0x50, 0xab,
+    0x8a, 0x5f, 0xc2, 0xe2, 0x7f, 0xda, 0xa5, 0x38, 0x8e, 0x3f, 0xb9, 0xd3,
+    0xea, 0xef, 0xf5, 0xa3, 0xa6, 0x6f, 0x8e, 0x9e, 0x61, 0xfd, 0x47, 0x4f,
+    0xb6, 0xfc, 0x18, 0x36, 0x36, 0xff, 0x8b, 0x4f, 0xfc, 0xfc, 0xfa, 0x1f,
+    0x26, 0x30, 0xeb, 0x3a, 0x79, 0xfd, 0xfa, 0xce, 0x9b, 0x56, 0x34, 0x41,
+    0xd0, 0xb3, 0xc5, 0xf1, 0x14, 0xff, 0xf9, 0x7a, 0xa6, 0xf1, 0x33, 0xda,
+    0xee, 0x07, 0x0e, 0x9f, 0xe7, 0xf0, 0xe5, 0xe1, 0xcd, 0x1d, 0x0e, 0x8a,
+    0xcc, 0x22, 0xd2, 0x9c, 0xfd, 0x5c, 0x75, 0x7f, 0xda, 0x74, 0x59, 0x51,
+    0x97, 0x57, 0x96, 0x81, 0xe8, 0xcd, 0xaf, 0x17, 0x4f, 0xe7, 0x68, 0xe6,
+    0xfe, 0xc3, 0xa7, 0xf5, 0x0f, 0x9b, 0x9d, 0xc3, 0xa6, 0xe8, 0x4e, 0x99,
+    0x96, 0x4e, 0x86, 0x9a, 0xe6, 0x45, 0xa7, 0xb4, 0xe9, 0x78, 0xab, 0x8d,
+    0x14, 0xfb, 0x5f, 0x42, 0x0d, 0x1d, 0x08, 0x7b, 0xbf, 0x4c, 0xe7, 0x32,
+    0xcb, 0x25, 0x41, 0x57, 0x17, 0xf3, 0xc8, 0xca, 0x30, 0x54, 0x58, 0xde,
+    0x20, 0xd4, 0xfb, 0x3a, 0xf7, 0xb0, 0xe8, 0xc5, 0xc9, 0x64, 0x94, 0xdf,
+    0xd5, 0x45, 0x98, 0xf2, 0x1b, 0xa2, 0xfd, 0xa2, 0x09, 0xfc, 0x3b, 0xfb,
+    0xef, 0x28, 0x07, 0x4e, 0x14, 0xd1, 0xd3, 0xc1, 0xa1, 0x01, 0xd3, 0xff,
+    0x38, 0x80, 0x5f, 0x76, 0x1c, 0x40, 0x74, 0x62, 0x2c, 0x50, 0xd4, 0x03,
+    0x5a, 0x20, 0x9f, 0xc0, 0xd7, 0xdd, 0xb6, 0xad, 0xce, 0x9f, 0x3e, 0x77,
+    0x88, 0x74, 0xff, 0xe6, 0x41, 0xcc, 0xcd, 0x93, 0x2f, 0x3e, 0xe7, 0x4e,
+    0xc5, 0xab, 0x9d, 0x3f, 0xb3, 0x43, 0x9e, 0xe2, 0x1d, 0x01, 0x3c, 0xe1,
+    0x1e, 0x8c, 0x4c, 0x61, 0x83, 0x8e, 0x12, 0xde, 0x84, 0xd4, 0xfd, 0xec,
+    0x60, 0x5d, 0x67, 0x88, 0x0a, 0x7d, 0x42, 0x1e, 0x39, 0xa2, 0x02, 0xb8,
+    0xdc, 0xcf, 0xfc, 0x9b, 0xe8, 0x38, 0x2e, 0x3f, 0xb9, 0xd3, 0xff, 0x7f,
+    0x65, 0x3b, 0x9b, 0xe8, 0x15, 0xe3, 0xa7, 0xce, 0xda, 0xdd, 0x93, 0xa3,
+    0x11, 0x62, 0x88, 0x5d, 0x47, 0x9f, 0xe7, 0xee, 0xdf, 0x31, 0x84, 0x59,
+    0xd3, 0xcb, 0x7c, 0x59, 0xd3, 0xfe, 0xc5, 0xbd, 0x93, 0xdd, 0xfd, 0x67,
+    0x4e, 0x4d, 0xf4, 0x74, 0x9d, 0xa7, 0xb4, 0x03, 0xe9, 0xfd, 0xd6, 0x34,
+    0x83, 0xe4, 0x3a, 0x7b, 0x70, 0x75, 0xca, 0x99, 0x96, 0x4a, 0x87, 0x37,
+    0x4c, 0x91, 0x4f, 0xd5, 0xd6, 0xb4, 0x50, 0xab, 0x8d, 0x0c, 0x3a, 0xe4,
+    0xc6, 0x46, 0xa6, 0x8f, 0xdd, 0x87, 0xa7, 0x0b, 0xa8, 0xec, 0x5e, 0xbc,
+    0x4f, 0xfc, 0x23, 0x67, 0x6d, 0x4b, 0x3a, 0x7b, 0xdf, 0xd7, 0xd3, 0x44,
+    0x0f, 0x14, 0x79, 0xbf, 0x8e, 0x4e, 0x57, 0x40, 0x1d, 0x33, 0xfe, 0x74,
+    0xfb, 0xf1, 0x07, 0xd6, 0x9d, 0x3f, 0xfc, 0x39, 0xaf, 0x9f, 0x78, 0xe0,
+    0x5d, 0x37, 0xe6, 0x1e, 0x06, 0x85, 0xa3, 0xf4, 0x64, 0xde, 0x5e, 0x9f,
+    0xf7, 0x3f, 0xd9, 0xfe, 0x3f, 0x9c, 0x27, 0x4e, 0xae, 0xec, 0x74, 0xcc,
+    0xb2, 0x74, 0xfe, 0xea, 0x65, 0xef, 0xad, 0xba, 0xc6, 0xd1, 0x91, 0xc8,
+    0x0a, 0x31, 0x3a, 0xeb, 0x3f, 0xf0, 0xe2, 0x9c, 0xa6, 0xfd, 0xad, 0xdc,
+    0xe8, 0x73, 0xe8, 0xc2, 0x39, 0xff, 0x96, 0xba, 0x6e, 0x76, 0xd5, 0x56,
+    0x34, 0x43, 0x13, 0xff, 0xff, 0xab, 0x58, 0x39, 0x6e, 0x3e, 0xed, 0xbf,
+    0xce, 0x59, 0x30, 0x69, 0x43, 0xa3, 0x11, 0x8d, 0xfa, 0x7c, 0x22, 0xa5,
+    0xbe, 0x46, 0xa4, 0x30, 0xe6, 0x9f, 0xcb, 0xe5, 0x6c, 0x2e, 0xd3, 0xa7,
+    0xf9, 0xf7, 0x6f, 0x2a, 0x85, 0xce, 0x9f, 0x76, 0xd5, 0x56, 0x34, 0x41,
+    0x53, 0xb8, 0xeb, 0x3a, 0x30, 0xf3, 0x90, 0xce, 0x7b, 0xda, 0x70, 0x15,
+    0x3a, 0xbb, 0xb1, 0x53, 0xdf, 0x8d, 0x28, 0x54, 0xfe, 0x4d, 0xb3, 0xda,
+    0x70, 0x15, 0x05, 0x4f, 0xd9, 0x67, 0xe3, 0xac, 0xa9, 0x99, 0x64, 0xa9,
+    0xf8, 0x5c, 0x76, 0x4e, 0x95, 0x18, 0x98, 0x4d, 0x88, 0x56, 0x39, 0xc2,
+    0x20, 0x19, 0x08, 0x53, 0x25, 0x7f, 0x46, 0x26, 0x4e, 0x95, 0x71, 0xf9,
+    0xc3, 0x53, 0xc3, 0xe4, 0x73, 0x90, 0xea, 0xa8, 0xf8, 0x65, 0x52, 0x91,
+    0xe7, 0xf7, 0x30, 0x74, 0x83, 0x87, 0x4f, 0xea, 0x1c, 0xd7, 0x5f, 0x47,
+    0x4f, 0xc1, 0xc1, 0xaf, 0x68, 0xe9, 0x3b, 0x4f, 0x6f, 0x46, 0x13, 0xee,
+    0xee, 0xdc, 0xf1, 0xd3, 0xff, 0xfd, 0xc4, 0xee, 0x06, 0x97, 0x83, 0xe1,
+    0x76, 0x73, 0xda, 0x3a, 0x4e, 0x74, 0xfb, 0x8f, 0x78, 0x2f, 0x63, 0xf2,
+    0x03, 0x1c, 0x75, 0x1b, 0x5e, 0x84, 0xd4, 0xff, 0x3e, 0xed, 0xbf, 0x7b,
+    0x62, 0xce, 0x9f, 0xff, 0x59, 0x4a, 0xd6, 0x75, 0xa9, 0xca, 0x1d, 0xda,
+    0x74, 0xff, 0xac, 0xfe, 0xd6, 0x79, 0x37, 0x64, 0xe9, 0x56, 0x22, 0x51,
+    0x45, 0x58, 0x74, 0xc7, 0xf8, 0x50, 0x30, 0xcf, 0x9f, 0xff, 0x55, 0x36,
+    0xb9, 0xf3, 0x36, 0xff, 0xdf, 0xd7, 0xd3, 0x45, 0xf7, 0x3f, 0xed, 0x20,
+    0xee, 0xde, 0xfe, 0xfa, 0x3a, 0x18, 0x45, 0x37, 0x99, 0xe5, 0x63, 0xa7,
+    0xff, 0xf0, 0x13, 0xaa, 0x71, 0xd6, 0xc3, 0x50, 0x78, 0xfd, 0x73, 0xa5,
+    0xec, 0x3f, 0x0d, 0x08, 0x4f, 0x78, 0x71, 0xa7, 0x43, 0x9e, 0x3a, 0x13,
+    0xcf, 0xf8, 0x51, 0xbe, 0xe6, 0x75, 0x34, 0x74, 0xfe, 0xe3, 0xb4, 0x73,
+    0x36, 0x3a, 0x7f, 0x78, 0x1f, 0x45, 0xbc, 0xc3, 0xc4, 0x03, 0x3a, 0xba,
+    0xd3, 0xc4, 0x03, 0x18, 0x7d, 0x3f, 0xa0, 0xcd, 0x4d, 0x3c, 0x40, 0x33,
+    0xd4, 0x3b, 0xb4, 0xf1, 0x00, 0xcf, 0xe4, 0xb7, 0x30, 0x00, 0x73, 0xc4,
+    0x03, 0x39, 0x04, 0x27, 0x88, 0x06, 0x02, 0x8b, 0x55, 0x91, 0x70, 0xba,
+    0xf1, 0xf4, 0xee, 0xbf, 0x8f, 0x10, 0x0c, 0x1e, 0x20, 0x19, 0x9d, 0x67,
+    0x88, 0x06, 0x02, 0x6e, 0x50, 0x5e, 0x79, 0x16, 0x17, 0x3c, 0x40, 0x33,
+    0xbd, 0x56, 0x3c, 0x40, 0x33, 0xfe, 0x1a, 0x6d, 0xdc, 0x4b, 0x57, 0x4f,
+    0x10, 0x0c, 0xff, 0xd5, 0xef, 0xf6, 0x41, 0xf7, 0x29, 0xa7, 0x88, 0x06,
+    0x6a, 0x09, 0xe2, 0x01, 0x9f, 0xc3, 0x4c, 0xeb, 0x4e, 0x03, 0xc4, 0x03,
+    0x3e, 0x45, 0x28, 0x40, 0x78, 0x80, 0x66, 0x4d, 0x1e, 0x20, 0x18, 0xe9,
+    0xea, 0xf8, 0xce, 0x7d, 0xe1, 0x7d, 0xda, 0x68, 0x80, 0x66, 0x03, 0x9e,
+    0x20, 0x1b, 0x8d, 0xa4, 0xf9, 0x1d, 0x74, 0x13, 0xc4, 0x03, 0x3d, 0xfd,
+    0x0d, 0x8f, 0x10, 0x0c, 0xe7, 0xed, 0x8f, 0x10, 0x0c, 0xff, 0xb3, 0x7d,
+    0x05, 0xf0, 0x41, 0xa3, 0xc4, 0x03, 0x3e, 0xfe, 0x9a, 0xd7, 0x3c, 0x40,
+    0x33, 0xea, 0xb7, 0x1f, 0x73, 0xc4, 0x03, 0x18, 0x8b, 0x2e, 0x25, 0x7e,
+    0x69, 0x37, 0x40, 0x78, 0x80, 0x61, 0xaa, 0xb3, 0x02, 0x45, 0x90, 0x94,
+    0x45, 0x6e, 0x19, 0x80, 0xcb, 0x45, 0xde, 0x86, 0xd7, 0xe6, 0x13, 0xec,
+    0xf6, 0xab, 0x73, 0xc4, 0x03, 0x3f, 0x82, 0xf6, 0x63, 0xaf, 0xe3, 0xc4,
+    0x02, 0x13, 0x69, 0x3b, 0xae, 0xc9, 0xe2, 0x01, 0x8b, 0x1f, 0xcf, 0x54,
+    0x27, 0xf7, 0xf4, 0xd6, 0xbf, 0xd5, 0x9e, 0x20, 0x19, 0xe4, 0x16, 0xe8,
+    0xf1, 0x00, 0xcf, 0xd4, 0xc3, 0x73, 0x76, 0x9e, 0x20, 0x18, 0xc4, 0x66,
+    0x70, 0x88, 0x08, 0x5f, 0x96, 0xcf, 0xf7, 0x1f, 0x57, 0x6b, 0xfe, 0x80,
+    0xf1, 0x00, 0xc9, 0x0f, 0x10, 0x0c, 0xd5, 0xb0, 0x4f, 0x93, 0x89, 0x13,
+    0x74, 0x07, 0x88, 0x06, 0x7d, 0x5e, 0xd2, 0x6e, 0x78, 0x80, 0x67, 0xe4,
+    0x1f, 0xdb, 0x9a, 0x3c, 0x40, 0x30, 0xe8, 0x90, 0x12, 0x3f, 0x1a, 0x40,
+    0x59, 0x1c, 0x59, 0x0d, 0x76, 0x0f, 0xfa, 0xc3, 0xc2, 0x0a, 0x2d, 0x01,
+    0x40, 0xa5, 0x6a, 0x58, 0xef, 0xa5, 0x01, 0x5f, 0xc2, 0x87, 0xec, 0x2f,
+    0xa7, 0x55, 0x58, 0xd1, 0x00, 0xdc, 0x8c, 0x99, 0xe5, 0x15, 0xb8, 0x56,
+    0x74, 0xfc, 0x97, 0x85, 0xc3, 0xc3, 0xa7, 0xfe, 0x68, 0xe5, 0xb8, 0x80,
+    0x07, 0xec, 0x1d, 0x30, 0x1c, 0xa9, 0x28, 0x54, 0xee, 0x3e, 0xc7, 0x4c,
+    0xcb, 0x25, 0x42, 0x1e, 0xd2, 0xb8, 0xab, 0x02, 0x2c, 0x8e, 0x4e, 0x5a,
+    0x68, 0xab, 0x8f, 0x02, 0x72, 0x7f, 0xe3, 0xa7, 0xff, 0x7b, 0x58, 0xa2,
+    0x77, 0xe8, 0x00, 0xfb, 0x9d, 0x1b, 0x33, 0x29, 0x9a, 0x40, 0x13, 0xcb,
+    0x52, 0x91, 0x50, 0xeb, 0xa5, 0x34, 0x5a, 0x08, 0x6f, 0xf8, 0xb7, 0xe8,
+    0xe4, 0xfd, 0xef, 0xb7, 0xaf, 0x3e, 0x8e, 0x9c, 0x3b, 0xb4, 0xf1, 0x80,
+    0x42, 0x1e, 0xe5, 0x19, 0xcf, 0x98, 0x6b, 0xf7, 0x63, 0xa7, 0x9d, 0x47,
+    0x59, 0xd1, 0xd3, 0xca, 0x59, 0x4c, 0xff, 0x9b, 0xaf, 0x83, 0x8b, 0x7e,
+    0xa8, 0x74, 0xfc, 0xd7, 0xe8, 0x3e, 0xac, 0xe9, 0xff, 0xaf, 0x0e, 0x6b,
+    0xd8, 0x2d, 0xcd, 0x1d, 0x3c, 0xb7, 0xff, 0xc7, 0x46, 0x1f, 0x2d, 0x21,
+    0xcd, 0xca, 0xc4, 0x5a, 0x0c, 0x25, 0x27, 0xf9, 0xec, 0xeb, 0x45, 0x81,
+    0x0e, 0x8e, 0x9f, 0x3a, 0xa3, 0x19, 0xfb, 0xeb, 0x3d, 0x4c, 0xe1, 0x53,
+    0xcc, 0x72, 0x98, 0x3a, 0x7d, 0x8c, 0x35, 0xf7, 0x3a, 0x77, 0x11, 0x83,
+    0xa7, 0x0b, 0xb4, 0xa9, 0xff, 0x08, 0x11, 0x52, 0xaf, 0xda, 0xea, 0xe7,
+    0x46, 0x1e, 0xfd, 0x0d, 0x47, 0x51, 0xcc, 0x24, 0x7e, 0x28, 0x54, 0xf7,
+    0x0e, 0xab, 0xd3, 0x08, 0x92, 0x35, 0xbe, 0x12, 0x54, 0x62, 0xb3, 0xf6,
+    0xfa, 0xef, 0x5f, 0xc7, 0x4f, 0xcd, 0xd2, 0x9d, 0xab, 0x1d, 0x38, 0x7d,
+    0xa3, 0xa7, 0xda, 0xfc, 0x7f, 0xb1, 0xd0, 0xe7, 0xe4, 0x85, 0xdf, 0x8d,
+    0xcf, 0xfd, 0xc6, 0x5f, 0xba, 0xc6, 0x6b, 0xaa, 0x1d, 0x35, 0xf5, 0xa3,
+    0xa7, 0xff, 0xde, 0x52, 0xb4, 0xab, 0x8f, 0xd7, 0xb2, 0x0d, 0x8e, 0x86,
+    0xa2, 0xdf, 0xf4, 0x66, 0x46, 0xe7, 0xfd, 0xcc, 0x55, 0x42, 0xa6, 0x6f,
+    0xe3, 0xa7, 0xfc, 0xbc, 0xb7, 0x10, 0x3c, 0xfd, 0x43, 0xa1, 0x44, 0x40,
+    0x01, 0x02, 0x7f, 0x94, 0xaf, 0x8e, 0xb1, 0x45, 0x0e, 0x9f, 0xf5, 0x69,
+    0x6e, 0x9d, 0xea, 0x32, 0x74, 0xb4, 0xa1, 0xfb, 0xf0, 0xea, 0x7f, 0xb3,
+    0xde, 0x45, 0x3d, 0x96, 0x3a, 0x7f, 0x05, 0xf7, 0xd6, 0x6f, 0xe3, 0xa7,
+    0xf9, 0xfc, 0x96, 0x40, 0xbf, 0x8e, 0x96, 0x82, 0x8a, 0x2c, 0x38, 0xe9,
+    0xa4, 0x6e, 0x98, 0x07, 0xa1, 0x97, 0x3f, 0xde, 0x4d, 0x9f, 0x70, 0x75,
+    0xce, 0x9d, 0xaf, 0x61, 0xd3, 0x66, 0xbe, 0x1e, 0xa7, 0xd3, 0x99, 0xfa,
+    0xff, 0x3c, 0x0a, 0xf1, 0xd0, 0xd3, 0xe0, 0xf1, 0x8c, 0x3a, 0xb4, 0xd4,
+    0x85, 0x95, 0x47, 0x37, 0xfc, 0x37, 0xa7, 0xb8, 0x94, 0xd3, 0xa7, 0xfb,
+    0xb8, 0x3f, 0x39, 0x9b, 0xb2, 0x74, 0xff, 0x34, 0x7f, 0x07, 0xcb, 0x2c,
+    0x07, 0x46, 0xc8, 0x97, 0xc2, 0x0d, 0xce, 0xe7, 0xf8, 0x5f, 0x37, 0xf6,
+    0x75, 0xce, 0x87, 0x3e, 0x7a, 0x31, 0x9f, 0x55, 0xe0, 0x85, 0xce, 0x9b,
+    0x5a, 0x3a, 0x73, 0x2c, 0xb2, 0x74, 0xc0, 0xa2, 0xae, 0x2f, 0xe3, 0xa7,
+    0xb5, 0xa3, 0x59, 0xff, 0x66, 0x86, 0x94, 0x60, 0x51, 0x83, 0xa7, 0x50,
+    0x30, 0xa8, 0x6a, 0x3f, 0x17, 0x08, 0x2e, 0x11, 0x5f, 0x9f, 0x4f, 0x83,
+    0xd4, 0xff, 0x63, 0xa7, 0xe1, 0xcd, 0xc1, 0xf5, 0xa7, 0x43, 0x07, 0xb1,
+    0xe2, 0x99, 0xa9, 0x67, 0x4f, 0xf0, 0xe5, 0xec, 0xb9, 0x96, 0x59, 0x2a,
+    0x7f, 0x5f, 0x4f, 0xfd, 0xb8, 0x9d, 0x3a, 0x72, 0xeb, 0xc7, 0x43, 0x08,
+    0xa5, 0xe0, 0xaf, 0xe7, 0xb7, 0x8e, 0x27, 0xe1, 0xbd, 0x4b, 0x45, 0x9d,
+    0x3e, 0xc6, 0x1a, 0xed, 0x3a, 0x7e, 0xd8, 0x2f, 0x82, 0x13, 0xa1, 0xd5,
+    0x13, 0x24, 0x27, 0x6a, 0x19, 0x1a, 0x41, 0xf1, 0x6f, 0xd2, 0x79, 0xd4,
+    0x04, 0x3a, 0x73, 0xf4, 0x4e, 0x9f, 0x7f, 0x5b, 0x6b, 0x87, 0x49, 0x3a,
+    0x78, 0x7e, 0x1a, 0x85, 0xa2, 0x12, 0xfa, 0x5d, 0x9f, 0xfd, 0x81, 0xa5,
+    0xe6, 0xed, 0xc0, 0x60, 0x4e, 0x9b, 0x94, 0x74, 0xcc, 0x68, 0xe9, 0xf6,
+    0x5e, 0x41, 0x0e, 0x1a, 0xcf, 0xa2, 0xb3, 0xee, 0x66, 0xfe, 0x73, 0xa7,
+    0xca, 0xab, 0x6f, 0xad, 0x3a, 0x3e, 0x26, 0x0d, 0x73, 0xa6, 0x1f, 0xfe,
+    0x4f, 0x3c, 0x1c, 0xe5, 0x1d, 0x3f, 0xf3, 0xe0, 0xb7, 0x98, 0x22, 0xec,
+    0x9d, 0x24, 0xea, 0x28, 0x45, 0x07, 0xc4, 0x13, 0xfd, 0x81, 0xc1, 0x71,
+    0xfd, 0xce, 0x8d, 0x9d, 0x44, 0x4b, 0x65, 0xa3, 0x06, 0x56, 0xf6, 0x1b,
+    0xa9, 0x08, 0xab, 0x4a, 0x20, 0x48, 0x6d, 0x76, 0x9b, 0x02, 0xb8, 0x7d,
+    0x72, 0x5a, 0xf5, 0x2a, 0x02, 0x14, 0x03, 0x38, 0x65, 0xa8, 0xd2, 0xfd,
+    0x2d, 0x0b, 0xf8, 0x73, 0x5e, 0x8f, 0x3f, 0xe9, 0xa4, 0xff, 0x67, 0x45,
+    0xfc, 0xdc, 0xe1, 0xd3, 0xf0, 0x83, 0x03, 0x4d, 0x3a, 0x7f, 0x58, 0x71,
+    0xad, 0xad, 0x1d, 0x3e, 0xa6, 0xfc, 0x0a, 0x1d, 0x39, 0xae, 0x03, 0xa7,
+    0xdf, 0x58, 0x6b, 0xab, 0x95, 0x0e, 0x98, 0x16, 0x1b, 0x21, 0x5f, 0x0c,
+    0x7c, 0x51, 0xf4, 0x6e, 0x56, 0x3a, 0x7f, 0xe5, 0x07, 0xfa, 0xfb, 0x9a,
+    0x47, 0x13, 0xa7, 0x5f, 0xa0, 0x4e, 0x8e, 0x9f, 0x12, 0xd1, 0x25, 0xf4,
+    0xd1, 0x02, 0xcb, 0xc6, 0xa0, 0x52, 0x49, 0xe3, 0x78, 0xc8, 0xfc, 0xff,
+    0x92, 0xff, 0x89, 0xf6, 0xe0, 0x01, 0xca, 0x9f, 0xe1, 0xf6, 0xbf, 0xdf,
+    0xc8, 0xc9, 0xd3, 0xfb, 0xfa, 0xd6, 0x60, 0xa8, 0x74, 0x39, 0xf6, 0xf0,
+    0xee, 0x7f, 0xf2, 0x29, 0xf0, 0x69, 0x4f, 0x9a, 0x00, 0x1c, 0xe9, 0xfd,
+    0x5c, 0xdf, 0x4e, 0x3e, 0x3a, 0x34, 0x88, 0x0f, 0x27, 0x4f, 0x37, 0x99,
+    0xb1, 0xd3, 0xfc, 0xfb, 0xae, 0xbd, 0x9b, 0xf8, 0xe8, 0xdc, 0xf6, 0xc4,
+    0x8a, 0x7f, 0x9e, 0xde, 0xff, 0x9d, 0x76, 0x4e, 0x9f, 0xff, 0xdc, 0x7e,
+    0x83, 0x2f, 0x26, 0xb5, 0x83, 0x6a, 0x10, 0x1d, 0x3e, 0x7c, 0x1f, 0x5f,
+    0x9d, 0x25, 0x9d, 0x0b, 0x37, 0x02, 0x51, 0x39, 0xbf, 0x84, 0xe9, 0xda,
+    0xad, 0xfe, 0x1b, 0xda, 0x20, 0x9f, 0xff, 0xb0, 0x76, 0xd6, 0x9c, 0x19,
+    0xc4, 0xed, 0x33, 0xe3, 0xa0, 0x2a, 0xb7, 0x77, 0x85, 0x0f, 0x5f, 0x96,
+    0x45, 0xc3, 0xaf, 0x43, 0x51, 0x93, 0x48, 0x75, 0x7f, 0xe9, 0x2e, 0x36,
+    0x7f, 0xff, 0xbb, 0xb6, 0x23, 0x15, 0x4d, 0xd3, 0xac, 0x3c, 0x71, 0xb1,
+    0xd3, 0xc1, 0xe7, 0xfb, 0x1d, 0x3f, 0x83, 0x4d, 0xcd, 0xbf, 0x13, 0xa6,
+    0xcd, 0x9c, 0xf5, 0xf0, 0x92, 0x7e, 0xf5, 0xff, 0xfc, 0xcb, 0x1d, 0x3f,
+    0xba, 0xfe, 0x40, 0x3b, 0x4e, 0x9d, 0xb0, 0xb4, 0xe8, 0xbe, 0x57, 0xa1,
+    0x9d, 0xc9, 0x6b, 0xdc, 0x9c, 0x26, 0xa2, 0xa1, 0x85, 0xe6, 0x8b, 0x3c,
+    0x63, 0xf9, 0x8c, 0xfe, 0x6b, 0x18, 0x35, 0xcc, 0x3a, 0x7f, 0x5e, 0xa6,
+    0x02, 0xe3, 0xb1, 0xd3, 0xcf, 0xfd, 0xf4, 0x87, 0x4f, 0xe4, 0xeb, 0xed,
+    0x5d, 0xb1, 0xd2, 0xf7, 0x4f, 0x63, 0xc4, 0xd3, 0xff, 0xbb, 0x61, 0xcb,
+    0xc3, 0x8f, 0xd7, 0xd1, 0xd3, 0xfa, 0x98, 0xe6, 0x2f, 0x34, 0x74, 0x61,
+    0xfd, 0x5e, 0x48, 0x9f, 0x91, 0x4f, 0x66, 0x2c, 0xe9, 0xf6, 0x05, 0x3b,
+    0xa3, 0xa7, 0x7b, 0xdb, 0x9d, 0x3f, 0xf6, 0xf6, 0x4e, 0x7c, 0x55, 0x9c,
+    0x45, 0x9d, 0x00, 0x3e, 0x5f, 0x0e, 0xcd, 0xff, 0x4e, 0x8d, 0x1b, 0x9b,
+    0xf2, 0x29, 0x3e, 0xc8, 0xe8, 0x66, 0x18, 0x90, 0xea, 0xa5, 0x72, 0x11,
+    0xa9, 0x0a, 0x2e, 0x11, 0xfa, 0x31, 0x49, 0xff, 0x0a, 0x7d, 0xdf, 0x2f,
+    0x6e, 0xff, 0x4e, 0x9f, 0xfc, 0x99, 0xd0, 0xbb, 0x39, 0xc7, 0xdf, 0x47,
+    0x4d, 0x5d, 0x3a, 0x7e, 0xf2, 0x6c, 0xb7, 0xb1, 0xd0, 0x13, 0xc2, 0xe0,
+    0xac, 0xd8, 0xa8, 0xe9, 0xe0, 0x7d, 0x16, 0x9d, 0x30, 0x28, 0x4d, 0xd7,
+    0x85, 0xe1, 0xd1, 0x0f, 0xfa, 0xe4, 0xdb, 0xb0, 0x74, 0xfb, 0xef, 0x80,
+    0xbc, 0x3a, 0x16, 0x78, 0x20, 0x18, 0x9d, 0x67, 0xd1, 0xd3, 0xff, 0x2f,
+    0x4b, 0x70, 0xbf, 0x7f, 0x70, 0x1d, 0x3f, 0xe7, 0xa1, 0xcf, 0x79, 0x19,
+    0xf1, 0xd0, 0xe8, 0xbd, 0xc2, 0x24, 0x1b, 0xfd, 0x12, 0x1d, 0x77, 0x45,
+    0xb2, 0xb1, 0xb1, 0x66, 0xc8, 0x9a, 0x8c, 0x4b, 0xd1, 0x90, 0xcf, 0xee,
+    0xa6, 0x33, 0x9b, 0xf8, 0xe9, 0xff, 0xda, 0xc1, 0xfe, 0xdc, 0xc5, 0xb1,
+    0x56, 0x3a, 0x7f, 0x0a, 0x9c, 0x75, 0xac, 0x4e, 0x9f, 0x3b, 0x19, 0x96,
+    0x3a, 0x30, 0xf6, 0x38, 0x65, 0x3f, 0xf2, 0x73, 0x18, 0x46, 0x3f, 0x55,
+    0xfe, 0x8e, 0x9f, 0x3a, 0xae, 0x3b, 0x07, 0x43, 0x4f, 0xcb, 0x49, 0x33,
+    0xff, 0x7e, 0xc2, 0x71, 0xf7, 0x6b, 0xb0, 0xe7, 0x4f, 0x83, 0x42, 0xfc,
+    0x3a, 0x7f, 0xfb, 0x5e, 0xd2, 0x01, 0xdb, 0xac, 0xcd, 0xfc, 0x74, 0x93,
+    0x87, 0xe8, 0xc9, 0x2c, 0xff, 0xfb, 0xbf, 0xf7, 0xae, 0x38, 0xa2, 0x73,
+    0x99, 0xf4, 0xe9, 0xf8, 0x69, 0x02, 0xe2, 0x74, 0xf6, 0xce, 0xa9, 0xce,
+    0x9d, 0x7b, 0xfe, 0x1d, 0x3f, 0xf2, 0x2d, 0x35, 0xc7, 0x4e, 0xfe, 0xae,
+    0x74, 0x3a, 0x22, 0x10, 0x8e, 0x87, 0xe7, 0xf9, 0xfe, 0xf9, 0x3a, 0x9e,
+    0xfc, 0xe9, 0xfb, 0xff, 0xbc, 0xcd, 0xf4, 0x74, 0xff, 0xff, 0xfb, 0xaf,
+    0xe1, 0xab, 0x26, 0x98, 0x4e, 0xd9, 0xf5, 0xe7, 0xdd, 0xfe, 0xe6, 0x8e,
+    0x9f, 0xff, 0xff, 0xf6, 0xb5, 0x9e, 0xe5, 0x2f, 0x5d, 0xea, 0x6f, 0xea,
+    0xa5, 0x33, 0x18, 0xff, 0xce, 0xce, 0xee, 0x74, 0x3a, 0x64, 0x15, 0x08,
+    0x39, 0xe0, 0x56, 0xfa, 0x3a, 0x66, 0x59, 0x3a, 0x34, 0x6e, 0x99, 0x22,
+    0x9f, 0x27, 0x2b, 0x38, 0x55, 0xc6, 0x8a, 0x1d, 0x77, 0x95, 0xa6, 0x61,
+    0x85, 0x16, 0xf0, 0x93, 0x57, 0x22, 0x62, 0x17, 0x5d, 0x28, 0x5a, 0xbf,
+    0x21, 0x62, 0x02, 0xdb, 0xe8, 0xe8, 0x63, 0x51, 0xd4, 0x20, 0xe7, 0xcc,
+    0x3b, 0x1c, 0x73, 0xa7, 0x32, 0xcb, 0x25, 0x4f, 0x37, 0xd9, 0x62, 0xae,
+    0x2f, 0xe7, 0xd8, 0x14, 0x06, 0x8f, 0x77, 0xf4, 0x74, 0xf9, 0x04, 0xc6,
+    0x1d, 0x19, 0x95, 0x0a, 0xb9, 0x68, 0xe9, 0xfd, 0xed, 0xdb, 0xc7, 0x1d,
+    0x8e, 0x9f, 0x6c, 0xbf, 0xf7, 0xf1, 0xd1, 0xd3, 0xef, 0x11, 0x0f, 0x1a,
+    0x4f, 0xf0, 0xbb, 0x3a, 0x41, 0xdd, 0xa7, 0x4c, 0xf6, 0x3a, 0x04, 0xf3,
+    0x6f, 0x1c, 0x43, 0xa2, 0x79, 0x1e, 0xe7, 0xe1, 0xdf, 0x4c, 0x67, 0x8e,
+    0x9f, 0xfd, 0xe6, 0x33, 0xb9, 0x4b, 0x7e, 0x20, 0x4e, 0x9f, 0xbf, 0x5e,
+    0x73, 0x7a, 0x3a, 0x04, 0xfd, 0xb4, 0x91, 0x3f, 0xf9, 0x02, 0x35, 0xb8,
+    0xe7, 0xb1, 0x00, 0x74, 0xfc, 0xfe, 0xe3, 0x75, 0xf9, 0xd3, 0xed, 0x95,
+    0xd3, 0x37, 0x3a, 0x7c, 0x9a, 0x7d, 0x96, 0x7b, 0x3f, 0x67, 0xcf, 0x5d,
+    0x07, 0xe7, 0xb3, 0xf6, 0x6a, 0x69, 0xec, 0xfd, 0x9e, 0xfd, 0xb9, 0xa3,
+    0xd9, 0xfb, 0x01, 0x3d, 0x11, 0x22, 0x9f, 0x3e, 0x6b, 0x04, 0xf6, 0x7e,
+    0xc1, 0xec, 0xfd, 0x9a, 0xbc, 0x7b, 0x3f, 0x56, 0x5b, 0xc9, 0xa2, 0x7f,
+    0x3f, 0xa4, 0x4f, 0x65, 0xfa, 0x00, 0xf6, 0x7e, 0xc1, 0xec, 0xfd, 0x98,
+    0x0e, 0x7b, 0x3f, 0x67, 0xfb, 0x01, 0x5d, 0xcb, 0xd8, 0x13, 0xd9, 0xfb,
+    0x3f, 0x67, 0x13, 0x5f, 0xec, 0x7b, 0x3f, 0x60, 0x08, 0xa2, 0x12, 0x2d,
+    0x22, 0xcf, 0x77, 0x67, 0xf1, 0xec, 0xfd, 0x83, 0xd9, 0xfb, 0x86, 0xbe,
+    0x66, 0x59, 0x3d, 0x9f, 0xb0, 0xd5, 0x61, 0xa1, 0x34, 0xc8, 0x42, 0xef,
+    0x09, 0xae, 0x94, 0x2c, 0xc3, 0x50, 0xb9, 0xf2, 0xf3, 0x24, 0xd3, 0xd8,
+    0xd7, 0x50, 0xb6, 0x7e, 0xae, 0x44, 0x84, 0xff, 0xb2, 0xc1, 0xce, 0xb3,
+    0x5c, 0x60, 0xe9, 0x9b, 0xb1, 0x53, 0xcc, 0x55, 0x74, 0xe8, 0xd9, 0x17,
+    0x3b, 0xa1, 0x09, 0xfa, 0xa1, 0x78, 0xea, 0xe6, 0x0d, 0x4e, 0x40, 0xcf,
+    0xff, 0x9b, 0xd7, 0xbd, 0x4c, 0x38, 0x78, 0xeb, 0xa6, 0x0e, 0x9f, 0xca,
+    0xab, 0x49, 0xa6, 0x30, 0xe8, 0xdd, 0x11, 0x7d, 0x57, 0x87, 0x64, 0x15,
+    0x36, 0x33, 0x3c, 0x21, 0x48, 0x52, 0x2b, 0x90, 0xf5, 0x1a, 0xa7, 0x3b,
+    0xff, 0x85, 0xc4, 0xff, 0xff, 0x27, 0x2b, 0x8e, 0xdb, 0xb0, 0x0e, 0xdd,
+    0x07, 0x8f, 0xd3, 0xa7, 0xfc, 0xa3, 0xee, 0x2f, 0xce, 0x7f, 0x63, 0xa7,
+    0xff, 0x07, 0xaf, 0x83, 0x8d, 0x4e, 0x65, 0xe3, 0xa7, 0xe1, 0xa5, 0x39,
+    0x4d, 0x3a, 0x73, 0x2c, 0xb2, 0x54, 0xef, 0xae, 0x02, 0xae, 0x2f, 0xe7,
+    0xfa, 0x9b, 0xf7, 0xb9, 0x7a, 0xba, 0x74, 0xff, 0xfb, 0x98, 0xdf, 0xa2,
+    0x39, 0xb3, 0x0d, 0x7e, 0xec, 0x74, 0x0a, 0x24, 0xfc, 0x77, 0x3c, 0xd7,
+    0x06, 0xe7, 0x4f, 0xc0, 0x71, 0xcd, 0xfc, 0x74, 0xe1, 0xa0, 0x7c, 0x3c,
+    0xef, 0xa4, 0x53, 0xaf, 0x3f, 0x4e, 0x86, 0xaa, 0xbb, 0x0b, 0x2e, 0x20,
+    0x2d, 0x20, 0x09, 0x63, 0x0c, 0x0f, 0x38, 0x5e, 0x36, 0x9c, 0x14, 0xd8,
+    0xe9, 0x00, 0xe9, 0xff, 0x27, 0xb9, 0x9a, 0xf9, 0xe4, 0xd8, 0xe9, 0xfe,
+    0x14, 0xfe, 0xfa, 0xd5, 0xfb, 0xf8, 0xe8, 0x6a, 0x24, 0x38, 0x20, 0x28,
+    0x13, 0x99, 0x65, 0x92, 0xc4, 0x20, 0x9f, 0x76, 0xd5, 0x56, 0x2c, 0x42,
+    0x0b, 0x8d, 0x6c, 0xe6, 0x59, 0x64, 0xb1, 0x07, 0xa0, 0xb1, 0x07, 0xae,
+    0x35, 0xb2, 0x5e, 0x22, 0x6e, 0xce, 0x53, 0xff, 0x71, 0xda, 0x9e, 0xce,
+    0x59, 0xd6, 0x74, 0x39, 0xf5, 0x5e, 0x28, 0x9f, 0xfd, 0x9c, 0x4e, 0xf2,
+    0xb3, 0x49, 0x5b, 0x1d, 0x3c, 0xfe, 0x75, 0x9d, 0x0b, 0x3e, 0x7f, 0x23,
+    0xcf, 0xcc, 0xd0, 0x7f, 0xaf, 0xa7, 0x4f, 0x0a, 0x3a, 0x87, 0x4e, 0xfa,
+    0xe0, 0x3a, 0x36, 0x37, 0xab, 0x20, 0x9f, 0x59, 0xf8, 0xeb, 0x2a, 0x7c,
+    0x34, 0x23, 0x85, 0x4d, 0x96, 0x2a, 0x66, 0x59, 0x2a, 0x30, 0xfd, 0xb4,
+    0x4d, 0xe2, 0x36, 0x45, 0x67, 0xf0, 0xfd, 0x70, 0x73, 0x15, 0x15, 0x71,
+    0xbc, 0x87, 0x4e, 0xa7, 0x08, 0x91, 0xb6, 0xa1, 0xa9, 0x3f, 0xf3, 0x83,
+    0x59, 0x81, 0xa1, 0xa5, 0x0e, 0x9f, 0xfe, 0x6e, 0x99, 0x7e, 0xf1, 0xd3,
+    0x8e, 0x28, 0x74, 0xff, 0xf6, 0x87, 0x37, 0x05, 0x6a, 0xba, 0x9b, 0x80,
+    0xe8, 0xdd, 0x13, 0x8c, 0xa6, 0xc7, 0x13, 0x02, 0xa8, 0x6e, 0xcf, 0xc9,
+    0x60, 0xe5, 0x00, 0xe9, 0xff, 0xff, 0x3e, 0xd7, 0x6b, 0xda, 0xdf, 0xe0,
+    0x70, 0x2f, 0x5d, 0xc1, 0x01, 0xd3, 0xe5, 0xe9, 0x9a, 0xdc, 0xe9, 0x68,
+    0x28, 0x98, 0xfa, 0xdf, 0x0e, 0xbe, 0x1e, 0x17, 0x8c, 0x85, 0x62, 0x46,
+    0xc3, 0xd9, 0x46, 0x75, 0x1a, 0x08, 0x94, 0x6a, 0x18, 0x73, 0x99, 0x65,
+    0x92, 0xa7, 0x81, 0x42, 0x12, 0xae, 0x2f, 0xe7, 0xb8, 0x94, 0xd3, 0xa7,
+    0xbb, 0xf1, 0x4b, 0xf3, 0xa7, 0xef, 0xb9, 0xdc, 0xc6, 0x0e, 0x86, 0xa2,
+    0x98, 0x26, 0x08, 0x41, 0xa2, 0x89, 0xff, 0xe1, 0xdf, 0xe6, 0xe0, 0x71,
+    0xb5, 0x6c, 0x34, 0x74, 0xff, 0xff, 0xff, 0x7b, 0x5f, 0x75, 0xf3, 0x94,
+    0x9e, 0x4e, 0x59, 0x3e, 0x35, 0x39, 0x43, 0xe6, 0xe7, 0x70, 0xe9, 0xff,
+    0xae, 0x08, 0xbf, 0xf6, 0xc5, 0x13, 0xa7, 0x4d, 0x8c, 0x9d, 0x2c, 0x73,
+    0xdb, 0xd2, 0x2c, 0xf2, 0xae, 0x02, 0xf1, 0xd0, 0xd3, 0xcc, 0xa2, 0x69,
+    0xff, 0xb3, 0xa0, 0x5a, 0x6b, 0xee, 0x9f, 0x0e, 0x9d, 0x4a, 0xfa, 0x3a,
+    0x1a, 0x7c, 0x54, 0x89, 0x38, 0x38, 0xb3, 0xa7, 0x81, 0xec, 0x01, 0xd0,
+    0x86, 0xf3, 0xa3, 0x73, 0xfd, 0x6e, 0x0b, 0xee, 0x8f, 0xc3, 0xa1, 0xd5,
+    0x81, 0x34, 0xf3, 0x14, 0x6a, 0x33, 0xe1, 0x84, 0x1f, 0xeb, 0xbf, 0x48,
+    0x27, 0xda, 0xc5, 0x1f, 0x47, 0x4f, 0xca, 0xfa, 0x41, 0xdd, 0xa7, 0x4f,
+    0xfa, 0xbb, 0x7e, 0x9c, 0xca, 0xdc, 0x07, 0x4f, 0xff, 0x93, 0xce, 0xbc,
+    0xdf, 0xce, 0xbf, 0xbd, 0xa0, 0x1d, 0x3c, 0x83, 0x41, 0x3a, 0x7f, 0xb4,
+    0xfd, 0xf3, 0xdc, 0x14, 0x3a, 0x1a, 0x8a, 0xd0, 0xab, 0x68, 0x7e, 0x7f,
+    0x22, 0x9e, 0x7e, 0x3e, 0x8e, 0x9f, 0xf0, 0xd3, 0x1c, 0xae, 0xf5, 0x02,
+    0x74, 0xf7, 0xc0, 0xa0, 0x9d, 0x0d, 0x54, 0x0b, 0x84, 0xf6, 0x30, 0x48,
+    0x76, 0xf4, 0xc1, 0x66, 0x4c, 0x9e, 0xcf, 0x77, 0xb9, 0xa3, 0xa6, 0xc6,
+    0x0e, 0x93, 0x68, 0xdb, 0xfd, 0x21, 0x9f, 0x74, 0x39, 0x82, 0x74, 0xff,
+    0xca, 0xe9, 0x9c, 0x7b, 0xda, 0xe3, 0xee, 0x74, 0x51, 0xf6, 0xe8, 0x96,
+    0x7f, 0xb0, 0x7b, 0x9a, 0xc4, 0xe1, 0xd3, 0xff, 0xcd, 0xf0, 0xe5, 0x78,
+    0x73, 0xde, 0xc6, 0x4e, 0x9f, 0xfd, 0xed, 0x63, 0x1c, 0x7b, 0xd9, 0xce,
+    0x39, 0xd3, 0xf7, 0x02, 0x97, 0x9c, 0x27, 0x46, 0x1f, 0xcd, 0x25, 0xcf,
+    0x67, 0x93, 0x47, 0x4f, 0xca, 0xcb, 0x03, 0x7c, 0x6d, 0xf9, 0xd1, 0xa3,
+    0xda, 0xf1, 0x04, 0x05, 0x3b, 0x8b, 0x10, 0xee, 0x6a, 0x30, 0xc6, 0xf3,
+    0xd4, 0xff, 0xf2, 0x6b, 0x03, 0xed, 0x22, 0x9c, 0xa1, 0x43, 0xa7, 0xff,
+    0xf0, 0xfb, 0x38, 0x8f, 0xe4, 0x03, 0xb6, 0xe6, 0x59, 0x64, 0xa9, 0xe0,
+    0xe6, 0x28, 0x54, 0xf5, 0x02, 0xbc, 0x74, 0xff, 0x76, 0xad, 0xf3, 0x8f,
+    0xf4, 0x4e, 0x9d, 0xfb, 0xf4, 0xe9, 0xbd, 0xa0, 0x9e, 0xbb, 0x07, 0x73,
+    0x9a, 0x3f, 0x9a, 0x21, 0x99, 0xcc, 0xb2, 0xc9, 0x53, 0xb0, 0x6c, 0x55,
+    0xc5, 0xfc, 0xff, 0xb3, 0x6c, 0x0d, 0x34, 0x5f, 0x63, 0xa0, 0x07, 0xce,
+    0x25, 0x53, 0xd4, 0x2a, 0xd9, 0x7d, 0x9d, 0x3f, 0x9a, 0x39, 0xef, 0x7f,
+    0xb1, 0xd3, 0xa9, 0x5d, 0xce, 0x9f, 0x60, 0x79, 0x4a, 0xe7, 0x43, 0xaa,
+    0x9f, 0xd9, 0x88, 0x24, 0x38, 0xef, 0xb9, 0x7f, 0x61, 0x5f, 0xc2, 0x1a,
+    0x2c, 0xfc, 0xd2, 0xf0, 0xec, 0xfe, 0x75, 0xe2, 0x75, 0x86, 0x9d, 0x3c,
+    0x9e, 0x47, 0x3a, 0x7f, 0xfd, 0xca, 0xee, 0xb1, 0x06, 0xbd, 0xa6, 0x5c,
+    0x4e, 0x9f, 0x05, 0x3a, 0xfe, 0x3a, 0x7f, 0x7f, 0x9d, 0x00, 0x10, 0x4e,
+    0x9f, 0xfb, 0x98, 0xb4, 0x0f, 0x70, 0x34, 0xb3, 0xa7, 0xff, 0x20, 0x79,
+    0xf7, 0x59, 0xdb, 0x55, 0x58, 0xd1, 0x06, 0x4f, 0x7f, 0xcc, 0xb1, 0xd0,
+    0xd3, 0xf9, 0xbf, 0x57, 0x9f, 0xfd, 0xda, 0xbd, 0x83, 0x6e, 0x20, 0x3e,
+    0xf8, 0xe8, 0x73, 0xf1, 0xfc, 0x96, 0x38, 0x9c, 0x06, 0x8c, 0xbd, 0x19,
+    0x64, 0xff, 0x2d, 0x19, 0xc1, 0x0f, 0x1c, 0xe9, 0xb9, 0xf9, 0xd3, 0xff,
+    0xe6, 0xa0, 0x87, 0x99, 0xbf, 0xda, 0x1f, 0x08, 0x4e, 0x9c, 0x8c, 0xab,
+    0x9d, 0x3f, 0xb2, 0xf6, 0xbd, 0xe7, 0x59, 0xd1, 0xd3, 0xd3, 0xe0, 0xfc,
+    0x62, 0x63, 0x08, 0x6e, 0xc0, 0xbe, 0xa1, 0x51, 0x3f, 0xaf, 0xf3, 0x57,
+    0xf9, 0xd7, 0x3a, 0x7f, 0xf8, 0x5e, 0xdf, 0x3b, 0x89, 0xfd, 0xf5, 0x8a,
+    0xb0, 0xe8, 0x6a, 0xe1, 0xa8, 0x47, 0xf1, 0x49, 0x23, 0xa6, 0xd4, 0x69,
+    0xfe, 0x42, 0x54, 0x6f, 0x3f, 0x5e, 0xc1, 0x45, 0x4e, 0x74, 0xff, 0x7f,
+    0xe0, 0x7e, 0xb7, 0xcf, 0x1d, 0x3f, 0xf8, 0x76, 0xf8, 0xc2, 0x0e, 0x07,
+    0x05, 0x43, 0xa7, 0x7d, 0xc7, 0x3a, 0x1c, 0xf9, 0xe9, 0x2e, 0x73, 0xf5,
+    0x83, 0xa1, 0xd9, 0x94, 0x61, 0x85, 0x0e, 0x4a, 0x4d, 0xb2, 0x82, 0x4a,
+    0xec, 0xe4, 0x25, 0x2a, 0x71, 0x9c, 0x0e, 0x62, 0x5d, 0xfc, 0x28, 0x6f,
+    0xc8, 0x27, 0x6f, 0xb5, 0xe3, 0xa7, 0xf6, 0xff, 0x2d, 0xc7, 0xdd, 0x51,
+    0xd3, 0xea, 0x5d, 0x66, 0x8e, 0x9f, 0xfe, 0xb3, 0xeb, 0x4e, 0xbc, 0xf2,
+    0x6b, 0x94, 0x74, 0xfe, 0x11, 0x76, 0xad, 0xd0, 0xe9, 0xfd, 0xe4, 0xbc,
+    0x9e, 0x6b, 0x95, 0x25, 0x9d, 0x3f, 0x60, 0xa9, 0xd7, 0xb9, 0x0f, 0x0f,
+    0xe9, 0x9c, 0x62, 0x60, 0xa8, 0x9b, 0xa7, 0x29, 0xee, 0xff, 0xbb, 0x4e,
+    0x9f, 0xc2, 0xd1, 0xc5, 0xbd, 0x8e, 0x9c, 0xb0, 0xe1, 0xd0, 0xe7, 0xdf,
+    0x84, 0x94, 0x61, 0x3d, 0x6b, 0xff, 0xfc, 0x74, 0xfb, 0xde, 0xd5, 0x00,
+    0xe9, 0xf3, 0xaf, 0xd9, 0x63, 0xa6, 0x4d, 0x8e, 0x84, 0x3e, 0x3e, 0x13,
+    0xf8, 0x9a, 0x7c, 0xca, 0x05, 0x52, 0x1d, 0x3f, 0xd9, 0xee, 0x62, 0xc6,
+    0xbc, 0x74, 0xfd, 0x79, 0x3b, 0xbb, 0xab, 0x9d, 0x21, 0x09, 0xf4, 0x61,
+    0xb4, 0xf9, 0x6f, 0x6d, 0x82, 0x74, 0xfb, 0xa0, 0x5a, 0x68, 0xe9, 0xbd,
+    0xac, 0x3c, 0xff, 0xa5, 0x10, 0xe8, 0xa4, 0xfd, 0xd6, 0x5a, 0x3a, 0x7e,
+    0x7d, 0xb0, 0x51, 0x43, 0xa3, 0xa6, 0xf3, 0x42, 0x13, 0xff, 0x38, 0xd7,
+    0x1c, 0x17, 0x77, 0x5a, 0x2a, 0x02, 0x8c, 0x3c, 0x5f, 0x59, 0x0c, 0xfe,
+    0xa0, 0xeb, 0x4f, 0xd6, 0x9d, 0x37, 0xfb, 0x1d, 0x3f, 0xb7, 0x6e, 0xfa,
+    0x4f, 0x39, 0xd3, 0x93, 0x7d, 0x1d, 0x18, 0x7a, 0x08, 0x69, 0x08, 0x88,
+    0x8e, 0x34, 0x4d, 0x96, 0x3a, 0x77, 0x73, 0x47, 0x78, 0xb5, 0x9f, 0xfe,
+    0x0f, 0xca, 0x4c, 0xd3, 0xed, 0x82, 0x8a, 0x1d, 0x3f, 0xba, 0xb7, 0xdf,
+    0xd5, 0x63, 0xa3, 0x11, 0x04, 0x89, 0xf3, 0xf3, 0xb0, 0x8b, 0x76, 0x0e,
+    0x9b, 0x19, 0x3a, 0x0a, 0x9f, 0xb5, 0xf5, 0xfa, 0xeb, 0x2a, 0x0a, 0x82,
+    0xa0, 0xa8, 0x2a, 0x1a, 0x7c, 0x08, 0x14, 0x02, 0xef, 0xc2, 0xaf, 0xc2,
+    0x95, 0x05, 0x4d, 0xcc, 0x2a, 0x7e, 0xaa, 0xf3, 0x0e, 0xb2, 0xbe, 0x16,
+    0xb2, 0xbe, 0x8a, 0x82, 0xa0, 0xa8, 0x69, 0x68, 0x81, 0x50, 0x54, 0x15,
+    0x05, 0x41, 0x50, 0x54, 0x15, 0x1b, 0x1b, 0xc0, 0x85, 0x20, 0x50, 0x02,
+    0xb4, 0x15, 0x78, 0x2a, 0x0a, 0x82, 0xa1, 0xa5, 0xa6, 0x82, 0xa0, 0xa8,
+    0x2a, 0x0a, 0x82, 0xa1, 0xa6, 0xa0, 0x01, 0x5e, 0x0a, 0x54, 0x15, 0x05,
+    0x41, 0x50, 0x54, 0x15, 0x1b, 0x1a, 0x85, 0x02, 0xba, 0x15, 0xc0, 0xa9,
+    0x28, 0x54, 0x15, 0x05, 0x41, 0x50, 0x54, 0x04, 0xd4, 0x6e, 0x14, 0x00,
+    0xaf, 0xc2, 0xa0, 0xa8, 0x2a, 0x0a, 0x9f, 0x71, 0xc1, 0xac, 0x2a, 0x0a,
+    0x86, 0x9e, 0x75, 0x82, 0xb8, 0x15, 0x41, 0x40, 0x26, 0x95, 0x8a, 0x82,
+    0xa0, 0xa8, 0x2a, 0x0a, 0x86, 0x9a, 0x8d, 0xc2, 0x90, 0x2a, 0xf0, 0x54,
+    0x15, 0x05, 0x41, 0x50, 0x54, 0x34, 0xd4, 0x04, 0x2b, 0x81, 0x42, 0x15,
+    0x2e, 0x15, 0x05, 0x41, 0x52, 0x69, 0x50, 0x56, 0xe5, 0x84, 0x15, 0x05,
+    0x41, 0x50, 0x54, 0x6c, 0x7c, 0xcd, 0x0a, 0x50, 0x6a, 0xc3, 0x4c, 0x05,
+    0x00, 0x2b, 0xc1, 0x52, 0xc2, 0xa0, 0xa8, 0x2a, 0x4d, 0x2a, 0x0a, 0xdc,
+    0xb0, 0x82, 0xa0, 0xa8, 0x73, 0xd2, 0x68, 0x52, 0x0d, 0x74, 0x69, 0x61,
+    0x50, 0x54, 0x15, 0x05, 0x41, 0x50, 0x54, 0x39, 0xb2, 0xdc, 0x2b, 0xa1,
+    0x4b, 0x0a, 0x10, 0xa8, 0x2a, 0x0a, 0x82, 0xa3, 0xa5, 0xf6, 0x82, 0xbc,
+    0x15, 0x05, 0x41, 0x50, 0x54, 0x2c, 0xbe, 0x10, 0xaf, 0x05, 0x49, 0x65,
+    0x41, 0x50, 0x54, 0x00, 0xb4, 0xfc, 0x2a, 0x0a, 0x82, 0xa0, 0xa8, 0x2a,
+    0x1c, 0xd4, 0x30, 0x15, 0xc0, 0xaf, 0xc2, 0xa1, 0xd7, 0xe9, 0x36, 0x70,
+    0x69, 0xe8, 0x4a, 0x71, 0x6e, 0xcd, 0x7b, 0xa4, 0x23, 0x2a, 0xb9, 0xeb,
+    0x07, 0x3d, 0x84, 0x5a, 0xd2, 0x38, 0x71, 0x4c, 0xa0, 0x3a, 0x17, 0x6d,
+    0x33, 0x79, 0x87, 0xf7, 0x9b, 0xcc, 0xac, 0xa5, 0xdf, 0x96, 0x7d, 0x24,
+    0x54, 0x93, 0x3e, 0x68, 0xbe, 0x68, 0xab, 0x93, 0x55, 0x9c, 0x8e, 0xb2,
+    0xa7, 0x92, 0xd5, 0xd3, 0xa7, 0x20, 0x70, 0xe9, 0x5d, 0xba, 0x23, 0x7a,
+    0x73, 0xc1, 0xaf, 0x10, 0x49, 0xef, 0x32, 0x90, 0x7e, 0xd2, 0x7f, 0x27,
+    0xf7, 0x11, 0x90, 0xf5, 0xf6, 0x3a, 0x37, 0x3e, 0xd6, 0x0e, 0x67, 0xd9,
+    0x8c, 0x57, 0xd3, 0xa6, 0x03, 0x9d, 0x3f, 0x76, 0x87, 0xeb, 0x80, 0xe9,
+    0xab, 0xa7, 0x49, 0x0e, 0xb1, 0x6b, 0x2b, 0x1d, 0x25, 0x9d, 0x35, 0xfd,
+    0xc8, 0x89, 0x5e, 0x8a, 0xf1, 0x0a, 0x87, 0xbe, 0x88, 0x4f, 0xf7, 0x1d,
+    0x78, 0xc3, 0x8e, 0xc7, 0x46, 0x22, 0x48, 0x0b, 0x53, 0xda, 0x7d, 0xf4,
+    0x74, 0xfc, 0xb4, 0xbf, 0xa1, 0x01, 0xd3, 0xfd, 0xf6, 0x83, 0xac, 0x5b,
+    0xab, 0x9d, 0x3b, 0x37, 0x64, 0xe9, 0xdb, 0x83, 0x3a, 0x7b, 0x22, 0x79,
+    0x3d, 0x7b, 0x3a, 0xd3, 0xa7, 0x06, 0x84, 0xe8, 0x43, 0x7b, 0x44, 0x73,
+    0xff, 0xcf, 0xf2, 0xbb, 0xda, 0x03, 0xdc, 0xcb, 0x2c, 0x9d, 0x0e, 0x9b,
+    0x55, 0x42, 0x1f, 0x4e, 0x1f, 0x8f, 0xc5, 0xf2, 0xda, 0x93, 0xb9, 0x06,
+    0xc7, 0x2d, 0x8c, 0xa8, 0x30, 0x9e, 0xc2, 0xcb, 0x42, 0x27, 0x72, 0xe4,
+    0x8f, 0xe1, 0x5c, 0xbd, 0x88, 0x5d, 0x74, 0xdd, 0x70, 0xac, 0xe1, 0x0d,
+    0x52, 0xb6, 0xc0, 0x48, 0x31, 0xa7, 0xe8, 0x8b, 0xd1, 0xc6, 0x4f, 0x96,
+    0x83, 0x67, 0x3a, 0x7e, 0x5e, 0x91, 0x4f, 0x32, 0x74, 0xf9, 0xf7, 0xe3,
+    0xb4, 0xe8, 0xfa, 0x7a, 0xca, 0x8b, 0xe6, 0xdf, 0xc7, 0x4f, 0xbd, 0x43,
+    0xfe, 0x1d, 0x27, 0xc3, 0x7a, 0x22, 0xf3, 0xf6, 0xfa, 0x75, 0x5d, 0x73,
+    0xa7, 0xe6, 0x8a, 0x37, 0x98, 0x74, 0xfb, 0x64, 0xeb, 0xb4, 0xe8, 0xe9,
+    0xe9, 0x09, 0x5c, 0xf6, 0x05, 0x14, 0x3a, 0x7f, 0xdc, 0x7e, 0x80, 0x71,
+    0x9a, 0x01, 0xd3, 0xb3, 0x18, 0x3a, 0x59, 0xc3, 0xd8, 0x01, 0xec, 0xfd,
+    0xff, 0x7f, 0x5d, 0x09, 0xd3, 0xcb, 0x7c, 0xd8, 0xe9, 0xf6, 0x5e, 0x17,
+    0xdc, 0xe8, 0x43, 0xc9, 0xd1, 0x0c, 0xf3, 0x8f, 0xac, 0x74, 0x9f, 0x13,
+    0x79, 0xe9, 0x08, 0xbc, 0xe8, 0x9f, 0xce, 0xf7, 0xe4, 0x33, 0xdf, 0xd7,
+    0x5a, 0x74, 0xf3, 0xff, 0x7d, 0x68, 0xa9, 0xf3, 0x6e, 0x65, 0x96, 0x4e,
+    0x81, 0x3d, 0x3f, 0xc9, 0xe7, 0xab, 0xcb, 0xf1, 0xd0, 0x14, 0x5c, 0x63,
+    0xa8, 0x08, 0xa1, 0xd7, 0x10, 0x51, 0xed, 0x6c, 0x74, 0x48, 0x08, 0xfe,
+    0xbf, 0x8c, 0x5a, 0x72, 0xb4, 0xad, 0xb7, 0xc9, 0xd3, 0x9a, 0x34, 0x74,
+    0xb7, 0x56, 0x8f, 0x1d, 0xcb, 0x67, 0xe7, 0xee, 0xcf, 0xdd, 0x8e, 0x9f,
+    0x7e, 0x0c, 0x1b, 0x1d, 0x3b, 0xae, 0xc1, 0xd3, 0xc8, 0x34, 0xc1, 0xd3,
+    0xfb, 0xd9, 0xf5, 0xd8, 0x4d, 0x1d, 0x0d, 0x46, 0x2f, 0x4b, 0x96, 0x4f,
+    0xc1, 0xcb, 0xc4, 0x13, 0xfc, 0xe9, 0xc7, 0x5e, 0xd8, 0xc9, 0xd3, 0xf3,
+    0xf1, 0x36, 0xa1, 0x3a, 0x7f, 0xb6, 0x1c, 0x6f, 0x30, 0x1a, 0x3a, 0x7f,
+    0xd8, 0x3b, 0xb7, 0x5d, 0xfd, 0xc0, 0x74, 0xfb, 0x3d, 0xac, 0x50, 0xe8,
+    0x43, 0xe6, 0x59, 0xfc, 0xf0, 0x42, 0xf7, 0x8e, 0x9f, 0xfe, 0xe3, 0xae,
+    0xcf, 0xec, 0xed, 0xaa, 0xac, 0x68, 0xbe, 0x27, 0x57, 0x76, 0x34, 0x5f,
+    0xf0, 0xe8, 0x83, 0xb2, 0xd4, 0xe0, 0x3a, 0xa3, 0xa7, 0xfc, 0xa9, 0x30,
+    0x42, 0xa2, 0x67, 0x4e, 0x9f, 0xab, 0xbb, 0xb7, 0x3c, 0x74, 0xff, 0xbd,
+    0xa4, 0xef, 0x87, 0xfa, 0x69, 0xd3, 0xab, 0x75, 0x47, 0x4f, 0xd5, 0xed,
+    0x3e, 0x6c, 0x74, 0x3a, 0x2d, 0x70, 0xb6, 0xf1, 0xf3, 0x23, 0xd3, 0xff,
+    0x6b, 0x07, 0xda, 0xfb, 0x79, 0xf3, 0x73, 0xa7, 0xf9, 0x9f, 0xbb, 0x6b,
+    0x16, 0xea, 0xe7, 0x4e, 0x4e, 0x21, 0xd3, 0xec, 0x6f, 0x42, 0xd3, 0xa7,
+    0xfe, 0xbd, 0xe5, 0x1c, 0x5b, 0x9c, 0x45, 0x9d, 0x3f, 0xd9, 0x7b, 0x94,
+    0xd7, 0xc1, 0x3a, 0x7e, 0xc6, 0x7e, 0xf2, 0xbc, 0x74, 0xff, 0xfb, 0xdf,
+    0x5a, 0xf7, 0x90, 0x41, 0xd4, 0x75, 0xe1, 0x53, 0xdc, 0xfb, 0xbf, 0x8e,
+    0x9d, 0xb3, 0x0a, 0xe7, 0x46, 0xc8, 0xcb, 0xc2, 0xfb, 0x2b, 0x7e, 0x4b,
+    0x37, 0xb0, 0xe9, 0xf7, 0x53, 0x6a, 0x59, 0xa6, 0x13, 0x9e, 0xf7, 0xef,
+    0x46, 0x98, 0x4e, 0x60, 0x39, 0xa8, 0x13, 0x9f, 0xc3, 0x4a, 0x79, 0xfa,
+    0x03, 0x50, 0x27, 0x3f, 0xb5, 0x9c, 0x4d, 0x7f, 0xb1, 0xa6, 0x13, 0x9b,
+    0x02, 0x69, 0x84, 0xe6, 0x65, 0x93, 0xcc, 0x27, 0x18, 0x9a, 0x5e, 0xe6,
+    0x88, 0x5c, 0xb2, 0x2d, 0x1f, 0xde, 0x41, 0x64, 0x8a, 0x5e, 0x2c, 0xc2,
+    0x6b, 0x8f, 0x9e, 0x49, 0xba, 0x7e, 0xec, 0xc7, 0x8f, 0x0e, 0xb8, 0x5a,
+    0x87, 0xfc, 0x1a, 0xa2, 0x71, 0x45, 0xd4, 0x60, 0x5e, 0x94, 0x6b, 0x38,
+    0x40, 0xb3, 0xa7, 0xf9, 0xff, 0xf0, 0xa5, 0xef, 0xab, 0x3a, 0x70, 0xe6,
+    0xb0, 0xf5, 0xfa, 0x37, 0x38, 0x20, 0x60, 0xe8, 0x76, 0x42, 0xf6, 0xd0,
+    0x9e, 0x09, 0x0d, 0xa1, 0x4c, 0x84, 0x5d, 0x1d, 0xe4, 0x3c, 0xf4, 0x7d,
+    0xe9, 0xc7, 0x4b, 0xd0, 0xc7, 0xfa, 0x63, 0x3e, 0x0e, 0x75, 0x14, 0x3a,
+    0x7e, 0xe3, 0xfd, 0x1d, 0xc0, 0x74, 0xfc, 0xfe, 0xc6, 0x11, 0x67, 0x4f,
+    0xa9, 0xbe, 0xcb, 0x1d, 0x3e, 0x1c, 0xfb, 0x8c, 0x1d, 0x3f, 0xfb, 0x01,
+    0xae, 0x27, 0xcd, 0xda, 0xf9, 0xb1, 0xd3, 0xfd, 0xca, 0x5f, 0x11, 0xf7,
+    0x69, 0xd3, 0xf7, 0xd1, 0x6d, 0xfd, 0x6c, 0x74, 0x35, 0x16, 0xc8, 0x98,
+    0x03, 0x88, 0xd9, 0x35, 0xfe, 0x96, 0x09, 0x37, 0xa1, 0xbd, 0x3f, 0xec,
+    0xae, 0x30, 0x83, 0xcc, 0xdc, 0xe9, 0xe1, 0x7c, 0x64, 0xe8, 0x76, 0x60,
+    0xee, 0xc9, 0x81, 0x38, 0xca, 0x44, 0x4a, 0x42, 0xed, 0x5c, 0x9e, 0xa3,
+    0x8e, 0x14, 0x3b, 0xc7, 0xb3, 0xff, 0xc8, 0x38, 0xb7, 0xfa, 0x3f, 0xb4,
+    0x71, 0x67, 0x4f, 0xf7, 0x11, 0xbc, 0xa6, 0xa2, 0xce, 0x9f, 0xf6, 0x90,
+    0x77, 0x6f, 0x93, 0x48, 0x74, 0x61, 0xfa, 0x78, 0xde, 0x7d, 0xa5, 0xb8,
+    0x5c, 0xe8, 0x6a, 0x61, 0x2b, 0x86, 0x17, 0x88, 0x67, 0xfe, 0xea, 0xdf,
+    0x3d, 0xf4, 0x00, 0x7d, 0xce, 0x9f, 0xfb, 0x9a, 0xfb, 0xe4, 0x1f, 0xdb,
+    0x9a, 0x3a, 0x7f, 0xfe, 0xcd, 0xf3, 0x54, 0x3c, 0x47, 0xf7, 0x3f, 0xa5,
+    0x9d, 0x0e, 0x8e, 0x5a, 0x46, 0x14, 0x69, 0xf8, 0x7f, 0x5a, 0x71, 0xce,
+    0x9f, 0xff, 0x50, 0xfa, 0xab, 0x82, 0xfe, 0xd3, 0x39, 0xc3, 0xa7, 0xfd,
+    0xb5, 0x0e, 0xbd, 0xc4, 0x7d, 0x1d, 0x3b, 0xba, 0xd1, 0xe2, 0x03, 0x9f,
+    0xfd, 0xd7, 0xe3, 0xfc, 0xce, 0xda, 0xaa, 0xc6, 0x88, 0x0e, 0xe3, 0x53,
+    0x14, 0x8c, 0xdf, 0xac, 0xd0, 0x04, 0xd0, 0xfd, 0x18, 0xfc, 0x62, 0x73,
+    0x29, 0x1b, 0x7c, 0xee, 0x52, 0xb9, 0xd3, 0xce, 0x0b, 0xfc, 0x3a, 0x00,
+    0x78, 0x3e, 0x1e, 0x9e, 0x1f, 0x03, 0xf3, 0xa7, 0xcb, 0x56, 0x95, 0xa5,
+    0x69, 0x59, 0x3a, 0x7f, 0xfe, 0x6e, 0x69, 0x3b, 0xd4, 0x5f, 0xdf, 0x73,
+    0x19, 0xf1, 0xd1, 0x88, 0xbb, 0x42, 0x2a, 0x3c, 0x9f, 0xff, 0xea, 0x6e,
+    0x0b, 0x0d, 0xcd, 0xdb, 0xf5, 0xc1, 0x73, 0x2c, 0xb2, 0x54, 0x3a, 0x6e,
+    0xfc, 0x86, 0xe8, 0x96, 0xcf, 0x80, 0xfe, 0xc5, 0x73, 0xa7, 0xf3, 0xe7,
+    0x6d, 0x55, 0x63, 0x44, 0x13, 0x3f, 0xcf, 0xec, 0xed, 0xaa, 0xac, 0x68,
+    0xbe, 0x67, 0x0e, 0x68, 0x28, 0x80, 0xb1, 0xec, 0x90, 0x51, 0xb9, 0x7a,
+    0x15, 0x33, 0xfb, 0xfe, 0x5f, 0xf1, 0x2d, 0xc3, 0xa7, 0xfd, 0xb5, 0x6f,
+    0x7f, 0x9e, 0x1a, 0xbc, 0x74, 0xff, 0xb0, 0x2e, 0xd7, 0xe6, 0x02, 0x8e,
+    0x9c, 0xcb, 0x2c, 0x95, 0x3e, 0xe6, 0x5a, 0xba, 0x55, 0xc5, 0xfc, 0xff,
+    0xfe, 0x63, 0xaf, 0x7b, 0xe2, 0x95, 0xf3, 0xeb, 0x1a, 0xf9, 0x9b, 0xf8,
+    0xe8, 0xf2, 0x29, 0x7e, 0x9b, 0x46, 0xc9, 0xb3, 0xad, 0x0c, 0x61, 0xff,
+    0x3f, 0xe5, 0xbe, 0xfa, 0x1c, 0xdb, 0xeb, 0x4e, 0x9f, 0xca, 0x7c, 0x61,
+    0xaf, 0xdd, 0x1d, 0x1b, 0x1f, 0xc2, 0x20, 0xcf, 0xca, 0xf8, 0xde, 0x3f,
+    0x4e, 0x9f, 0xfd, 0xb8, 0xfc, 0xb7, 0x10, 0x00, 0x7e, 0xb4, 0xe8, 0x73,
+    0xfb, 0xfa, 0x5f, 0x3f, 0xef, 0xf4, 0xf8, 0x3e, 0xbe, 0x59, 0xb1, 0xd3,
+    0xff, 0xfd, 0xad, 0xb1, 0x91, 0xc0, 0xf5, 0x3f, 0xd8, 0x3c, 0x71, 0xd8,
+    0xe9, 0xcc, 0xb2, 0xc9, 0x53, 0xfb, 0xe8, 0x1c, 0x73, 0x7f, 0x15, 0x71,
+    0x7f, 0x3f, 0xff, 0x5f, 0x5f, 0x2d, 0xc4, 0x08, 0x71, 0x9f, 0x9e, 0xd6,
+    0x6c, 0x74, 0x71, 0x15, 0x5f, 0xa2, 0x42, 0x26, 0xad, 0x51, 0x99, 0x43,
+    0x57, 0x3f, 0x02, 0x5c, 0x91, 0xcf, 0x76, 0x15, 0xcb, 0x84, 0xe8, 0x91,
+    0xfa, 0x39, 0xa9, 0xff, 0x62, 0x0e, 0xd4, 0x3e, 0xc5, 0x9d, 0x3f, 0xee,
+    0x23, 0x21, 0xe6, 0x7a, 0xff, 0x0e, 0x9e, 0xcf, 0x30, 0xd3, 0xa7, 0xfe,
+    0x54, 0x2e, 0xab, 0x54, 0x3f, 0x41, 0xa3, 0xa3, 0x87, 0xd5, 0x44, 0x53,
+    0xfe, 0xcf, 0x3f, 0x75, 0xc7, 0x1f, 0x1e, 0x20, 0x89, 0xfc, 0xf9, 0xdb,
+    0x55, 0x58, 0xd1, 0x04, 0x5c, 0x79, 0x33, 0xf5, 0x73, 0xbd, 0x46, 0x4e,
+    0x9f, 0x95, 0xc2, 0xcd, 0x0b, 0x4e, 0x81, 0x3d, 0xdf, 0xcb, 0x63, 0x89,
+    0x9c, 0x01, 0xa8, 0x61, 0x59, 0x3f, 0x73, 0x3d, 0xe4, 0x59, 0xd3, 0xf7,
+    0xbe, 0xe7, 0x2b, 0x73, 0xa4, 0xfb, 0x9e, 0xd8, 0x96, 0x4c, 0xea, 0x1d,
+    0x3f, 0xec, 0xe3, 0xa7, 0x87, 0x38, 0x87, 0x4d, 0x4c, 0xfc, 0x3d, 0x0f,
+    0x0b, 0x43, 0x51, 0x4e, 0x2e, 0xf3, 0xfd, 0xc7, 0xef, 0x85, 0xf3, 0x73,
+    0xa7, 0xff, 0xf9, 0x36, 0x76, 0xeb, 0xbd, 0x4d, 0xd8, 0x6d, 0x75, 0x79,
+    0xb9, 0xd3, 0xde, 0xe6, 0x08, 0x51, 0x41, 0xc3, 0x79, 0xfb, 0xea, 0xf4,
+    0xcd, 0x6e, 0x74, 0x39, 0xf5, 0x78, 0xe6, 0x7c, 0xfd, 0xee, 0x70, 0xe9,
+    0xe4, 0x61, 0x19, 0x3a, 0x7f, 0xe5, 0xd6, 0xff, 0x7c, 0x9d, 0x7f, 0xef,
+    0xa3, 0xa7, 0xff, 0xdf, 0xec, 0x2f, 0x9c, 0xb9, 0xfd, 0x9c, 0xff, 0xa7,
+    0x4f, 0x7b, 0x5f, 0x74, 0x14, 0x62, 0xe1, 0x17, 0xd4, 0xc9, 0xf5, 0x34,
+    0x51, 0xce, 0x86, 0xa6, 0xb5, 0x90, 0xeb, 0x5a, 0x5c, 0xfd, 0x6e, 0x25,
+    0xfa, 0x28, 0x74, 0xff, 0xe4, 0x03, 0xe9, 0x6e, 0x9d, 0xea, 0x32, 0x74,
+    0xf2, 0xbf, 0x33, 0x63, 0xa7, 0xf3, 0x87, 0x3c, 0x9c, 0xfc, 0xe9, 0x2d,
+    0xcf, 0x5c, 0x24, 0xb3, 0xff, 0xfe, 0x5d, 0x08, 0x1a, 0x9a, 0xfd, 0x7c,
+    0x47, 0xf7, 0x3f, 0xa5, 0x9d, 0x37, 0xc5, 0x73, 0xa7, 0xff, 0xd4, 0x9e,
+    0x40, 0xe0, 0x73, 0xc8, 0xb4, 0xe9, 0xd3, 0xbb, 0x5a, 0xe9, 0xf6, 0x70,
+    0x6e, 0x64, 0xf5, 0x26, 0x17, 0xfc, 0x36, 0x20, 0x2a, 0x8d, 0x70, 0xc1,
+    0x21, 0x3f, 0x51, 0x99, 0x4f, 0xdd, 0x7d, 0x90, 0x7c, 0x74, 0xf8, 0x5c,
+    0x38, 0xc1, 0xd3, 0xda, 0xff, 0xaa, 0x1d, 0x3e, 0x7e, 0x79, 0xda, 0x74,
+    0xf0, 0x7f, 0xf6, 0x9c, 0xfc, 0x37, 0x26, 0x01, 0x24, 0xf8, 0x18, 0xb7,
+    0xe1, 0xd0, 0x14, 0xc2, 0x92, 0x13, 0x82, 0x91, 0x3b, 0xbf, 0x74, 0x74,
+    0xce, 0xad, 0xce, 0x9f, 0xf5, 0x0d, 0xb3, 0xb6, 0xaa, 0xb1, 0xa2, 0x11,
+    0x87, 0x44, 0x08, 0x07, 0xbf, 0x1b, 0x9f, 0xfc, 0xf9, 0xbf, 0xdf, 0x20,
+    0xfe, 0xdc, 0xd1, 0xd3, 0xfe, 0xfb, 0x9c, 0xa5, 0xdc, 0xcb, 0x2c, 0x9d,
+    0x3f, 0xfe, 0xcb, 0x71, 0xc4, 0x22, 0x9b, 0x60, 0xa2, 0x87, 0x4d, 0x55,
+    0xb2, 0x25, 0x9a, 0x89, 0x3f, 0xf7, 0xb8, 0x97, 0xb9, 0x4d, 0xeb, 0xa8,
+    0x74, 0xfd, 0x8c, 0xe0, 0xfe, 0x03, 0xa7, 0xcd, 0xcf, 0x38, 0x0e, 0x99,
+    0xd7, 0xb1, 0xe9, 0xee, 0x5b, 0x3f, 0xff, 0xf0, 0x17, 0x4d, 0xe5, 0x27,
+    0x90, 0x38, 0x1c, 0xf2, 0x2d, 0x3a, 0x74, 0x69, 0x13, 0xbf, 0x97, 0xcf,
+    0xb6, 0x5b, 0x85, 0xce, 0x80, 0xaa, 0x90, 0x62, 0x1c, 0x3c, 0x2e, 0xf4,
+    0x66, 0xdf, 0x49, 0x27, 0xf8, 0x2f, 0xad, 0x3e, 0xd8, 0xc9, 0xd1, 0x88,
+    0x93, 0xa5, 0xa9, 0xcc, 0xb2, 0xc9, 0x53, 0xfd, 0x80, 0xae, 0xe5, 0xec,
+    0x09, 0x57, 0x17, 0xf3, 0x32, 0xc9, 0x53, 0x99, 0x65, 0x92, 0xa7, 0xea,
+    0xd8, 0x3c, 0x7d, 0x15, 0x71, 0x7f, 0x02, 0x8b, 0xc6, 0x52, 0x2f, 0xcd,
+    0xe7, 0xd6, 0x40, 0xfd, 0x59, 0x57, 0x1b, 0x39, 0xcc, 0xb2, 0xc9, 0x53,
+    0xb4, 0xfd, 0x2a, 0xe2, 0xfe, 0x40, 0x44, 0x42, 0x79, 0x66, 0x7e, 0x08,
+    0xbb, 0x6a, 0xc7, 0x4f, 0x82, 0x97, 0x9c, 0x27, 0x4f, 0x60, 0xe2, 0xb9,
+    0xd2, 0xfb, 0xd3, 0xca, 0x59, 0x44, 0xff, 0xdc, 0xa6, 0x8d, 0x28, 0xc0,
+    0xa3, 0x07, 0x4f, 0xdc, 0xcb, 0xd9, 0xed, 0x1d, 0x16, 0x3f, 0x2f, 0x22,
+    0x47, 0x53, 0x33, 0xe3, 0xa8, 0xc2, 0x72, 0x1d, 0x39, 0x0c, 0x8d, 0x6e,
+    0x76, 0xea, 0xd8, 0xac, 0x9d, 0x3f, 0xfb, 0x15, 0xe8, 0x41, 0x96, 0x7e,
+    0x3a, 0xce, 0x9f, 0xac, 0x9a, 0xe2, 0x30, 0x54, 0xfe, 0x1c, 0xdd, 0xba,
+    0x45, 0x0e, 0x9e, 0xaa, 0xea, 0x87, 0x47, 0xc3, 0xd4, 0xd8, 0xce, 0x79,
+    0xe9, 0x77, 0x8a, 0x9f, 0xb9, 0x8b, 0x5d, 0x34, 0xe9, 0xcc, 0xb2, 0xc9,
+    0x53, 0xf8, 0x7d, 0xc4, 0x71, 0xd8, 0xab, 0x8b, 0xf9, 0xef, 0xae, 0x0c,
+    0x6a, 0x23, 0x31, 0x2e, 0x59, 0x64, 0x74, 0x2e, 0x15, 0xd3, 0xf9, 0xfe,
+    0xf7, 0xa9, 0xed, 0x1d, 0x0e, 0xa9, 0x85, 0xa5, 0x3b, 0xa4, 0xa4, 0x20,
+    0x79, 0x18, 0x68, 0x96, 0xcf, 0x81, 0x89, 0xc5, 0x0e, 0x9f, 0xfe, 0xcb,
+    0x38, 0xd7, 0xb4, 0x1f, 0xeb, 0xad, 0x3a, 0x37, 0x3f, 0x55, 0x93, 0xce,
+    0xb3, 0xe8, 0xe9, 0xff, 0xbe, 0xb7, 0x39, 0x5c, 0x4e, 0xf5, 0xce, 0x8c,
+    0x3d, 0xf0, 0x0d, 0xcf, 0x9f, 0xda, 0xbd, 0x87, 0x4f, 0xbf, 0xea, 0x9c,
+    0x43, 0xa1, 0xd1, 0xe8, 0x30, 0x82, 0xf1, 0x0d, 0xf9, 0x44, 0xff, 0xf2,
+    0x5e, 0xc1, 0x08, 0xd3, 0x38, 0x34, 0xa1, 0xd3, 0xff, 0xfc, 0x1e, 0x23,
+    0x38, 0xa9, 0x17, 0x5e, 0xd7, 0xed, 0xcd, 0xfc, 0x74, 0x62, 0x2e, 0x29,
+    0x3a, 0x1d, 0xd0, 0xdd, 0x6d, 0x18, 0xdb, 0x63, 0xc6, 0x0c, 0x7c, 0x19,
+    0x3c, 0x18, 0xa3, 0xdd, 0x8e, 0xd2, 0x3e, 0x36, 0x23, 0x37, 0xec, 0x65,
+    0x8b, 0x8d, 0xef, 0x92, 0x9a, 0xaa, 0x35, 0x10, 0x42, 0xd4, 0x65, 0xa9,
+    0xea, 0x5a, 0x1f, 0xa5, 0x44, 0xff, 0x1e, 0x5b, 0x30, 0xfb, 0x9d, 0x79,
+    0xc4, 0xe9, 0xff, 0xec, 0x1b, 0xbc, 0xa2, 0x6f, 0xae, 0x60, 0x28, 0xe8,
+    0x69, 0xf6, 0x04, 0x72, 0x7f, 0x50, 0xdb, 0x3d, 0xc4, 0x3a, 0x37, 0x3d,
+    0x25, 0x91, 0x4c, 0xad, 0xaa, 0xdc, 0xe9, 0xce, 0x3b, 0x1d, 0x3c, 0x9c,
+    0x45, 0x9d, 0x2e, 0x21, 0xbb, 0x60, 0x6e, 0x7f, 0xc2, 0xfe, 0xe5, 0x02,
+    0xb7, 0xd1, 0xd3, 0x98, 0xff, 0xa7, 0x4f, 0xfa, 0x93, 0xb9, 0xbd, 0xcc,
+    0xb2, 0xc9, 0xd1, 0x47, 0xc1, 0xa1, 0xe9, 0xff, 0xe1, 0x76, 0xfc, 0xfb,
+    0xe4, 0x1f, 0xdb, 0x9a, 0x3a, 0x31, 0x33, 0x7b, 0x13, 0xf2, 0x13, 0xa0,
+    0x21, 0x9f, 0xce, 0x2d, 0x1c, 0xc0, 0x1d, 0x3f, 0x67, 0x74, 0x2f, 0xb1,
+    0xd3, 0xf5, 0x7b, 0x94, 0x20, 0x3a, 0x7f, 0xd5, 0xec, 0x62, 0x9c, 0x5d,
+    0x83, 0xa4, 0x9d, 0x3e, 0x7e, 0x15, 0xc3, 0x51, 0x75, 0x68, 0x49, 0xcf,
+    0xff, 0x67, 0x9c, 0x6d, 0x9e, 0xe2, 0x74, 0x16, 0x3a, 0x7f, 0x3a, 0xf5,
+    0xaa, 0x1d, 0x8e, 0x9f, 0x56, 0xb0, 0x7c, 0x74, 0xef, 0x52, 0xb9, 0xd3,
+    0xfb, 0xdc, 0x4b, 0x81, 0x48, 0x74, 0x05, 0x1e, 0x9c, 0x4d, 0x13, 0x2f,
+    0x12, 0xfe, 0x3d, 0x3f, 0xbf, 0x03, 0xf1, 0x29, 0xa7, 0x4f, 0xf5, 0xb3,
+    0xcf, 0x79, 0x04, 0x07, 0x4f, 0xff, 0xdf, 0xbf, 0xb5, 0x83, 0xf3, 0xae,
+    0x81, 0x1a, 0x69, 0xd0, 0x88, 0x92, 0x13, 0x89, 0xff, 0xf8, 0x73, 0x5f,
+    0xfc, 0xce, 0x50, 0xe3, 0x0d, 0x7d, 0xce, 0x9f, 0xf6, 0x6b, 0xfc, 0xed,
+    0xaa, 0xac, 0x68, 0x81, 0xa7, 0xbd, 0xca, 0x6f, 0xc4, 0x53, 0x0a, 0xe4,
+    0xff, 0x08, 0x3c, 0x9b, 0x2d, 0xec, 0x74, 0xf8, 0x37, 0xc5, 0x06, 0xf8,
+    0x3a, 0x1d, 0x36, 0xbc, 0x86, 0x3a, 0x1d, 0xd1, 0xc4, 0xfe, 0xcd, 0xfc,
+    0x1c, 0xc5, 0x0e, 0x9f, 0xb3, 0xce, 0x28, 0x03, 0xa7, 0xfd, 0x5d, 0xc1,
+    0x06, 0xbd, 0xad, 0xce, 0x9f, 0xff, 0xff, 0xb3, 0xdc, 0xa1, 0x53, 0xe6,
+    0xbb, 0x55, 0xeb, 0xd8, 0x1f, 0x98, 0xba, 0x1d, 0xda, 0x78, 0x82, 0xe7,
+    0xfd, 0x54, 0xa5, 0xa8, 0x3f, 0x14, 0x64, 0xf1, 0x05, 0xcf, 0xfd, 0xc4,
+    0xe2, 0x38, 0xfb, 0xe2, 0x8c, 0x9e, 0x20, 0xb9, 0xfc, 0xe8, 0x3e, 0xf8,
+    0xa3, 0x27, 0x88, 0x2e, 0x7e, 0x5e, 0x07, 0xe2, 0x8c, 0x9e, 0x20, 0xb9,
+    0xff, 0xfe, 0xa1, 0x14, 0x5f, 0xcd, 0x5b, 0x89, 0xd4, 0x53, 0x6c, 0x64,
+    0xf1, 0x05, 0xcd, 0xbf, 0xc0, 0xa7, 0x2f, 0x64, 0xfe, 0xa9, 0xd2, 0x10,
+    0x9f, 0x43, 0xaa, 0xc7, 0xe1, 0xf0, 0xca, 0x31, 0x9f, 0xc8, 0xea, 0x6b,
+    0xda, 0xdc, 0xe9, 0xea, 0xe8, 0x28, 0xe9, 0xff, 0xb8, 0x9c, 0x47, 0x1f,
+    0x7c, 0x51, 0x93, 0xc4, 0x17, 0x3f, 0xcc, 0x6a, 0xc9, 0xb7, 0xc5, 0x19,
+    0x3c, 0x41, 0x73, 0xef, 0x69, 0xd7, 0xf2, 0xc8, 0x9f, 0xfa, 0xa7, 0x3f,
+    0xfb, 0xe5, 0xb8, 0x96, 0x7f, 0x6b, 0xe2, 0x8c, 0x9e, 0x20, 0xb9, 0xff,
+    0xff, 0x84, 0x51, 0x7f, 0x3f, 0xcf, 0x9a, 0xb7, 0x13, 0xa8, 0xa6, 0xd8,
+    0xc9, 0xe2, 0x0b, 0x8c, 0x4c, 0x97, 0x74, 0x4a, 0x5d, 0x9f, 0xee, 0x27,
+    0x51, 0x4d, 0xb1, 0x93, 0xc4, 0x17, 0x3f, 0xfd, 0x55, 0xbb, 0x75, 0xc4,
+    0x08, 0x5f, 0xae, 0x54, 0xff, 0xb1, 0xad, 0xff, 0x5d, 0x1d, 0xaf, 0xcf,
+    0x10, 0x5c, 0x59, 0x1c, 0xbd, 0x47, 0xd2, 0x74, 0xff, 0xac, 0x9d, 0xf5,
+    0x03, 0x5f, 0x19, 0x3c, 0x41, 0x73, 0xf7, 0x13, 0x9c, 0x40, 0x1a, 0x00,
+    0xb9, 0xf6, 0x03, 0xe2, 0x8c, 0x9e, 0x20, 0xb9, 0xb3, 0xd6, 0x3f, 0x1e,
+    0x1c, 0xc6, 0xe8, 0xec, 0xd4, 0x2f, 0xe7, 0xe5, 0xe0, 0x7e, 0x28, 0xc9,
+    0xe2, 0x0b, 0x9f, 0xf5, 0xb8, 0x9d, 0x45, 0x36, 0xc6, 0x4f, 0x10, 0x5c,
+    0xd9, 0xf2, 0x91, 0x17, 0xa3, 0xe9, 0xfd, 0xfa, 0x2e, 0x87, 0x76, 0x9e,
+    0x20, 0xb9, 0xff, 0x62, 0x5e, 0xc1, 0xc0, 0xd3, 0x4f, 0x10, 0x5a, 0xcf,
+    0x02, 0x02, 0xbb, 0xfb, 0xd3, 0x70, 0x1a, 0x0c, 0x7c, 0x9a, 0x8c, 0x57,
+    0xd1, 0x8e, 0x7f, 0x0b, 0x46, 0x5b, 0xe6, 0x03, 0x9a, 0x20, 0xbb, 0x91,
+    0x19, 0x35, 0x58, 0xe9, 0x68, 0x07, 0x95, 0xe3, 0x58, 0xd9, 0x94, 0x3e,
+    0x13, 0x30, 0x52, 0x71, 0x27, 0xfd, 0x8d, 0xe5, 0x35, 0x52, 0xaf, 0xf6,
+    0x3a, 0x7e, 0xa6, 0xbd, 0xea, 0xe1, 0xd3, 0xdb, 0xe9, 0xf7, 0x3a, 0x72,
+    0xdd, 0xa7, 0x4f, 0xb0, 0x3c, 0xfd, 0x93, 0xa3, 0xe1, 0xf3, 0xd1, 0x18,
+    0x8d, 0xce, 0x0d, 0x78, 0xe8, 0xe9, 0xe5, 0x51, 0x7c, 0xe4, 0xbf, 0xc3,
+    0xa7, 0x57, 0x40, 0x74, 0xb7, 0x73, 0x71, 0xe1, 0xd9, 0xe5, 0x3a, 0x8c,
+    0x9d, 0x3e, 0xda, 0xb8, 0xea, 0xe7, 0x42, 0xb2, 0x79, 0xb8, 0x47, 0x0e,
+    0x9e, 0x8a, 0x43, 0x7a, 0x96, 0x45, 0xd2, 0x7f, 0xfb, 0x04, 0x5f, 0x65,
+    0xf1, 0x3b, 0xda, 0x69, 0xd3, 0xab, 0xbb, 0x1d, 0x30, 0x1c, 0xe9, 0xe4,
+    0x75, 0xe1, 0xd0, 0x74, 0xfd, 0x4a, 0x79, 0xfa, 0x03, 0xa0, 0x26, 0xdc,
+    0x42, 0xa7, 0xff, 0xf3, 0xa0, 0x45, 0xff, 0xb7, 0xb2, 0xc1, 0x7b, 0x7d,
+    0x59, 0xd3, 0x01, 0xce, 0x99, 0xd4, 0x3a, 0x7f, 0xb3, 0xda, 0x75, 0xfd,
+    0xc6, 0x0e, 0x9f, 0xda, 0xce, 0x26, 0xbf, 0xd8, 0xe9, 0x99, 0x64, 0xa9,
+    0xfe, 0x1c, 0xbd, 0x4d, 0xd2, 0x04, 0xe8, 0xb2, 0x7e, 0x28, 0x39, 0xd1,
+    0x55, 0xab, 0x70, 0x80, 0x0c, 0x37, 0xd0, 0xa8, 0x8b, 0x68, 0xe9, 0x93,
+    0x4f, 0xa3, 0x13, 0x99, 0x65, 0x92, 0xa4, 0xb2, 0xae, 0x2f, 0xe7, 0xd4,
+    0xc5, 0x57, 0x4a, 0xb9, 0x1b, 0xdf, 0x61, 0x7d, 0x3f, 0xb7, 0xf3, 0xe7,
+    0x33, 0x63, 0xa1, 0xdb, 0x70, 0x46, 0x91, 0xe4, 0x72, 0xaa, 0x21, 0x6f,
+    0x0e, 0x94, 0x8c, 0x73, 0xa9, 0x5c, 0x94, 0x5f, 0x54, 0xa5, 0xe1, 0x3e,
+    0xd4, 0xa1, 0x5f, 0x1f, 0xff, 0x2c, 0x72, 0xf2, 0x6c, 0xea, 0xb6, 0x1d,
+    0x36, 0x32, 0x74, 0xcf, 0xe3, 0xa3, 0x63, 0x57, 0x61, 0x69, 0x2c, 0xe8,
+    0xc3, 0x65, 0xe2, 0x29, 0xf9, 0x6f, 0xb7, 0xb2, 0xc7, 0x4f, 0x62, 0xf3,
+    0xc7, 0x4f, 0xff, 0xfd, 0x6a, 0x63, 0xf6, 0xff, 0x6f, 0x9c, 0x4f, 0x79,
+    0xf7, 0x7d, 0x9f, 0x47, 0x4f, 0xff, 0xf2, 0xb8, 0xd5, 0x5e, 0x76, 0xf1,
+    0xfb, 0xb3, 0xfb, 0x54, 0xd3, 0xa7, 0x26, 0xec, 0x1d, 0x3e, 0xcc, 0xdb,
+    0xfd, 0x1d, 0x3f, 0xf7, 0x3f, 0xdb, 0xfb, 0xb8, 0x96, 0xae, 0x9d, 0x3f,
+    0xdc, 0xad, 0x71, 0x36, 0xa1, 0x3a, 0x7a, 0xb6, 0xfa, 0xd3, 0xa2, 0xfb,
+    0x55, 0x5a, 0xee, 0xfb, 0x10, 0x6e, 0x5b, 0xd2, 0x0a, 0x78, 0x03, 0x4e,
+    0x87, 0x7c, 0x51, 0xf5, 0x21, 0x51, 0xbc, 0xfc, 0x3f, 0x85, 0x74, 0xd3,
+    0xa7, 0xff, 0x34, 0x5f, 0xe2, 0xc5, 0xd4, 0xf2, 0x6c, 0x74, 0xfa, 0x97,
+    0x9c, 0x59, 0xd1, 0xb9, 0xf8, 0xf9, 0x2e, 0x77, 0xba, 0xe7, 0x4f, 0xed,
+    0x7a, 0xf6, 0x0e, 0x04, 0xe8, 0x74, 0xc3, 0xd2, 0x13, 0xcb, 0x23, 0xa1,
+    0xb9, 0xd5, 0xf3, 0xe9, 0xd3, 0xcb, 0x5b, 0xac, 0xe9, 0xff, 0xe1, 0x6f,
+    0xcc, 0x0a, 0x6b, 0x7f, 0x7f, 0x5a, 0x3a, 0x7c, 0xa6, 0xb4, 0x8c, 0x1d,
+    0x3f, 0xf5, 0x6c, 0x2f, 0xba, 0x04, 0x5f, 0x63, 0xa3, 0xa7, 0xd8, 0x25,
+    0x33, 0xef, 0x9c, 0x7e, 0xb4, 0xe8, 0xf8, 0x9a, 0x43, 0x8f, 0xe1, 0x0d,
+    0x42, 0xf9, 0x92, 0x19, 0xfb, 0x66, 0x1b, 0x7d, 0xf7, 0x63, 0xa7, 0x97,
+    0x95, 0xc3, 0xa6, 0x6e, 0xc7, 0x4f, 0xb9, 0x88, 0xdd, 0x1d, 0x3f, 0xfd,
+    0xc7, 0xfb, 0x77, 0x86, 0x81, 0xad, 0x38, 0x0a, 0x9f, 0xc0, 0xce, 0xda,
+    0xaa, 0xc7, 0x88, 0x12, 0x77, 0x93, 0x63, 0xa7, 0x6d, 0x42, 0x74, 0x35,
+    0x1d, 0x81, 0x26, 0xea, 0x8a, 0xcf, 0xbc, 0x39, 0x3f, 0x0d, 0xa9, 0x4e,
+    0x21, 0xd3, 0x2a, 0x69, 0xd3, 0xde, 0xda, 0x84, 0xe9, 0xc3, 0x4a, 0x1d,
+    0x3d, 0xbe, 0xab, 0xc7, 0x46, 0xc7, 0xed, 0x83, 0x16, 0x21, 0xe0, 0xdc,
+    0xdd, 0xfc, 0xe9, 0xfc, 0x34, 0xce, 0xb4, 0xe0, 0x3a, 0x75, 0xfd, 0x28,
+    0x74, 0xff, 0x3a, 0xdb, 0x9b, 0x67, 0xf7, 0xd1, 0xd1, 0x87, 0xba, 0x83,
+    0xf3, 0x99, 0x65, 0x93, 0xd5, 0xf5, 0x3a, 0x84, 0x25, 0xab, 0xe9, 0x71,
+    0xac, 0x9f, 0x63, 0x7f, 0x75, 0x0e, 0x87, 0x4d, 0x4c, 0x22, 0xfd, 0x84,
+    0x78, 0x13, 0x3c, 0x73, 0x3f, 0xfe, 0xc1, 0x45, 0x2e, 0xd7, 0xb9, 0xfd,
+    0x35, 0xae, 0x74, 0x6c, 0x8a, 0x55, 0x13, 0xe7, 0xb0, 0x34, 0xd3, 0xa7,
+    0xd4, 0x22, 0x8b, 0x3a, 0x7f, 0xb8, 0x9d, 0xc4, 0x5b, 0xab, 0x9d, 0x3e,
+    0x45, 0xd0, 0xe1, 0xd0, 0xad, 0x2e, 0x9f, 0xb9, 0xb3, 0x48, 0x32, 0x30,
+    0x35, 0x12, 0x92, 0x14, 0x55, 0x28, 0xd0, 0x04, 0xa2, 0x41, 0xf9, 0x25,
+    0xf9, 0xcc, 0xf9, 0x3c, 0xfe, 0xd1, 0x53, 0xd6, 0x7f, 0x68, 0xa9, 0x99,
+    0x64, 0xa8, 0x69, 0xef, 0xe1, 0x33, 0x24, 0x33, 0x63, 0x25, 0x5c, 0x6b,
+    0xe7, 0xff, 0xd9, 0xe7, 0xb6, 0x60, 0xfb, 0x88, 0xe3, 0xb1, 0xd0, 0x03,
+    0xf8, 0x64, 0x9e, 0x7f, 0xff, 0x3d, 0xe4, 0x10, 0x7c, 0xf6, 0xb2, 0xdc,
+    0xa1, 0xf6, 0x8e, 0x9f, 0x37, 0x9f, 0xbf, 0x4e, 0x9f, 0xfa, 0x97, 0xd7,
+    0xbc, 0x97, 0x87, 0xfd, 0x1d, 0x1b, 0x9f, 0x7f, 0x0a, 0x27, 0xd9, 0xfa,
+    0xdf, 0x47, 0x41, 0xd3, 0xb3, 0x18, 0xe9, 0xb1, 0xd1, 0x3c, 0x30, 0x88,
+    0x6e, 0xaa, 0x4e, 0x6d, 0x74, 0xe9, 0xf3, 0x73, 0xd8, 0x12, 0xa7, 0x9c,
+    0x45, 0xce, 0x92, 0x30, 0x7b, 0xfe, 0x1b, 0xfa, 0x4d, 0x3f, 0xc3, 0x9c,
+    0xcf, 0x9c, 0xcd, 0x8e, 0x9f, 0xbf, 0xbe, 0x93, 0xbd, 0xc3, 0xa7, 0xbc,
+    0xa6, 0x70, 0xe9, 0xf8, 0x1f, 0xeb, 0xe2, 0x00, 0xe9, 0x80, 0xe7, 0x4c,
+    0x07, 0x3a, 0x7d, 0xfb, 0x70, 0x6e, 0x43, 0x54, 0x01, 0x58, 0x74, 0x5d,
+    0x00, 0x88, 0x56, 0xa7, 0xff, 0xb0, 0x6b, 0x7d, 0x28, 0xa5, 0x7c, 0xb2,
+    0xc0, 0x74, 0xff, 0xde, 0xe6, 0x2f, 0xeb, 0x83, 0x37, 0xf1, 0xd3, 0xfb,
+    0x7b, 0x27, 0x7e, 0xb8, 0x4e, 0x9e, 0x02, 0xe9, 0xbf, 0x11, 0x9d, 0xa5,
+    0x3f, 0x23, 0x4f, 0xc0, 0x5f, 0xdd, 0x7d, 0xd8, 0xe9, 0xb3, 0x73, 0xa3,
+    0x73, 0xc9, 0xbf, 0x33, 0x9e, 0x07, 0x53, 0xa7, 0x43, 0xa3, 0x66, 0xa1,
+    0x24, 0xc9, 0x34, 0xf6, 0xbf, 0xdf, 0xc7, 0x4e, 0xee, 0x32, 0x74, 0xff,
+    0x98, 0x7d, 0xb5, 0xdc, 0xb3, 0xec, 0x74, 0xfe, 0x5e, 0x2f, 0x02, 0x8c,
+    0x9d, 0x3f, 0x0e, 0x31, 0xc4, 0xf1, 0xd3, 0xd9, 0x9c, 0xd1, 0xd1, 0x88,
+    0xbe, 0xa4, 0x0f, 0x19, 0x2a, 0x2c, 0x9c, 0xcb, 0x2c, 0x95, 0x3e, 0xc5,
+    0x07, 0xfd, 0x15, 0x71, 0x7f, 0x3e, 0xcb, 0x99, 0x65, 0x93, 0xa1, 0xcf,
+    0x8f, 0xc7, 0x13, 0xfe, 0x1c, 0xd5, 0xb8, 0x96, 0x71, 0x3a, 0x7f, 0xff,
+    0x28, 0xcd, 0x75, 0x4b, 0xb5, 0x8d, 0x1f, 0xeb, 0x58, 0x27, 0x46, 0x22,
+    0x79, 0x0e, 0xe7, 0x99, 0xa1, 0x69, 0xd3, 0xfd, 0xe7, 0xdc, 0x15, 0xce,
+    0x21, 0xd2, 0xe1, 0xd1, 0x87, 0x91, 0x63, 0x89, 0xcc, 0xb2, 0xc9, 0x53,
+    0xf2, 0x52, 0x9c, 0x4f, 0x15, 0x71, 0x7f, 0x3d, 0x5c, 0x70, 0x9d, 0x3e,
+    0xc0, 0x66, 0x30, 0x74, 0xb5, 0xf1, 0x18, 0x5d, 0x40, 0xe1, 0xe0, 0x90,
+    0x4d, 0xfb, 0x42, 0x9b, 0x7e, 0x46, 0x57, 0x3e, 0xbe, 0xb8, 0xfb, 0x7e,
+    0x74, 0x93, 0x89, 0xfa, 0x0c, 0x72, 0x1f, 0x9b, 0x4f, 0x57, 0x53, 0x87,
+    0x4f, 0xe7, 0x16, 0x8a, 0x3e, 0xe7, 0x43, 0xb2, 0x97, 0x9a, 0x47, 0x91,
+    0xab, 0xa9, 0x08, 0x3b, 0x1b, 0xa1, 0xcf, 0x61, 0xd9, 0xc8, 0xf5, 0x68,
+    0xd0, 0x04, 0x83, 0x0d, 0xad, 0x42, 0xff, 0xd2, 0xac, 0xef, 0xcf, 0x15,
+    0x10, 0x4c, 0xac, 0xa1, 0xd3, 0xf3, 0xaf, 0xbd, 0xaf, 0x1d, 0x3f, 0xfa,
+    0xcc, 0x55, 0xb8, 0xed, 0xf0, 0xe2, 0xce, 0x9f, 0xfe, 0x45, 0xee, 0xdd,
+    0x7c, 0xc1, 0x1c, 0x40, 0x1d, 0x39, 0x39, 0xf9, 0xd0, 0xad, 0x23, 0xeb,
+    0x83, 0x54, 0x59, 0xe4, 0x9b, 0xc9, 0xf2, 0xba, 0xf9, 0x87, 0xf1, 0x1d,
+    0xf1, 0x0d, 0x65, 0x6e, 0x90, 0xad, 0xb0, 0xd2, 0x56, 0x25, 0x0f, 0x3e,
+    0x67, 0xb4, 0xaf, 0x46, 0xce, 0x72, 0x86, 0x76, 0xe7, 0x2d, 0x4b, 0x1a,
+    0x92, 0x95, 0xed, 0x3d, 0xbb, 0xbc, 0xf3, 0x12, 0x4f, 0x28, 0x31, 0x49,
+    0xd2, 0xed, 0x29, 0x5d, 0x73, 0x8a, 0x7c, 0xa7, 0x8c, 0x55, 0x6b, 0xce,
+    0x09, 0xd8, 0x1b, 0xea, 0x15, 0x63, 0x4d, 0x0f, 0xd5, 0xa3, 0x5a, 0xf5,
+    0x72, 0x59, 0xfc, 0xba, 0x0b, 0xd1, 0xd9, 0x33, 0x1c, 0x45, 0xfc, 0xec,
+    0x7f, 0xda, 0x60, 0xb2, 0xa8, 0xfc, 0xa2, 0xe8, 0xc0, 0x5f, 0x5b, 0x8f,
+    0xed, 0xe9, 0xf5, 0xc0, 0x5e, 0x78, 0xe9, 0xfd, 0x76, 0x76, 0xd5, 0x56,
+    0x34, 0x5c, 0x73, 0xfa, 0xec, 0xed, 0xaa, 0xac, 0x68, 0xba, 0xe7, 0xfe,
+    0xba, 0x9b, 0x76, 0x76, 0xd5, 0x56, 0x34, 0x4a, 0x30, 0xf1, 0x82, 0xea,
+    0x34, 0xe4, 0x27, 0xea, 0x42, 0x3e, 0xc5, 0x09, 0x1a, 0x0a, 0xba, 0xfd,
+    0x66, 0x03, 0xa8, 0x03, 0xad, 0x14, 0x78, 0xfd, 0x51, 0xfc, 0xff, 0xeb,
+    0x97, 0x4d, 0xbb, 0x3b, 0x6a, 0xab, 0x1a, 0x25, 0xa9, 0xf7, 0x6d, 0x55,
+    0x63, 0x44, 0x6f, 0x3f, 0xea, 0x6d, 0xd9, 0xdb, 0x55, 0x58, 0xd1, 0x2f,
+    0xcf, 0xcf, 0xef, 0xbc, 0xaf, 0x1d, 0x2b, 0xb1, 0x15, 0x6b, 0x33, 0xe2,
+    0x54, 0xfe, 0xbb, 0x3b, 0x6a, 0xab, 0x1a, 0x2a, 0xb9, 0x91, 0x51, 0xd3,
+    0xc8, 0xba, 0xbc, 0x74, 0x28, 0x6e, 0x7c, 0x2f, 0x38, 0x55, 0x32, 0x74,
+    0xfd, 0x5c, 0x60, 0x5c, 0x27, 0x4e, 0x76, 0xe1, 0xd0, 0x13, 0xc6, 0x60,
+    0xb2, 0x7f, 0x94, 0xc1, 0xcd, 0xfd, 0x4b, 0x3a, 0x60, 0xa1, 0xd3, 0xf6,
+    0x76, 0xd5, 0x56, 0x34, 0x48, 0x11, 0xf0, 0xf3, 0x6e, 0x15, 0x9f, 0x6a,
+    0x86, 0xb7, 0x3a, 0x1a, 0x79, 0x7b, 0x92, 0xcf, 0xe6, 0xbf, 0x76, 0x7e,
+    0xec, 0x74, 0xfe, 0xee, 0xcb, 0x71, 0x6e, 0x8e, 0x87, 0x3e, 0x7c, 0x34,
+    0x9f, 0xfd, 0x8c, 0x72, 0x97, 0xee, 0x3f, 0xbf, 0x59, 0xd1, 0xb2, 0xa6,
+    0xe0, 0x91, 0x63, 0x22, 0x84, 0x75, 0x0d, 0x01, 0x84, 0x57, 0xd2, 0x09,
+    0xff, 0x87, 0x36, 0xba, 0xfd, 0xc4, 0x73, 0xc7, 0x45, 0xc8, 0xb6, 0xeb,
+    0x8c, 0xfe, 0xbb, 0x3b, 0x6a, 0xab, 0x1a, 0x2c, 0x89, 0xfd, 0x76, 0x76,
+    0xd5, 0x56, 0x34, 0x5a, 0xf3, 0xfa, 0xec, 0xed, 0xaa, 0xac, 0x68, 0xb9,
+    0x27, 0xdd, 0xb5, 0x55, 0x8d, 0x17, 0x64, 0xff, 0xa9, 0xb7, 0x67, 0x6d,
+    0x55, 0x63, 0x45, 0x1d, 0x2b, 0xb0, 0xff, 0x56, 0x67, 0x3c, 0x2e, 0xd5,
+    0x9d, 0x26, 0x9d, 0x3e, 0xed, 0xaa, 0xac, 0x68, 0xa5, 0x67, 0xfa, 0xdc,
+    0x46, 0x38, 0xfb, 0x61, 0xd3, 0xff, 0xb8, 0xfb, 0x3f, 0x12, 0xf5, 0x07,
+    0x88, 0x75, 0xc6, 0xe6, 0x66, 0xdd, 0x88, 0xc7, 0x61, 0xb2, 0x37, 0x4c,
+    0x1e, 0xa1, 0xaf, 0x2b, 0x82, 0x9a, 0x82, 0xe3, 0x27, 0x8d, 0x97, 0xf6,
+    0xdb, 0x18, 0x16, 0xe6, 0xc9, 0x2e, 0x71, 0x64, 0x80, 0x3f, 0xd1, 0xff,
+    0xa1, 0x79, 0x7a, 0x37, 0x89, 0xfe, 0x6d, 0xd9, 0xdb, 0x55, 0x58, 0xd1,
+    0x1c, 0x4f, 0xf2, 0x5d, 0x9d, 0xb5, 0x55, 0x8d, 0x15, 0xac, 0xae, 0xa4,
+    0x44, 0xf9, 0x16, 0x7f, 0xf5, 0xcb, 0xa6, 0xdd, 0x9d, 0xb5, 0x55, 0x8d,
+    0x12, 0xdc, 0xd9, 0xb9, 0xd3, 0xf8, 0x38, 0xb5, 0xba, 0x68, 0xe8, 0xdc,
+    0xf1, 0xd0, 0x5a, 0x77, 0x02, 0xd3, 0xa7, 0xfb, 0x37, 0x1c, 0x00, 0x29,
+    0xa7, 0x4c, 0xbb, 0x1d, 0x0e, 0x79, 0xad, 0x37, 0x9f, 0xff, 0xb9, 0x5b,
+    0x80, 0x3c, 0xa6, 0xe6, 0x87, 0xfa, 0xfa, 0x74, 0xfc, 0x9d, 0x14, 0xf6,
+    0x8e, 0x9f, 0x76, 0x87, 0x1c, 0xe8, 0x34, 0x43, 0x7c, 0x3c, 0xfa, 0x2b,
+    0x9f, 0xcd, 0x41, 0x0e, 0x20, 0x4e, 0x9f, 0xf5, 0x36, 0xec, 0xed, 0xaa,
+    0xac, 0x68, 0x98, 0x27, 0xc0, 0xd5, 0x08, 0x0e, 0x9f, 0xfd, 0x9e, 0xbf,
+    0x7d, 0xbc, 0x2f, 0xff, 0xb4, 0x74, 0xfe, 0xd2, 0x71, 0x17, 0x8a, 0x1d,
+    0x3f, 0xfa, 0xb6, 0xe2, 0x38, 0xe3, 0x09, 0xd4, 0x3a, 0x3c, 0x7f, 0x2c,
+    0x99, 0x4d, 0x6c, 0x3a, 0x6f, 0xc0, 0x54, 0x21, 0xac, 0xe8, 0xac, 0xfe,
+    0xc0, 0x8e, 0x7b, 0x98, 0x74, 0xfd, 0xb7, 0xdb, 0xfa, 0x10, 0x1d, 0x3f,
+    0x67, 0xbc, 0xfd, 0xd1, 0xd3, 0xf5, 0x08, 0x36, 0x07, 0x8e, 0x87, 0x44,
+    0x58, 0x99, 0x5f, 0x96, 0x4a, 0xe7, 0x5c, 0x4d, 0xd8, 0x88, 0x2d, 0x38,
+    0x43, 0x68, 0x56, 0x6e, 0x68, 0xb3, 0x0a, 0x4a, 0x12, 0x6d, 0x43, 0x1b,
+    0xc9, 0xf7, 0x88, 0x3e, 0xc2, 0xee, 0x72, 0xff, 0xe9, 0x53, 0xfe, 0xa6,
+    0xdd, 0x9d, 0xb5, 0x55, 0x8d, 0x13, 0x1c, 0xf3, 0xf5, 0xd5, 0x1d, 0x2b,
+    0x91, 0x11, 0x2b, 0x1d, 0xe2, 0x54, 0xf9, 0x1f, 0x67, 0xe9, 0xd3, 0xf3,
+    0xeb, 0xe7, 0xb3, 0x87, 0x4e, 0x71, 0xd8, 0xe9, 0xff, 0xff, 0xe6, 0xeb,
+    0x99, 0xfb, 0x3a, 0xe6, 0x5b, 0x35, 0xf3, 0x37, 0x6e, 0x90, 0x50, 0xe9,
+    0xeb, 0x55, 0x58, 0xd1, 0x58, 0xcf, 0xfa, 0xff, 0x3c, 0x39, 0xfb, 0x8f,
+    0x8e, 0x85, 0x13, 0x35, 0xb1, 0x76, 0xe3, 0x7d, 0x84, 0x07, 0x8b, 0x67,
+    0xff, 0x38, 0xf9, 0x4f, 0xdc, 0x72, 0xcf, 0xd3, 0xa7, 0xf8, 0x3c, 0xcd,
+    0x6e, 0xd7, 0xe1, 0xd3, 0xfc, 0xfb, 0xb5, 0x86, 0xd7, 0x76, 0x3a, 0x30,
+    0xfd, 0x10, 0xe6, 0x7f, 0xd8, 0x1e, 0xa7, 0xfb, 0x03, 0x4d, 0x3a, 0x7f,
+    0xed, 0x9f, 0xdf, 0x3e, 0xdb, 0xea, 0xaf, 0xba, 0x3a, 0x7f, 0xba, 0xfa,
+    0xae, 0x8b, 0xb4, 0xe8, 0xea, 0x21, 0xaf, 0x28, 0x4c, 0x1f, 0x1d, 0x18,
+    0x6e, 0xc4, 0x96, 0x7f, 0xff, 0xe1, 0xff, 0x6c, 0xb7, 0xc1, 0xfd, 0x57,
+    0xcc, 0xdd, 0xb9, 0xf8, 0x83, 0x47, 0x4f, 0xdb, 0x30, 0xdb, 0xef, 0xbb,
+    0x1d, 0x3c, 0x23, 0x9e, 0x3a, 0x15, 0xa3, 0xd5, 0x73, 0x69, 0xfb, 0x6f,
+    0xb7, 0xf4, 0x20, 0x3a, 0x7f, 0xe6, 0x39, 0x4b, 0xf7, 0x1f, 0xdf, 0xac,
+    0xe8, 0x73, 0xf8, 0xc3, 0x29, 0xdc, 0x4b, 0x9d, 0x74, 0xdf, 0x23, 0x5b,
+    0xb2, 0x97, 0x21, 0x78, 0x24, 0x1a, 0x8c, 0x07, 0xc3, 0xf7, 0xf0, 0xd0,
+    0xfb, 0x09, 0xe9, 0xfb, 0xbd, 0x70, 0xe2, 0xce, 0x9b, 0xe8, 0x0e, 0x9d,
+    0xc4, 0x59, 0xd2, 0x60, 0xe8, 0xa3, 0x59, 0xf8, 0xdc, 0xfa, 0x87, 0x6f,
+    0xf4, 0x74, 0xff, 0x38, 0x79, 0x81, 0xed, 0x58, 0xe8, 0x44, 0x78, 0x00,
+    0xb0, 0x51, 0x34, 0x43, 0xe2, 0x89, 0xda, 0xfb, 0xa3, 0xa7, 0xb7, 0xd9,
+    0xd4, 0x3a, 0x02, 0x78, 0x5f, 0x8f, 0x4d, 0xe7, 0x3a, 0x7c, 0xbc, 0x17,
+    0x69, 0xd3, 0xdf, 0xfb, 0x34, 0x74, 0xf3, 0xf6, 0x84, 0xe9, 0xed, 0x69,
+    0xc0, 0x74, 0x3a, 0x21, 0xd0, 0x97, 0x84, 0x4c, 0x8f, 0xcf, 0x9d, 0xa0,
+    0xfd, 0xa7, 0x4f, 0xf2, 0x5b, 0x98, 0xc0, 0xb8, 0x4e, 0x9e, 0x67, 0xae,
+    0xb3, 0xa7, 0xcf, 0xb7, 0xdc, 0x60, 0xe9, 0xce, 0x2d, 0x3a, 0x18, 0x46,
+    0x2f, 0x0a, 0x04, 0xdf, 0x44, 0x5e, 0x2a, 0x9f, 0xe6, 0xf9, 0x19, 0xd6,
+    0xd8, 0xc9, 0xd3, 0x7d, 0x59, 0xd3, 0xfd, 0xff, 0xcf, 0x0d, 0x03, 0x04,
+    0xe8, 0xe1, 0xe8, 0x88, 0xc4, 0xca, 0xaf, 0x1d, 0x3f, 0x3a, 0xf0, 0x51,
+    0x43, 0xa5, 0xa3, 0xa1, 0x0d, 0xdd, 0x15, 0xcc, 0x07, 0x2a, 0x66, 0x59,
+    0x2a, 0x10, 0xd6, 0xb2, 0x2b, 0x3f, 0xa9, 0xa3, 0x9e, 0xe2, 0x15, 0x71,
+    0xa1, 0x9e, 0x0d, 0x6f, 0xa3, 0xa7, 0x38, 0xb0, 0x74, 0xc2, 0xe7, 0x49,
+    0x83, 0xa1, 0x83, 0xc0, 0xe8, 0xdd, 0x0a, 0x4f, 0xfc, 0xa2, 0x0d, 0xb4,
+    0xeb, 0xad, 0xfc, 0x74, 0xe0, 0x62, 0xa3, 0xa1, 0x43, 0xe1, 0xea, 0x24,
+    0xf2, 0xf5, 0xfa, 0xce, 0x92, 0x87, 0x4d, 0xd5, 0x0e, 0x87, 0x3c, 0xb4,
+    0x23, 0xfa, 0x23, 0x3f, 0xfd, 0xcc, 0x6e, 0x9f, 0xcd, 0xc5, 0x7a, 0x10,
+    0x1d, 0x3f, 0xf3, 0xb5, 0x3d, 0xcc, 0xdf, 0xdf, 0xb9, 0xd1, 0xa4, 0x4a,
+    0x79, 0x42, 0x58, 0x74, 0x21, 0xb2, 0xbf, 0x23, 0x87, 0x54, 0xf1, 0x8c,
+    0x49, 0x09, 0x0e, 0x37, 0x54, 0x3d, 0x60, 0xe9, 0x2c, 0xe9, 0x73, 0xc5,
+    0xd5, 0xe0, 0xa9, 0xf8, 0x0f, 0xcc, 0xbd, 0x47, 0x4f, 0xc9, 0xec, 0xe5,
+    0x28, 0x74, 0xe6, 0x59, 0x64, 0xa9, 0xff, 0x58, 0x2f, 0xb7, 0xdc, 0xe5,
+    0x6e, 0x55, 0xc5, 0xfc, 0xe7, 0x5a, 0x1d, 0x18, 0x7d, 0x76, 0x51, 0x9e,
+    0x4e, 0xaa, 0x09, 0xd3, 0xee, 0x3e, 0xf4, 0xae, 0x74, 0xff, 0xf3, 0xfb,
+    0x41, 0xcf, 0x27, 0x3f, 0xcd, 0xfc, 0x74, 0x70, 0xfe, 0xbc, 0x55, 0x2e,
+    0x9d, 0x37, 0xfa, 0x3a, 0x75, 0x50, 0x9d, 0x3e, 0x5a, 0x78, 0x14, 0x74,
+    0x6c, 0x99, 0x2e, 0x42, 0x75, 0x5c, 0x8a, 0x84, 0x3c, 0x2f, 0xf8, 0xcc,
+    0xf7, 0x3c, 0x9b, 0x1d, 0x3f, 0xac, 0x9a, 0x1c, 0xbd, 0x47, 0x4d, 0x9e,
+    0x3a, 0x7d, 0x9b, 0x0e, 0x6e, 0x74, 0x62, 0x24, 0x37, 0x22, 0xe1, 0x90,
+    0x8a, 0xce, 0xe3, 0x84, 0xe8, 0x3a, 0x7b, 0xcb, 0x5f, 0x4e, 0x9f, 0xf8,
+    0x0e, 0x36, 0xaf, 0x03, 0xe8, 0xb4, 0xe9, 0xef, 0x0e, 0x34, 0xe9, 0xf6,
+    0x7f, 0x7d, 0x6a, 0x8e, 0x9f, 0xfc, 0x9a, 0xe6, 0x04, 0x72, 0xf0, 0xe6,
+    0x8e, 0x85, 0x11, 0xf5, 0xb9, 0x17, 0x51, 0x04, 0x83, 0xc5, 0x90, 0xec,
+    0xc0, 0xfd, 0xa1, 0x14, 0xd2, 0x30, 0xc2, 0x73, 0x23, 0x01, 0xdd, 0x29,
+    0x21, 0x18, 0xc1, 0x0f, 0x55, 0x56, 0xdb, 0xc9, 0x57, 0x34, 0xd8, 0x02,
+    0x8b, 0xe8, 0xb4, 0x61, 0x6d, 0xa8, 0xd1, 0xbd, 0x0f, 0x06, 0x4f, 0x2f,
+    0xc6, 0xfe, 0xc6, 0x09, 0x3f, 0xd7, 0x79, 0x31, 0x56, 0xbf, 0x73, 0xa7,
+    0xff, 0xfb, 0xf7, 0xbb, 0xda, 0x4e, 0x52, 0x7b, 0x3a, 0x05, 0xd3, 0x4e,
+    0x8b, 0x93, 0xed, 0xda, 0x34, 0xc0, 0x9d, 0xcf, 0xbb, 0x6a, 0xab, 0x1a,
+    0x2b, 0x79, 0xff, 0x53, 0x6e, 0xce, 0xda, 0xaa, 0xc6, 0x89, 0xc2, 0x57,
+    0x61, 0xfe, 0xac, 0xce, 0x6b, 0xec, 0x27, 0x4d, 0xff, 0x0e, 0x9f, 0x76,
+    0xd5, 0x56, 0x34, 0x5a, 0x33, 0xfc, 0xc6, 0x2b, 0xeb, 0xbd, 0xaf, 0x1d,
+    0x3f, 0x3d, 0x0f, 0xe1, 0xc3, 0xa6, 0x45, 0x0e, 0x9f, 0xff, 0x6c, 0xfe,
+    0x70, 0xf5, 0xf9, 0x5a, 0x1c, 0x01, 0xd3, 0xfe, 0x7d, 0xe9, 0x5f, 0x83,
+    0x4a, 0xfb, 0x1d, 0x3f, 0xe7, 0xe8, 0x31, 0x33, 0xbe, 0xfc, 0xe8, 0x74,
+    0x6a, 0x71, 0x4f, 0x48, 0x92, 0xc6, 0x13, 0x19, 0xd4, 0x3a, 0xa7, 0xfb,
+    0x39, 0xcf, 0xd4, 0x5b, 0xe8, 0xe9, 0xec, 0x05, 0x70, 0xe9, 0xb9, 0xa3,
+    0xa5, 0x75, 0xf2, 0xaa, 0x12, 0xf8, 0x1b, 0xc1, 0x76, 0x0c, 0xd6, 0x79,
+    0xc8, 0xd1, 0x3c, 0x5f, 0x7e, 0x75, 0xf4, 0x82, 0x7a, 0xd5, 0x56, 0x34,
+    0x5b, 0x53, 0xf7, 0x1d, 0x6e, 0x81, 0x3a, 0x3a, 0x7b, 0x1e, 0x2d, 0x9f,
+    0xf7, 0x10, 0x34, 0xd0, 0xf1, 0x16, 0x74, 0xf3, 0xde, 0xc4, 0x3a, 0x7f,
+    0x9d, 0xaf, 0xdd, 0x9f, 0xbb, 0x1d, 0x3f, 0xcf, 0xdf, 0x9a, 0x7e, 0x52,
+    0x1d, 0x3f, 0xb8, 0x94, 0xdf, 0x26, 0xc7, 0x46, 0x26, 0x47, 0x62, 0x2e,
+    0x9e, 0x89, 0x0b, 0x27, 0x37, 0xe7, 0x13, 0xf2, 0x95, 0xd0, 0xfe, 0x27,
+    0x4f, 0x93, 0x65, 0xbd, 0x8e, 0x9f, 0x56, 0xed, 0xfb, 0xa3, 0xa5, 0x72,
+    0x87, 0xff, 0xe2, 0xeb, 0xc4, 0xf1, 0x72, 0x62, 0x40, 0x86, 0xcc, 0xcb,
+    0xe1, 0xd3, 0xee, 0xda, 0xaa, 0xc6, 0x8b, 0x96, 0x57, 0x04, 0xf2, 0x70,
+    0x5a, 0x7f, 0x5d, 0x9d, 0xb5, 0x55, 0x8d, 0x17, 0x6c, 0x3b, 0xa2, 0xd8,
+    0xd8, 0xa5, 0xb3, 0x9d, 0x61, 0x8d, 0x59, 0x49, 0xd6, 0xd4, 0xa7, 0xce,
+    0x2b, 0xc2, 0xdb, 0x92, 0xab, 0x06, 0x59, 0x4e, 0x9c, 0xfc, 0x51, 0x3f,
+    0xae, 0xce, 0xda, 0xaa, 0xc6, 0x8a, 0x9e, 0x5e, 0x3a, 0x7f, 0x9e, 0xb6,
+    0xf9, 0xbe, 0x9c, 0x27, 0x42, 0x1e, 0x58, 0x88, 0x4f, 0x5a, 0xaa, 0xc6,
+    0x8a, 0xe6, 0x7f, 0x5d, 0x9d, 0xb5, 0x55, 0x8d, 0x16, 0x74, 0x74, 0xfb,
+    0x38, 0x5b, 0x3f, 0xfb, 0xcf, 0xaf, 0x9f, 0xeb, 0xce, 0xc3, 0x08, 0x74,
+    0xfe, 0x7e, 0x7c, 0x5d, 0xf1, 0x7c, 0xf8, 0xe8, 0xc4, 0x46, 0xde, 0x4e,
+    0x9f, 0x77, 0x3c, 0x8b, 0x3a, 0x7a, 0x85, 0xc2, 0x74, 0xfd, 0x8c, 0x3a,
+    0xdf, 0xe9, 0xd3, 0xee, 0xda, 0xaa, 0xc6, 0x89, 0x0a, 0x7f, 0xd8, 0xbc,
+    0xae, 0xed, 0xf3, 0x75, 0x9d, 0x3f, 0xc9, 0xbe, 0xbc, 0x2e, 0xbd, 0x1d,
+    0x33, 0x6e, 0xc4, 0x56, 0x70, 0xcc, 0x08, 0x33, 0xd7, 0xc7, 0x1d, 0x67,
+    0x4f, 0xec, 0xe6, 0xb5, 0x9d, 0xd8, 0xe9, 0x5c, 0x15, 0x62, 0x79, 0x08,
+    0xc4, 0x85, 0x7f, 0x49, 0x16, 0x4d, 0xc1, 0xfa, 0x86, 0xd6, 0x8f, 0x3c,
+    0x4d, 0x3f, 0xfa, 0xe5, 0xd3, 0x6e, 0xce, 0xda, 0xaa, 0xc6, 0x89, 0xf2,
+    0x2c, 0xb9, 0x0e, 0xaf, 0x2e, 0x77, 0x90, 0x93, 0x9c, 0xd4, 0xdc, 0xe9,
+    0xf6, 0x77, 0x31, 0x83, 0xa5, 0x77, 0x0f, 0x0b, 0xe8, 0xe4, 0xfb, 0xb6,
+    0xaa, 0xb1, 0xa2, 0xb2, 0x9f, 0xf5, 0x36, 0xec, 0xed, 0xaa, 0xac, 0x68,
+    0x9b, 0xa5, 0x76, 0x1f, 0xea, 0xcc, 0xe2, 0xc8, 0xd0, 0x48, 0x54, 0x4f,
+    0xbb, 0x6a, 0xab, 0x1a, 0x25, 0x69, 0xf0, 0xb8, 0x6b, 0x87, 0x4f, 0xae,
+    0x5d, 0x36, 0xec, 0x3d, 0x84, 0x33, 0x9f, 0xf2, 0x6b, 0xf5, 0x8a, 0x5e,
+    0xfe, 0x8e, 0x9f, 0x9c, 0x6a, 0xd4, 0xae, 0x74, 0x34, 0xfb, 0x56, 0x81,
+    0x3e, 0xed, 0xaa, 0xac, 0x68, 0x97, 0x27, 0xf9, 0x29, 0xbe, 0x17, 0x5e,
+    0x8e, 0x9e, 0xbc, 0x82, 0xe7, 0x4f, 0xff, 0xab, 0xc9, 0xfb, 0x45, 0x1a,
+    0xfe, 0x1f, 0xda, 0x74, 0xfa, 0xe5, 0xd3, 0x6e, 0x74, 0xc0, 0x30, 0x8b,
+    0x86, 0x74, 0x6d, 0xa2, 0x19, 0xff, 0xae, 0xa6, 0xdd, 0x9d, 0xb5, 0x55,
+    0x8d, 0x11, 0xdc, 0xff, 0x7b, 0x98, 0xdb, 0xa8, 0x74, 0x74, 0xfd, 0x7d,
+    0x8b, 0xdb, 0x04, 0xe9, 0xbf, 0xe1, 0xd3, 0xf5, 0xf2, 0x39, 0xca, 0xf1,
+    0xd3, 0xfb, 0x19, 0xd3, 0x8f, 0xb4, 0x74, 0xff, 0x9c, 0x7f, 0xf2, 0x55,
+    0xea, 0x69, 0xd3, 0xd6, 0xaa, 0xb1, 0xa2, 0xa1, 0x8b, 0x1f, 0x5f, 0x4f,
+    0xa6, 0x6e, 0x1d, 0x3f, 0xfc, 0xf4, 0xbc, 0xe8, 0xe2, 0x5e, 0x4e, 0xd1,
+    0xd3, 0xfc, 0xed, 0x7e, 0xec, 0xfd, 0xd8, 0xe9, 0xfe, 0xc4, 0xbd, 0x4b,
+    0xe3, 0x34, 0x74, 0xf7, 0x3d, 0x9b, 0x1d, 0x3e, 0xcd, 0xa8, 0x6f, 0x1d,
+    0x3f, 0xff, 0xff, 0x9d, 0xbf, 0x3d, 0xc4, 0x7d, 0x7c, 0xcf, 0xec, 0xf7,
+    0xbe, 0x67, 0x7b, 0x97, 0xbf, 0xae, 0x1d, 0x18, 0x8e, 0x21, 0x22, 0xd1,
+    0x44, 0xff, 0xff, 0x7f, 0x4a, 0xe9, 0xb7, 0x29, 0x3c, 0xfc, 0x4f, 0x6b,
+    0x02, 0x74, 0xae, 0xbe, 0x55, 0xc0, 0x5f, 0x05, 0xf7, 0xd8, 0xbe, 0xc6,
+    0x19, 0x09, 0xdb, 0x11, 0x74, 0x54, 0x53, 0x34, 0x73, 0xe8, 0xc6, 0xef,
+    0xcb, 0xa7, 0xdd, 0xb5, 0x55, 0x8d, 0x15, 0x44, 0xff, 0xa9, 0xb7, 0x67,
+    0x6d, 0x55, 0x63, 0x44, 0xd7, 0x2b, 0xb0, 0xff, 0x56, 0x67, 0x3e, 0xed,
+    0xaa, 0xac, 0x68, 0xab, 0x27, 0xf9, 0xda, 0xfd, 0xd9, 0xfb, 0xb1, 0xd2,
+    0xbb, 0x0f, 0xb0, 0x4c, 0xe7, 0xfd, 0x77, 0x1f, 0x7f, 0x3f, 0x29, 0x5c,
+    0xe9, 0xff, 0xae, 0xa6, 0xdd, 0x9d, 0xb5, 0x55, 0x8d, 0x12, 0x24, 0xfb,
+    0xb6, 0xaa, 0xb1, 0xa2, 0xd2, 0x9f, 0xf5, 0x36, 0xec, 0xed, 0xaa, 0xac,
+    0x68, 0x9f, 0x65, 0x76, 0x1f, 0xea, 0xcc, 0xe7, 0xff, 0x5c, 0xba, 0x6d,
+    0xd9, 0xdb, 0x55, 0x58, 0xd1, 0x42, 0x4f, 0xb8, 0x9b, 0x3f, 0x4e, 0x9f,
+    0x76, 0xd5, 0x56, 0x34, 0x51, 0xf3, 0xfc, 0xed, 0x7e, 0xec, 0xfd, 0xd8,
+    0xe9, 0xff, 0x0b, 0xb0, 0xe2, 0xec, 0x71, 0xce, 0x9f, 0xff, 0xb0, 0x3c,
+    0x7f, 0xb7, 0x78, 0x68, 0x1a, 0xd3, 0x80, 0xa9, 0xf5, 0xcb, 0xa6, 0xdc,
+    0xe9, 0x95, 0xe1, 0x38, 0x99, 0xf8, 0xe6, 0xfc, 0xf2, 0x1d, 0x96, 0x6b,
+    0xb4, 0x75, 0x8d, 0x67, 0xc5, 0x15, 0x25, 0xdc, 0x5a, 0x33, 0xad, 0xe1,
+    0x28, 0x84, 0xec, 0x21, 0x72, 0x19, 0xc0, 0x28, 0xf4, 0x70, 0x53, 0xfa,
+    0xec, 0xed, 0xaa, 0xac, 0x68, 0x88, 0xa7, 0xec, 0xed, 0xaa, 0xac, 0x68,
+    0x8a, 0xe7, 0xf9, 0x5e, 0xec, 0xed, 0xaa, 0xac, 0x68, 0xae, 0x22, 0xe4,
+    0x40, 0x51, 0xc4, 0xff, 0xe0, 0x38, 0xda, 0xea, 0xf0, 0x3e, 0x8b, 0x4e,
+    0x9e, 0xbb, 0x66, 0x15, 0xce, 0x92, 0x6e, 0x7e, 0x60, 0x4b, 0x9e, 0xce,
+    0x57, 0x8e, 0x9f, 0xd8, 0x9d, 0x00, 0x3f, 0xd1, 0xd2, 0xbe, 0x44, 0xf4,
+    0xf4, 0x41, 0x3f, 0xff, 0x7b, 0x49, 0xca, 0x46, 0xa0, 0xfb, 0xfe, 0x77,
+    0x0e, 0x9f, 0x76, 0xd5, 0x56, 0x34, 0x53, 0xd3, 0xac, 0xb4, 0x3a, 0x7f,
+    0xfe, 0xef, 0x7f, 0xef, 0x5c, 0x71, 0x44, 0xe7, 0x33, 0xe9, 0xd3, 0xff,
+    0x23, 0x70, 0x40, 0xeb, 0x4e, 0xb4, 0xe9, 0xfc, 0xd7, 0xee, 0xcf, 0xdd,
+    0x8e, 0x9e, 0xf8, 0x34, 0xd3, 0xa7, 0xd5, 0x9c, 0x45, 0x9d, 0x1a, 0x3c,
+    0x7b, 0xc4, 0x50, 0xe8, 0x9f, 0xc7, 0xb9, 0xfe, 0x71, 0xb6, 0x5e, 0xcf,
+    0x68, 0xe8, 0xbe, 0xd5, 0x34, 0xb9, 0x66, 0x2c, 0xd8, 0xcd, 0x06, 0xe9,
+    0x74, 0x61, 0xc1, 0x78, 0x86, 0x7f, 0xf5, 0x36, 0xe0, 0x8d, 0x33, 0xad,
+    0x38, 0x0e, 0x9f, 0xfd, 0xe1, 0xc0, 0x50, 0x82, 0xe5, 0xa2, 0xce, 0x8b,
+    0x93, 0x0c, 0x0b, 0xd2, 0x25, 0x4e, 0xb8, 0x38, 0x74, 0xff, 0xfb, 0x8f,
+    0xdc, 0x6a, 0x57, 0xb0, 0x29, 0xfd, 0x8e, 0x9f, 0x3b, 0x41, 0xfb, 0x4e,
+    0x9e, 0xb5, 0x55, 0x8d, 0x15, 0x9c, 0x30, 0x7a, 0xbd, 0x28, 0x9e, 0xf2,
+    0x2f, 0x47, 0x4f, 0xdb, 0x2d, 0xc5, 0xba, 0x3a, 0x73, 0xec, 0x87, 0x4f,
+    0xbc, 0x0f, 0xa2, 0xd3, 0xa7, 0x7f, 0x5a, 0x3a, 0x7f, 0xb1, 0xa9, 0xfa,
+    0xbd, 0xf0, 0x05, 0x9d, 0x3e, 0xc6, 0x36, 0xfc, 0x07, 0x4a, 0xe0, 0xa7,
+    0xc9, 0x90, 0xa8, 0xdc, 0x8f, 0xa4, 0x3c, 0x2d, 0xa1, 0xb1, 0x29, 0xd0,
+    0xe7, 0xd4, 0x19, 0xff, 0x9b, 0x43, 0x72, 0xaf, 0x20, 0xe2, 0xce, 0x9f,
+    0xfa, 0xea, 0x6d, 0xd9, 0xdb, 0x55, 0x58, 0xd1, 0x22, 0xcf, 0xd9, 0xdb,
+    0x55, 0x58, 0xd1, 0x64, 0xcf, 0xfe, 0xf6, 0xbe, 0xea, 0xec, 0xd9, 0x05,
+    0xba, 0x3a, 0x2e, 0x44, 0x2e, 0x1c, 0x4f, 0xd9, 0xdb, 0x55, 0x58, 0xd1,
+    0x6c, 0x4f, 0xde, 0xbb, 0xbd, 0xff, 0x87, 0x45, 0xc7, 0xd0, 0x87, 0x13,
+    0xb3, 0x58, 0x74, 0xf5, 0xaa, 0xac, 0x68, 0xb6, 0xe7, 0xb5, 0xb5, 0x74,
+    0xe8, 0xe9, 0xe7, 0xf8, 0xb6, 0x7e, 0x4e, 0x79, 0x01, 0xf9, 0xd3, 0xfc,
+    0xed, 0x7e, 0xec, 0xfd, 0xd8, 0xe9, 0x5c, 0xd4, 0x78, 0xe3, 0x4b, 0x04,
+    0x42, 0x5b, 0x3a, 0xfb, 0xe0, 0x4e, 0x9d, 0xb7, 0x10, 0xe9, 0xff, 0x5f,
+    0x77, 0xda, 0xb7, 0xf7, 0x30, 0x5c, 0x07, 0x4f, 0xce, 0x2d, 0x0f, 0xeb,
+    0x3a, 0x7d, 0xdb, 0x55, 0x58, 0xd1, 0x78, 0x4f, 0x7a, 0xff, 0x38, 0x74,
+    0xf9, 0x6e, 0x2d, 0xa3, 0xa7, 0xfd, 0xf5, 0x7b, 0xb7, 0xd8, 0x3e, 0xd1,
+    0xd3, 0x62, 0x87, 0x43, 0x9e, 0xbe, 0x20, 0xcf, 0x26, 0xd8, 0xb3, 0xa7,
+    0xd8, 0x20, 0x54, 0xe7, 0x4f, 0x9f, 0xef, 0xf5, 0xa3, 0xa7, 0x79, 0xc0,
+    0x74, 0x5f, 0x2a, 0x8d, 0xaf, 0xb2, 0x15, 0x6d, 0x1c, 0xd9, 0x37, 0x0b,
+    0x77, 0x33, 0x42, 0x4e, 0x3e, 0x51, 0x00, 0x08, 0x44, 0x9f, 0xc5, 0x33,
+    0xfb, 0x7b, 0xb0, 0x15, 0xdd, 0x1d, 0x17, 0x23, 0xa9, 0xe1, 0x6d, 0x39,
+    0x33, 0x73, 0xa7, 0xad, 0x55, 0x63, 0x45, 0xe9, 0x3f, 0xe4, 0xf7, 0x06,
+    0x9a, 0x0a, 0x01, 0xd1, 0xd3, 0xe9, 0x59, 0x6c, 0xe5, 0xa7, 0x8e, 0x9f,
+    0xea, 0xf3, 0x5d, 0x4f, 0x26, 0xc7, 0x42, 0xcf, 0x50, 0x46, 0xe7, 0xd8,
+    0xbe, 0x50, 0x4e, 0x95, 0xc1, 0x4d, 0x07, 0x21, 0x09, 0xf5, 0xd9, 0x51,
+    0x0c, 0x3b, 0x3f, 0x4b, 0x68, 0x5f, 0xb6, 0x12, 0xd9, 0x2f, 0xc2, 0xc6,
+    0x29, 0x28, 0x01, 0x88, 0x45, 0xf5, 0x11, 0x70, 0xd6, 0x04, 0x22, 0xc6,
+    0x31, 0x3f, 0xe5, 0xb1, 0xb3, 0x1b, 0x4c, 0xdf, 0xf0, 0xe9, 0xec, 0xe5,
+    0x78, 0xe9, 0xfd, 0x89, 0xd0, 0x03, 0xfd, 0x1d, 0x2b, 0xe4, 0x4f, 0x4f,
+    0x44, 0x13, 0xe4, 0xf3, 0xef, 0xb1, 0xd3, 0xee, 0xda, 0xaa, 0xc6, 0x88,
+    0x8e, 0x7f, 0xfb, 0x9f, 0xeb, 0x58, 0xb1, 0xcb, 0xdf, 0x1d, 0x59, 0x3a,
+    0x7f, 0xcd, 0x7d, 0xbb, 0x9e, 0xf2, 0x78, 0xe9, 0xfe, 0xce, 0xe6, 0xb2,
+    0x87, 0x63, 0xa7, 0xff, 0xf9, 0xf9, 0x49, 0xe7, 0xe0, 0xe7, 0xb8, 0x9c,
+    0xc4, 0x64, 0xe9, 0xb6, 0x59, 0x53, 0x32, 0xc9, 0x53, 0xfe, 0xba, 0xdc,
+    0x46, 0x38, 0xfb, 0x5c, 0x03, 0x5e, 0xc8, 0xbc, 0xf5, 0xe7, 0xf3, 0x9d,
+    0x0d, 0x3f, 0xc4, 0x5a, 0x9f, 0xb2, 0x97, 0x9b, 0xf8, 0xe9, 0x95, 0xa5,
+    0x73, 0xa7, 0xe5, 0x71, 0xce, 0x57, 0x8e, 0x9f, 0x9d, 0x4c, 0x14, 0x50,
+    0xe9, 0xfb, 0x3c, 0xab, 0xd9, 0xc3, 0xa3, 0x11, 0x10, 0x25, 0xda, 0x2c,
+    0x9f, 0xff, 0xad, 0x77, 0x68, 0x53, 0xd7, 0x75, 0xfc, 0x34, 0x03, 0xa2,
+    0xf8, 0x5c, 0x45, 0xbe, 0xda, 0x9c, 0xb3, 0x0a, 0x2c, 0x67, 0xba, 0xc2,
+    0x1f, 0x74, 0xda, 0xa3, 0x0d, 0x01, 0x0e, 0x8b, 0x3d, 0x0a, 0x6b, 0xc5,
+    0xd3, 0x2a, 0xe1, 0xd3, 0xee, 0xda, 0xaa, 0xc6, 0x88, 0xba, 0x7d, 0xe0,
+    0x7d, 0x16, 0x95, 0x2b, 0xb6, 0x3f, 0x4c, 0x18, 0xa3, 0x38, 0xb9, 0x37,
+    0x26, 0xc6, 0x7b, 0x3f, 0xf2, 0xe9, 0xb7, 0x67, 0x6d, 0x55, 0x63, 0x44,
+    0xcd, 0x3f, 0x2b, 0x15, 0x6f, 0x7c, 0xe9, 0xfc, 0x74, 0xed, 0xdf, 0x47,
+    0x4e, 0xb2, 0x2c, 0xe9, 0xaf, 0xd5, 0xa3, 0xa6, 0xcf, 0xce, 0x9f, 0xfd,
+    0xc7, 0x5d, 0x7b, 0x37, 0x02, 0xfe, 0xf0, 0xe9, 0xfb, 0xd9, 0xb6, 0x01,
+    0x83, 0xa7, 0xf7, 0xcc, 0x1a, 0xe8, 0x2f, 0xce, 0x9f, 0xff, 0x2e, 0xb9,
+    0x9b, 0x83, 0x8c, 0xd7, 0x18, 0xe7, 0xe7, 0x40, 0x51, 0x1f, 0x86, 0xd3,
+    0x6b, 0x0e, 0x9e, 0x03, 0xaa, 0xf1, 0xd0, 0xad, 0x27, 0x2f, 0x61, 0xe4,
+    0x16, 0x61, 0x33, 0x90, 0xbd, 0xa2, 0x20, 0x0a, 0xcf, 0xcc, 0xb8, 0x8e,
+    0x78, 0xe9, 0xea, 0xe2, 0x30, 0x74, 0xf7, 0x18, 0x70, 0x9d, 0x18, 0x7d,
+    0xd6, 0x2b, 0xa2, 0x19, 0x58, 0xe9, 0xff, 0xf0, 0x37, 0x6f, 0x3f, 0x7e,
+    0xdd, 0xc4, 0xb5, 0x74, 0xe9, 0xff, 0x95, 0x27, 0x92, 0xc8, 0x1f, 0x65,
+    0x8e, 0x9e, 0xf5, 0xfe, 0x70, 0xe9, 0xff, 0xfd, 0x43, 0x61, 0xc0, 0xf3,
+    0xff, 0x9c, 0x76, 0xf5, 0xf6, 0x3a, 0x31, 0x10, 0xdf, 0x92, 0x4f, 0x79,
+    0x38, 0x87, 0x4f, 0xf5, 0x75, 0xbf, 0x32, 0xc1, 0xc3, 0xa1, 0xd3, 0x9e,
+    0xc5, 0x8e, 0x43, 0x28, 0x48, 0xff, 0x20, 0x97, 0x4e, 0x9f, 0xbd, 0x8b,
+    0xdf, 0x16, 0x74, 0xb9, 0x86, 0xf5, 0x04, 0x27, 0xff, 0xc1, 0x41, 0xdb,
+    0x34, 0x95, 0xcb, 0x99, 0x65, 0x92, 0xa7, 0xef, 0x71, 0xf6, 0xe7, 0xe7,
+    0x4f, 0xdb, 0xb7, 0x40, 0xfd, 0x83, 0xa7, 0xfb, 0x6c, 0x00, 0x7f, 0xae,
+    0xb4, 0xe9, 0xd5, 0x56, 0x34, 0x59, 0xf3, 0xf0, 0x28, 0x5a, 0x8b, 0x3a,
+    0x36, 0x44, 0x65, 0x8e, 0x80, 0x4f, 0x3f, 0xe4, 0xe3, 0xb5, 0x3c, 0xfe,
+    0xd1, 0xd3, 0xff, 0xc9, 0xde, 0x57, 0xcc, 0xbc, 0x39, 0xac, 0x13, 0xa7,
+    0x32, 0xcb, 0x25, 0x4f, 0xfa, 0x9b, 0xa1, 0xcb, 0x07, 0x3a, 0x55, 0xc5,
+    0xfc, 0xff, 0xcf, 0xbb, 0x47, 0xf0, 0x7c, 0xb2, 0xc0, 0x74, 0xfe, 0xe2,
+    0x04, 0x6a, 0x98, 0x3a, 0x7f, 0x07, 0x9f, 0xd0, 0x2f, 0xf0, 0xe8, 0x73,
+    0xe7, 0x43, 0x19, 0xfe, 0x41, 0x0f, 0xd0, 0xff, 0xed, 0x1d, 0x0d, 0x57,
+    0x35, 0x62, 0x5d, 0xd6, 0x18, 0x2f, 0xec, 0x2f, 0x56, 0x63, 0xc3, 0xc0,
+    0x37, 0x69, 0x33, 0xd0, 0xaf, 0xbc, 0x41, 0x3f, 0xdd, 0xa6, 0x78, 0x8f,
+    0xd7, 0x3a, 0x7f, 0xdd, 0x4d, 0x37, 0xef, 0x1c, 0x5c, 0xe9, 0xee, 0xa3,
+    0xac, 0xe9, 0xff, 0xf7, 0x94, 0xfd, 0xf0, 0x3c, 0xcd, 0x6e, 0xd7, 0xe1,
+    0xd1, 0xd4, 0x5a, 0xac, 0xf8, 0x48, 0x26, 0xa6, 0x9d, 0x3f, 0xff, 0xff,
+    0x0d, 0x33, 0xec, 0xe0, 0xe7, 0xbf, 0x02, 0xe9, 0xb4, 0x17, 0x1a, 0xed,
+    0x34, 0xe9, 0xfd, 0x9c, 0xe7, 0xfe, 0xa1, 0x3a, 0x48, 0x14, 0x66, 0x30,
+    0x2b, 0xd8, 0x42, 0xcf, 0xba, 0xc5, 0xec, 0x09, 0xd3, 0xfe, 0xc6, 0x55,
+    0x77, 0x15, 0x0f, 0xec, 0x9d, 0x0e, 0x9d, 0x27, 0x21, 0xf7, 0x47, 0x62,
+    0x55, 0x3f, 0xff, 0xfe, 0xc0, 0x6b, 0x30, 0x54, 0xfb, 0xd1, 0x7c, 0xe5,
+    0xda, 0x1c, 0xd9, 0x78, 0xb3, 0xa7, 0xd7, 0xab, 0x8f, 0xf4, 0xe8, 0xc4,
+    0x56, 0xa4, 0x20, 0xe7, 0x69, 0xf6, 0x3a, 0x75, 0xfe, 0x70, 0xe8, 0x69,
+    0xf0, 0x68, 0x9b, 0xc3, 0x93, 0xb9, 0xfb, 0x27, 0x4e, 0x07, 0xf6, 0x3a,
+    0x77, 0xb3, 0xe9, 0xd3, 0xf3, 0xef, 0xaf, 0x9d, 0x73, 0xa7, 0x07, 0xfb,
+    0x1d, 0x3c, 0x11, 0x76, 0x9d, 0x08, 0x6f, 0x68, 0x76, 0x79, 0xfd, 0xa7,
+    0x3a, 0x02, 0x98, 0x1e, 0xe3, 0xc8, 0x3a, 0xb1, 0xde, 0x36, 0x5f, 0x8f,
+    0xcd, 0x96, 0x3a, 0x7e, 0xea, 0x5e, 0xc1, 0xd1, 0xd3, 0xee, 0x0b, 0xe7,
+    0x4c, 0x9f, 0xf2, 0x75, 0xb9, 0xdd, 0xbf, 0xa0, 0x9a, 0x20, 0xdb, 0x8d,
+    0x2c, 0xfa, 0xac, 0x8b, 0x73, 0xa7, 0xe6, 0xf0, 0x6b, 0x7f, 0x1d, 0x2c,
+    0xb1, 0xe9, 0x09, 0x2c, 0xff, 0xff, 0xa9, 0x9f, 0x67, 0x3c, 0xf8, 0x3b,
+    0xfb, 0x3a, 0x9b, 0x52, 0xce, 0x8b, 0xe1, 0x3a, 0x77, 0x15, 0x6a, 0x96,
+    0x42, 0xbc, 0x49, 0xa7, 0xc9, 0xbb, 0x50, 0x4e, 0x9c, 0x9c, 0xc3, 0xa6,
+    0x75, 0xe1, 0xe0, 0x58, 0x9a, 0x7d, 0x81, 0xd7, 0x1c, 0xe8, 0x43, 0xd2,
+    0xe9, 0x64, 0xee, 0x60, 0x9d, 0x3f, 0xff, 0x0d, 0x29, 0xf3, 0xe8, 0xd7,
+    0xb4, 0x9b, 0xf1, 0x19, 0x3a, 0x30, 0xfe, 0x7f, 0x1a, 0x9e, 0x41, 0xa0,
+    0x9d, 0x3f, 0xe5, 0xe7, 0xb5, 0xf7, 0x54, 0xdc, 0x3a, 0x7d, 0xa7, 0xef,
+    0x9c, 0xeb, 0x8d, 0xfc, 0x05, 0x12, 0xba, 0x5e, 0x9f, 0x7d, 0x62, 0xab,
+    0xa7, 0x4f, 0x73, 0x12, 0xf1, 0xd3, 0xf6, 0x93, 0xb9, 0xff, 0x4e, 0x84,
+    0x44, 0xda, 0xc8, 0xf8, 0x53, 0xe2, 0x29, 0x97, 0x7c, 0x9a, 0x2f, 0xc9,
+    0xff, 0x9b, 0xef, 0xda, 0xd5, 0xfb, 0xce, 0xb3, 0xa7, 0xff, 0xb8, 0xe1,
+    0xcb, 0x7c, 0xc1, 0xc0, 0xf1, 0xce, 0x9f, 0xf9, 0x30, 0x73, 0x35, 0xf1,
+    0xba, 0x59, 0xd1, 0xba, 0x35, 0xd8, 0x46, 0xd2, 0x74, 0xe5, 0x1f, 0xa7,
+    0x4f, 0xc1, 0x70, 0x77, 0x37, 0x3a, 0x2e, 0x3c, 0x95, 0x8e, 0x4f, 0xe7,
+    0x5e, 0x27, 0x58, 0x69, 0xd3, 0x23, 0x07, 0x4e, 0xf2, 0x6c, 0x74, 0xe1,
+    0x7b, 0x1d, 0x3f, 0xfc, 0x2f, 0x6f, 0x9d, 0xc4, 0xfe, 0xfa, 0xc5, 0x58,
+    0x74, 0x7c, 0x45, 0x12, 0xc5, 0x84, 0x71, 0x50, 0xd4, 0x3a, 0xae, 0xd0,
+    0x9e, 0x64, 0x3f, 0xd1, 0xef, 0x84, 0x75, 0x0d, 0x49, 0xfe, 0xc1, 0x68,
+    0xe2, 0xde, 0xc7, 0x4f, 0xb8, 0x97, 0xb0, 0x27, 0x4f, 0xa9, 0x68, 0xab,
+    0x0e, 0x9d, 0xe7, 0xdc, 0xe8, 0xc3, 0xc3, 0xa2, 0x79, 0xff, 0xff, 0x3f,
+    0x11, 0x77, 0x30, 0xda, 0xef, 0xde, 0x26, 0xfa, 0xb2, 0x6c, 0x74, 0x05,
+    0x33, 0x15, 0x0d, 0x58, 0x6b, 0x54, 0x41, 0x3f, 0x57, 0x5f, 0x9f, 0x42,
+    0x74, 0xf3, 0xa6, 0xce, 0x74, 0xf3, 0x35, 0x9a, 0x3a, 0x7f, 0x9a, 0xba,
+    0x6f, 0xb4, 0xea, 0x1d, 0x0e, 0x7b, 0x54, 0x43, 0x3b, 0x48, 0x27, 0x4f,
+    0x86, 0xdf, 0x35, 0xb9, 0xd1, 0x87, 0x89, 0x43, 0x51, 0x49, 0x96, 0x00,
+    0xb8, 0x5e, 0xbf, 0x64, 0x9d, 0xbe, 0xcd, 0x3a, 0x7b, 0xef, 0xf5, 0xa3,
+    0xa7, 0x80, 0x0c, 0xdc, 0xe9, 0xea, 0x6e, 0xe0, 0x3a, 0x7d, 0xec, 0xa1,
+    0xb1, 0xd0, 0x27, 0x8e, 0xa8, 0x8a, 0x7f, 0xbf, 0xa6, 0x87, 0x30, 0x1a,
+    0x3a, 0x7f, 0x01, 0x37, 0xdd, 0xb9, 0xe3, 0xa3, 0x87, 0xd9, 0xa3, 0x89,
+    0xf9, 0xf7, 0xd2, 0xd1, 0x5c, 0xe9, 0xfa, 0xb6, 0x05, 0x08, 0x4e, 0x8e,
+    0xa6, 0xed, 0xc6, 0x9f, 0x42, 0x3e, 0xf1, 0x15, 0xf9, 0x84, 0xff, 0x73,
+    0xeb, 0xda, 0xff, 0x3a, 0xe7, 0x43, 0xaa, 0x2b, 0xc8, 0xe6, 0xa9, 0x56,
+    0x66, 0x3f, 0x3a, 0x4b, 0x3a, 0x37, 0x35, 0x17, 0xd0, 0xc4, 0xfd, 0x5b,
+    0xb4, 0x5c, 0x27, 0x4f, 0xf3, 0xee, 0xd4, 0x15, 0xd7, 0x8e, 0x8a, 0x3e,
+    0x31, 0x2c, 0x9f, 0x53, 0x73, 0x67, 0x3a, 0x7f, 0xe4, 0x7d, 0x0d, 0x37,
+    0xe6, 0xb3, 0xa7, 0x4f, 0xff, 0xe4, 0xd6, 0xd8, 0xce, 0x0f, 0xea, 0x9e,
+    0xec, 0x1a, 0xe9, 0xd0, 0x14, 0x65, 0x89, 0x37, 0x90, 0xe7, 0xff, 0xfd,
+    0xc4, 0xdf, 0xd9, 0xbf, 0xbb, 0xd7, 0xf0, 0x3e, 0x8b, 0x79, 0x87, 0x4f,
+    0x04, 0x34, 0x27, 0x4f, 0xfa, 0xb9, 0x64, 0xaf, 0x9a, 0xae, 0x1d, 0x3f,
+    0xec, 0xb7, 0x11, 0x4b, 0xff, 0xfa, 0xa1, 0xd3, 0xfd, 0xc4, 0xa0, 0x60,
+    0x69, 0xa7, 0x43, 0xaa, 0xeb, 0x0c, 0x22, 0xb2, 0x1d, 0x76, 0x2f, 0x46,
+    0xfe, 0x10, 0x09, 0xf7, 0x91, 0x27, 0xfe, 0xc1, 0x06, 0x67, 0x75, 0xe7,
+    0xc3, 0xa7, 0xfb, 0x7f, 0x67, 0x53, 0x6a, 0x59, 0xd2, 0xc0, 0x1f, 0xc8,
+    0xa0, 0x4f, 0xff, 0x9c, 0x5b, 0x9c, 0x45, 0x87, 0x18, 0x7c, 0xe9, 0xd3,
+    0xf0, 0x35, 0x67, 0xea, 0x87, 0x4f, 0xec, 0x6e, 0x20, 0x78, 0x87, 0x4f,
+    0x79, 0xab, 0xe1, 0xd3, 0xc8, 0xa2, 0x32, 0x74, 0x61, 0xe2, 0x09, 0x14,
+    0xdf, 0x30, 0xe9, 0xed, 0x0b, 0xac, 0xe8, 0x73, 0x6f, 0xb8, 0xbc, 0xf6,
+    0x71, 0xab, 0x3a, 0x1d, 0x3b, 0x35, 0x09, 0xa9, 0x48, 0x4b, 0xb4, 0xe9,
+    0xfa, 0xbd, 0xf9, 0x0c, 0xb8, 0x74, 0xda, 0x69, 0xd0, 0x03, 0x4d, 0xf8,
+    0x84, 0xfd, 0xb3, 0x0d, 0xbe, 0xfb, 0xb1, 0xd3, 0xab, 0x3a, 0x74, 0xe1,
+    0xcf, 0x1d, 0x1c, 0x36, 0x82, 0x35, 0x3c, 0x17, 0xdf, 0x47, 0x4f, 0xe5,
+    0x39, 0x9e, 0xe2, 0x78, 0xe9, 0x93, 0xa7, 0x4f, 0xdb, 0x7c, 0xda, 0xab,
+    0x87, 0x42, 0xb4, 0x99, 0x23, 0xb5, 0x61, 0x02, 0x11, 0x70, 0xce, 0x85,
+    0x67, 0xfe, 0xdb, 0x98, 0x10, 0xa6, 0xf9, 0xbf, 0x8e, 0x9f, 0xf8, 0x2e,
+    0x1e, 0xbf, 0x92, 0xc8, 0x13, 0xa7, 0x98, 0x75, 0x4d, 0x3a, 0x7f, 0x98,
+    0xd5, 0xea, 0x1d, 0xbf, 0x09, 0xd3, 0xda, 0xfc, 0x54, 0x3a, 0x7e, 0xe7,
+    0xfb, 0x31, 0xc4, 0x3a, 0x78, 0x47, 0x3c, 0x74, 0x3a, 0x6b, 0x61, 0x46,
+    0xc4, 0x24, 0x24, 0x60, 0xf7, 0x84, 0x7e, 0x30, 0x9f, 0xbe, 0x30, 0xfe,
+    0x1b, 0xc7, 0x4f, 0xfe, 0x17, 0xbd, 0xd7, 0xee, 0x27, 0x1c, 0x27, 0x4e,
+    0x1a, 0x59, 0xd0, 0xd4, 0x49, 0xe1, 0x8a, 0x24, 0x4a, 0xe5, 0x69, 0xd3,
+    0x3d, 0x5f, 0x07, 0xca, 0xdc, 0x71, 0xe3, 0xb2, 0xda, 0x1b, 0x8d, 0x2d,
+    0x0c, 0x75, 0xd9, 0x38, 0x4a, 0xa4, 0x2a, 0x2d, 0x2a, 0x43, 0x78, 0xd3,
+    0x52, 0x33, 0x26, 0x25, 0x01, 0x76, 0x1c, 0x8b, 0x84, 0xd7, 0x27, 0x0f,
+    0xea, 0x39, 0x00, 0x46, 0xdd, 0x7d, 0x1e, 0x8c, 0xa4, 0x9d, 0x4b, 0x48,
+    0xf4, 0xaa, 0x56, 0x61, 0x1b, 0x7f, 0x1a, 0x37, 0xd8, 0xed, 0x15, 0x43,
+    0xda, 0x2e, 0x75, 0x19, 0xfc, 0xb4, 0xd9, 0x53, 0xff, 0xae, 0x5d, 0x36,
+    0xec, 0xed, 0xaa, 0xac, 0x68, 0x9b, 0x27, 0xf5, 0xd9, 0xdb, 0x55, 0x58,
+    0xd1, 0x56, 0xcf, 0xe6, 0xb7, 0xff, 0x0b, 0xb4, 0xe9, 0xec, 0xe5, 0x78,
+    0xe9, 0x5f, 0x38, 0x7a, 0x62, 0x67, 0x3e, 0x7e, 0xaf, 0x81, 0x3a, 0x75,
+    0x55, 0x8d, 0x15, 0xa4, 0xf9, 0x4d, 0xf5, 0xfe, 0xe7, 0x4b, 0xb6, 0x3d,
+    0x34, 0x27, 0x9f, 0xfe, 0xb3, 0xf7, 0x01, 0x4b, 0xa6, 0xba, 0x58, 0xe9,
+    0xff, 0xe6, 0xeb, 0x05, 0xd7, 0x59, 0xef, 0x3a, 0xce, 0x9b, 0xde, 0x74,
+    0x4c, 0x52, 0x64, 0xff, 0xff, 0xe7, 0xbc, 0x9e, 0xd6, 0x29, 0x6e, 0x27,
+    0xb1, 0x81, 0x75, 0xed, 0x8c, 0x9d, 0x3c, 0xdf, 0x26, 0xc7, 0x4f, 0xbe,
+    0xf8, 0x5c, 0x07, 0x49, 0xf7, 0x3c, 0xab, 0xc4, 0x53, 0xec, 0xe2, 0x62,
+    0xce, 0x9f, 0xf8, 0x69, 0x2d, 0xca, 0xff, 0x6e, 0xa1, 0xd1, 0xb1, 0xf4,
+    0x70, 0x96, 0x7f, 0x35, 0xfb, 0xb3, 0xf7, 0x63, 0xa7, 0xcc, 0x60, 0x56,
+    0xae, 0x74, 0xfc, 0x2e, 0xce, 0xed, 0xd1, 0xd0, 0xc1, 0xec, 0xaa, 0x2b,
+    0x87, 0x45, 0x96, 0x42, 0x36, 0x7f, 0x37, 0x3d, 0x42, 0x0f, 0xce, 0x95,
+    0xd7, 0xda, 0xe0, 0xa6, 0xc5, 0x78, 0xf4, 0x90, 0xbf, 0xe9, 0x6f, 0x21,
+    0x89, 0x50, 0x92, 0x18, 0x6a, 0xf8, 0x9a, 0x7f, 0x5d, 0x9d, 0xb5, 0x55,
+    0x8d, 0x16, 0x04, 0xfb, 0xb6, 0xaa, 0xb1, 0xa2, 0x75, 0x9f, 0xff, 0xdc,
+    0x7d, 0x83, 0x8b, 0xbb, 0x5a, 0xce, 0x26, 0xbf, 0xd8, 0xe9, 0xf5, 0xcb,
+    0xa6, 0xdd, 0x88, 0x97, 0x60, 0xce, 0x7f, 0x37, 0x57, 0x28, 0xa3, 0xac,
+    0xe9, 0xf7, 0x6d, 0x55, 0x63, 0x45, 0xb3, 0x3f, 0xff, 0xa9, 0xb7, 0x69,
+    0xd3, 0x02, 0x99, 0xac, 0xf0, 0xb9, 0xd3, 0xfe, 0x03, 0xea, 0xee, 0x25,
+    0xab, 0xa7, 0x4f, 0xf3, 0xb5, 0xfb, 0xb3, 0xf7, 0x63, 0xa5, 0x76, 0x26,
+    0x0c, 0xb3, 0x3a, 0x5c, 0x13, 0xe9, 0xff, 0xf5, 0x00, 0x1f, 0xea, 0xec,
+    0xed, 0x6b, 0x94, 0xd3, 0xa7, 0xad, 0x55, 0x63, 0x45, 0xcd, 0x25, 0x9d,
+    0x1d, 0x37, 0xac, 0x96, 0xcc, 0xc2, 0xce, 0x95, 0xd8, 0x6e, 0x59, 0x22,
+    0x9f, 0x76, 0xd5, 0x56, 0x34, 0x5d, 0xf3, 0xf9, 0xb7, 0x6b, 0xbd, 0x46,
+    0x4e, 0x95, 0xd8, 0x7d, 0x14, 0x67, 0x3d, 0x72, 0x81, 0x01, 0xd0, 0xee,
+    0xcc, 0x1f, 0x2d, 0x47, 0xd5, 0x8d, 0x77, 0x57, 0x49, 0xca, 0x6e, 0xc2,
+    0x79, 0x70, 0xd6, 0xa4, 0x20, 0x46, 0x78, 0x28, 0x5a, 0x86, 0x67, 0xa1,
+    0x21, 0xf4, 0x9e, 0x7d, 0xad, 0x2e, 0x9a, 0x74, 0xff, 0xdb, 0xdb, 0xfa,
+    0xdf, 0xd9, 0x82, 0xa1, 0xd3, 0x86, 0xae, 0x73, 0xed, 0xf1, 0x3c, 0xfe,
+    0x1d, 0xb1, 0x57, 0x9d, 0x43, 0xa7, 0xfd, 0xaa, 0x53, 0x88, 0xe3, 0xfb,
+    0x9d, 0x3f, 0xee, 0x57, 0xab, 0x9b, 0xb7, 0x3c, 0x74, 0x61, 0xfd, 0xa1,
+    0xec, 0xff, 0xff, 0xf7, 0x46, 0x99, 0x1c, 0xf7, 0xb3, 0x67, 0x1a, 0x53,
+    0x4b, 0x7c, 0x10, 0x9d, 0x3d, 0x6a, 0xab, 0x1a, 0x25, 0x79, 0xff, 0xde,
+    0xe6, 0x36, 0xdc, 0x40, 0xb8, 0xf8, 0xe8, 0xe9, 0xfa, 0x89, 0x6c, 0xcd,
+    0xd8, 0xe9, 0xff, 0x0d, 0x32, 0x1e, 0x3e, 0xd8, 0xc9, 0xd3, 0xff, 0xf3,
+    0x71, 0x01, 0x8b, 0x4f, 0x69, 0xd7, 0x5b, 0xf8, 0xe9, 0xef, 0xeb, 0xad,
+    0x3a, 0x7f, 0x9e, 0xc2, 0xfb, 0x02, 0xbc, 0x74, 0xff, 0xfe, 0x4f, 0x52,
+    0xe8, 0x41, 0xc6, 0x68, 0x76, 0xb2, 0x6c, 0x74, 0x05, 0x17, 0x28, 0x45,
+    0x46, 0xf0, 0x14, 0xdf, 0xf0, 0xff, 0x91, 0x89, 0x4f, 0xfb, 0xd4, 0xdd,
+    0x71, 0xfb, 0xf4, 0x27, 0x4f, 0xfd, 0xe4, 0xbc, 0x9e, 0x61, 0xae, 0x3e,
+    0x3a, 0x75, 0x36, 0xe7, 0x5c, 0x31, 0x6c, 0x2c, 0x02, 0x41, 0x90, 0xef,
+    0x59, 0x0e, 0xa3, 0x96, 0xf1, 0xb7, 0xd4, 0x09, 0xff, 0xd9, 0xcb, 0x87,
+    0x02, 0x83, 0xec, 0xe1, 0xd3, 0xbc, 0xe1, 0x2a, 0x7f, 0xf7, 0x29, 0x3c,
+    0xed, 0x4e, 0xed, 0xf8, 0x0a, 0x9f, 0xd5, 0x6b, 0x83, 0xdb, 0xea, 0xe7,
+    0x3e, 0x5d, 0x0d, 0xca, 0xeb, 0x2e, 0xfb, 0x2e, 0x71, 0x8f, 0xd0, 0x96,
+    0xbd, 0x0a, 0xc9, 0xff, 0xd7, 0x2e, 0x9b, 0x76, 0x76, 0xd5, 0x56, 0x34,
+    0x4c, 0x33, 0xff, 0xf6, 0x5d, 0xf7, 0xb4, 0x0b, 0x94, 0xf3, 0x59, 0x7d,
+    0x34, 0xe9, 0xff, 0xaf, 0x9c, 0xdd, 0xbf, 0xd7, 0x85, 0xda, 0x74, 0xfe,
+    0x40, 0xe2, 0xfe, 0x6e, 0xae, 0x74, 0xfe, 0x7a, 0xdb, 0xca, 0x57, 0x4e,
+    0x9f, 0x57, 0x5b, 0x4b, 0x3a, 0x04, 0xf6, 0x7f, 0x33, 0x9f, 0xff, 0x27,
+    0x79, 0x5f, 0x03, 0x8d, 0xe3, 0xde, 0x0b, 0x9d, 0x3f, 0xf6, 0x6e, 0xcf,
+    0xde, 0x3d, 0xb8, 0x8c, 0x1d, 0x1c, 0x44, 0xf8, 0xab, 0xcf, 0xcb, 0x7c,
+    0x1f, 0x5f, 0x9d, 0x2d, 0x1d, 0x3e, 0x7c, 0x1f, 0x5f, 0x9d, 0x3f, 0x71,
+    0x3d, 0xaa, 0xdf, 0xe1, 0xf3, 0x30, 0x5c, 0xb1, 0x09, 0xfc, 0xdf, 0x3a,
+    0xef, 0x01, 0xa7, 0x4f, 0xff, 0xe6, 0x55, 0x7b, 0x39, 0xf0, 0x73, 0x64,
+    0xc1, 0xdd, 0xba, 0x3a, 0x7c, 0xcf, 0xb3, 0x96, 0x3a, 0x43, 0x88, 0x8d,
+    0xa6, 0x59, 0xff, 0xe7, 0xf0, 0xd0, 0x39, 0x88, 0x1f, 0xfd, 0xa3, 0xa7,
+    0xeb, 0xdf, 0x7c, 0x2e, 0x03, 0xa7, 0xff, 0x3f, 0x80, 0xed, 0xcd, 0xfd,
+    0xb7, 0xec, 0x9d, 0x0e, 0x7f, 0xa8, 0x61, 0x3f, 0x81, 0x40, 0xef, 0x53,
+    0xa7, 0x4f, 0xda, 0x45, 0x17, 0x5e, 0x3a, 0x7f, 0xff, 0xdd, 0xcb, 0xce,
+    0x3e, 0xf9, 0xf4, 0x5f, 0x94, 0x9e, 0x7f, 0x68, 0xe9, 0xf8, 0x73, 0x5f,
+    0x2d, 0x7d, 0x9d, 0x1b, 0xa3, 0x3b, 0xa5, 0xb7, 0x9b, 0xa7, 0xbe, 0x5e,
+    0x55, 0xb1, 0xd1, 0x87, 0xb8, 0xa1, 0x9c, 0xff, 0xf7, 0xf7, 0xd0, 0xba,
+    0xe9, 0x39, 0x5e, 0xe3, 0x9d, 0x3f, 0x9c, 0x7d, 0x4b, 0x4f, 0x1d, 0x18,
+    0x88, 0x2e, 0x29, 0x4f, 0xff, 0xb8, 0x39, 0xee, 0x26, 0x6f, 0xec, 0xbc,
+    0xfa, 0x3a, 0x73, 0x83, 0xe9, 0xd1, 0x87, 0xe4, 0x2a, 0xb3, 0xbe, 0x87,
+    0x0e, 0x9d, 0x7d, 0x6a, 0xfb, 0x3a, 0x28, 0xf0, 0xf4, 0x3b, 0x2b, 0xaf,
+    0xb5, 0xf6, 0x37, 0x49, 0x0c, 0x24, 0x72, 0x18, 0x36, 0x84, 0x46, 0xea,
+    0xac, 0x43, 0x0b, 0xa4, 0xdc, 0x86, 0x58, 0x08, 0x06, 0x35, 0xcd, 0x42,
+    0x93, 0xd0, 0x94, 0xfd, 0x8e, 0x7f, 0xfb, 0xa9, 0xbb, 0x74, 0x9e, 0xe3,
+    0xf7, 0xce, 0x74, 0xfb, 0xb6, 0xaa, 0xb1, 0xa2, 0xae, 0x9d, 0xd7, 0x59,
+    0xd3, 0xfc, 0xdb, 0xb3, 0xb6, 0xaa, 0xb1, 0xa2, 0x3c, 0x9f, 0xe7, 0x6b,
+    0xf7, 0x67, 0xee, 0xc7, 0x4a, 0xe0, 0xa6, 0x37, 0x89, 0xfd, 0x33, 0xa1,
+    0xb1, 0x45, 0x9f, 0x76, 0xd5, 0x56, 0x34, 0x58, 0x33, 0x94, 0x7d, 0x8e,
+    0x9f, 0xff, 0x87, 0xfa, 0xd9, 0x79, 0x7f, 0xff, 0x73, 0xad, 0xfa, 0xd3,
+    0xa7, 0xd8, 0x39, 0xed, 0x1d, 0x3f, 0xbb, 0x4b, 0xfb, 0xda, 0xdc, 0xe9,
+    0x5d, 0x89, 0x86, 0x28, 0x67, 0x61, 0xda, 0x62, 0xfa, 0x4b, 0x3f, 0xae,
+    0xce, 0xda, 0xaa, 0xc6, 0x8b, 0x2a, 0x7f, 0x5d, 0x9d, 0xb5, 0x55, 0x8d,
+    0x16, 0x9c, 0xf9, 0x5b, 0xab, 0x6a, 0xb4, 0xad, 0x5f, 0x07, 0x4f, 0xf5,
+    0xf7, 0xc4, 0x64, 0x35, 0x56, 0x3a, 0x7c, 0xad, 0xef, 0x9d, 0x63, 0x9d,
+    0x3f, 0xbe, 0xaf, 0x3d, 0xa4, 0xd1, 0xd2, 0x43, 0xa2, 0xfb, 0x3c, 0x3b,
+    0xf3, 0x49, 0xff, 0xf9, 0x39, 0x43, 0xe6, 0xe7, 0x71, 0xc4, 0x73, 0xc7,
+    0x4f, 0xaf, 0x50, 0x71, 0x67, 0x4f, 0x2d, 0xf7, 0xd1, 0xd0, 0xd4, 0x4f,
+    0xe2, 0xab, 0x05, 0x13, 0xfb, 0x35, 0xf3, 0xbd, 0xff, 0x87, 0x4f, 0xff,
+    0x9c, 0x6d, 0xc4, 0xe2, 0x75, 0xd8, 0x67, 0x38, 0x74, 0xf3, 0xfd, 0x7e,
+    0x1d, 0x3d, 0x6a, 0xab, 0x1a, 0x2d, 0xc9, 0xff, 0x67, 0x70, 0x7e, 0x73,
+    0x37, 0x64, 0xe9, 0xf0, 0x82, 0xb7, 0xd1, 0xd0, 0xe7, 0xcf, 0x48, 0x11,
+    0xba, 0x35, 0xba, 0x45, 0xa8, 0x4a, 0x4f, 0xea, 0x10, 0x30, 0x2e, 0xb3,
+    0xa7, 0x2c, 0x50, 0xe9, 0x09, 0xd3, 0xfd, 0xcf, 0xeb, 0x59, 0x82, 0xa1,
+    0xd3, 0xed, 0x56, 0xf4, 0x13, 0xa4, 0x81, 0x3d, 0xff, 0x1c, 0x43, 0xa2,
+    0xbf, 0x06, 0xb8, 0xdd, 0x3f, 0xce, 0x3f, 0xad, 0xf5, 0xe4, 0x3a, 0x78,
+    0x2f, 0x9d, 0x3a, 0x7d, 0xf3, 0x7d, 0x22, 0x87, 0x4a, 0xb6, 0x3c, 0xbd,
+    0xc8, 0x27, 0xb4, 0x04, 0xf1, 0xd1, 0x47, 0x95, 0xf4, 0xa6, 0x7f, 0xef,
+    0x20, 0x1d, 0xa1, 0xe3, 0x8d, 0x8e, 0x83, 0xa7, 0x7f, 0x5e, 0x3a, 0x6f,
+    0xdc, 0xe8, 0x69, 0xb2, 0xf0, 0xe4, 0x1d, 0x3d, 0xbd, 0x93, 0xa7, 0x4e,
+    0x75, 0xdd, 0x88, 0x89, 0xdc, 0xf1, 0x64, 0x3e, 0x0a, 0x87, 0x4c, 0x69,
+    0x21, 0x97, 0x38, 0x7d, 0x7e, 0x74, 0xff, 0x36, 0xec, 0xed, 0xaa, 0xac,
+    0x68, 0xa1, 0xe1, 0x0f, 0x8e, 0x87, 0xa7, 0xc0, 0x7b, 0x62, 0xce, 0x9e,
+    0x76, 0x30, 0x27, 0x49, 0xfa, 0x78, 0xfa, 0x26, 0x9f, 0xf5, 0x05, 0xc3,
+    0xc4, 0x14, 0x59, 0xd3, 0xff, 0x69, 0xc5, 0x8c, 0x10, 0x57, 0xb0, 0xe8,
+    0x59, 0xfe, 0x70, 0xee, 0x7f, 0xef, 0xdb, 0xca, 0xee, 0xfe, 0x74, 0xd8,
+    0xe9, 0xfe, 0x76, 0xbf, 0x76, 0x7e, 0xec, 0x74, 0xf9, 0x3d, 0xaa, 0x43,
+    0xa7, 0xfb, 0xa0, 0xed, 0x0f, 0xb0, 0x07, 0x40, 0x0f, 0x73, 0xf2, 0x59,
+    0xfc, 0x23, 0x5e, 0xfa, 0xf6, 0x3a, 0x78, 0x41, 0xb0, 0x0e, 0x8c, 0x3d,
+    0x44, 0x32, 0x9f, 0xf2, 0x6f, 0xaf, 0x9e, 0xf8, 0x1c, 0x13, 0xa7, 0xd5,
+    0xbe, 0xbc, 0x87, 0x47, 0x11, 0x12, 0x24, 0x1a, 0x42, 0x9f, 0x57, 0xea,
+    0x3f, 0xd3, 0xa7, 0xd7, 0xde, 0x75, 0xf4, 0x74, 0x30, 0x7a, 0xa2, 0x55,
+    0x3f, 0xd5, 0xa7, 0x63, 0x76, 0xe5, 0xe3, 0xa7, 0xff, 0xc1, 0xe3, 0xfd,
+    0xbb, 0xc3, 0x40, 0xd6, 0x9c, 0x05, 0x4c, 0x1c, 0x3a, 0x30, 0xfb, 0x11,
+    0x5e, 0x7f, 0x72, 0x80, 0xc0, 0xb8, 0x4e, 0x95, 0xca, 0xcb, 0x2f, 0x2e,
+    0xf8, 0x44, 0x56, 0xd3, 0xd5, 0x62, 0xe8, 0xf0, 0xc9, 0x69, 0x80, 0x4d,
+    0xb2, 0x32, 0xa5, 0x0d, 0xad, 0x0e, 0x04, 0x2e, 0x62, 0x19, 0x9d, 0x8c,
+    0xf5, 0x70, 0x8a, 0xe3, 0x3d, 0x42, 0x8c, 0x04, 0x42, 0x8d, 0xa8, 0x4a,
+    0xfa, 0x30, 0x0f, 0xe1, 0x09, 0x78, 0x8a, 0xfe, 0x14, 0xff, 0x48, 0x27,
+    0xf5, 0xd9, 0xdb, 0x55, 0x58, 0xd1, 0x79, 0xc3, 0xb7, 0x4c, 0x0d, 0x5b,
+    0x0a, 0xbe, 0x4f, 0xe2, 0x6f, 0x28, 0x4b, 0xb1, 0xad, 0xad, 0x4f, 0x87,
+    0xe3, 0x4c, 0x0a, 0xbd, 0x1d, 0x14, 0xfe, 0xbb, 0x3b, 0x6a, 0xab, 0x1a,
+    0x29, 0x69, 0xf7, 0x6d, 0x55, 0x63, 0x45, 0x85, 0x3f, 0xfe, 0x7c, 0x10,
+    0xbf, 0x1f, 0x7f, 0x60, 0xd2, 0xce, 0x9f, 0xbf, 0xea, 0x6d, 0x4b, 0x3a,
+    0x57, 0x62, 0x2c, 0x96, 0x67, 0x7e, 0xa3, 0x3f, 0xae, 0xce, 0xda, 0xaa,
+    0xc6, 0x8b, 0x2e, 0x7a, 0xe5, 0x15, 0x8a, 0xb2, 0x74, 0xeb, 0xbe, 0xac,
+    0xe9, 0x6a, 0xc7, 0x9d, 0xf9, 0x7c, 0x80, 0x74, 0xca, 0x6c, 0x74, 0xd5,
+    0xd6, 0x9a, 0x8c, 0x10, 0x9f, 0xea, 0xdc, 0x73, 0x7f, 0x3a, 0x87, 0x4f,
+    0xed, 0xb7, 0xd3, 0x87, 0xc8, 0x74, 0xf9, 0xf2, 0xf3, 0xe8, 0xe9, 0x3d,
+    0x1e, 0xdb, 0x26, 0x91, 0x48, 0xbb, 0x18, 0x4a, 0x4f, 0x53, 0x5a, 0x13,
+    0xa7, 0xea, 0xeb, 0xfa, 0xb8, 0x74, 0xe6, 0x59, 0x64, 0xa9, 0xfe, 0x76,
+    0xef, 0xee, 0xbe, 0x6e, 0x55, 0xc5, 0xfc, 0xcf, 0xa3, 0xa0, 0x28, 0xc9,
+    0xe1, 0x08, 0xa5, 0x5e, 0x49, 0x9f, 0x92, 0xb4, 0x0d, 0x7e, 0x74, 0xff,
+    0xfd, 0xc4, 0xf7, 0x33, 0x43, 0x8b, 0xff, 0x5c, 0xa6, 0x9d, 0x3f, 0x9d,
+    0xbe, 0xae, 0x50, 0x4e, 0x8c, 0x44, 0x5f, 0x56, 0xa4, 0xd3, 0xa4, 0xd3,
+    0xa4, 0xd3, 0xa1, 0xcd, 0x82, 0x82, 0x08, 0x21, 0x3f, 0xfe, 0xf6, 0x92,
+    0xd8, 0x3d, 0x71, 0xc0, 0xe2, 0x87, 0x4b, 0x73, 0xa6, 0xd7, 0xe7, 0x46,
+    0x1f, 0xd6, 0x94, 0xbc, 0x23, 0x32, 0x39, 0xd3, 0xf0, 0xba, 0xc5, 0xf0,
+    0xe9, 0x9a, 0xe7, 0x40, 0x4f, 0x49, 0x81, 0x4f, 0xca, 0x67, 0xff, 0xff,
+    0xb8, 0xfe, 0xd2, 0x6b, 0x4f, 0xee, 0x23, 0xf4, 0x0b, 0xa6, 0xb7, 0xca,
+    0x1d, 0x32, 0x6e, 0x74, 0xce, 0xb3, 0xa7, 0xff, 0xe6, 0xb8, 0xfe, 0xd6,
+    0xbf, 0xb9, 0x8b, 0xfa, 0xe0, 0x3a, 0x6b, 0x5c, 0xeb, 0xb9, 0x5b, 0x28,
+    0x86, 0x1c, 0xd9, 0x0e, 0xfb, 0x1f, 0x76, 0x17, 0x14, 0xa4, 0x30, 0xa7,
+    0xd4, 0x20, 0x3c, 0x63, 0x79, 0xf6, 0xfc, 0x5b, 0xe8, 0xac, 0xff, 0xeb,
+    0x97, 0x4d, 0xbb, 0x3b, 0x6a, 0xab, 0x1a, 0x28, 0xc9, 0xf5, 0xe7, 0xeb,
+    0x80, 0xe9, 0xf0, 0xd0, 0x1f, 0xe9, 0xd3, 0xff, 0x6f, 0x64, 0xef, 0x33,
+    0x05, 0xba, 0x3a, 0x57, 0x3a, 0x24, 0xb8, 0x51, 0xe2, 0x78, 0x6b, 0x25,
+    0xff, 0xb0, 0xf1, 0x59, 0xcd, 0x4f, 0x2b, 0xea, 0x1b, 0xfe, 0x87, 0x4c,
+    0xff, 0xd7, 0x53, 0x6e, 0xce, 0xda, 0xaa, 0xc6, 0x88, 0xe6, 0x7f, 0xf5,
+    0xcb, 0xa6, 0xdd, 0x9d, 0xb5, 0x55, 0x8d, 0x13, 0x94, 0xfe, 0xbb, 0x3b,
+    0x6a, 0xab, 0x1a, 0x2c, 0xc9, 0xfe, 0x6e, 0xa9, 0x77, 0x73, 0xc0, 0x3a,
+    0x7f, 0x95, 0x80, 0x71, 0x6f, 0xbb, 0xac, 0xe9, 0xfe, 0x07, 0x5f, 0xdc,
+    0xad, 0xda, 0x74, 0xfe, 0xcd, 0x77, 0xb9, 0xbe, 0x8e, 0x95, 0xca, 0xca,
+    0x2a, 0x9c, 0xf9, 0xa7, 0x33, 0xfa, 0xec, 0xed, 0xaa, 0xac, 0x68, 0xb7,
+    0x67, 0xe1, 0xab, 0xbb, 0xb7, 0x0e, 0x9c, 0x9b, 0x80, 0xe9, 0xff, 0x53,
+    0x6e, 0xce, 0xda, 0xaa, 0xc6, 0x8a, 0x42, 0x57, 0x59, 0x12, 0x9d, 0x2e,
+    0x58, 0xe4, 0xff, 0xd7, 0x53, 0x6e, 0xce, 0xda, 0xaa, 0xc6, 0x89, 0x4a,
+    0x36, 0x56, 0xc2, 0xc2, 0x8a, 0xd5, 0xe8, 0xfc, 0x10, 0xe4, 0x13, 0xbf,
+    0x43, 0x4d, 0x51, 0xbc, 0xfa, 0xe4, 0xd7, 0xeb, 0x3a, 0x7f, 0xd4, 0xdb,
+    0xb3, 0xb6, 0xaa, 0xb1, 0xa2, 0x76, 0x9b, 0x65, 0x73, 0xa7, 0xff, 0xc8,
+    0x1f, 0xd6, 0xea, 0xa8, 0x22, 0xe3, 0x96, 0x3a, 0x7f, 0x9d, 0xaf, 0xdd,
+    0x9f, 0xbb, 0x1d, 0x2b, 0x96, 0x8f, 0x1e, 0x25, 0x50, 0xd0, 0xaa, 0x4f,
+    0xff, 0x5d, 0xf6, 0xfe, 0x84, 0x19, 0xe7, 0x14, 0x01, 0xd3, 0xff, 0x52,
+    0xf9, 0x96, 0xae, 0x3f, 0xd6, 0x9d, 0x3f, 0xf0, 0xe7, 0x2b, 0x6c, 0xd0,
+    0xd6, 0xe7, 0x4d, 0x7f, 0x70, 0x51, 0x0d, 0xa4, 0x48, 0x6a, 0xa6, 0x75,
+    0xc6, 0x35, 0xa4, 0x2b, 0xf8, 0x6c, 0x4f, 0xff, 0xc1, 0xaf, 0x5d, 0x9a,
+    0x71, 0xdc, 0x1a, 0xd3, 0x80, 0xe9, 0xf7, 0x6d, 0x55, 0x63, 0x44, 0x59,
+    0x3f, 0xea, 0x6d, 0xd9, 0xdb, 0x55, 0x58, 0xd1, 0x2e, 0xcf, 0xff, 0xd8,
+    0x1e, 0x3f, 0xdb, 0xbc, 0x34, 0x0d, 0x69, 0xc0, 0x54, 0xae, 0xc4, 0x6c,
+    0xac, 0xce, 0xfd, 0x2a, 0x7f, 0xf5, 0xcb, 0xa6, 0xdd, 0x9d, 0xb5, 0x55,
+    0x8d, 0x13, 0x14, 0xfb, 0xb6, 0xaa, 0xb1, 0xa2, 0xa9, 0x96, 0x1d, 0x18,
+    0x78, 0x4a, 0x19, 0xcf, 0xff, 0xfe, 0xed, 0x73, 0x76, 0xe7, 0xae, 0xe5,
+    0x6b, 0xa8, 0xcf, 0xb8, 0x9d, 0x69, 0xd1, 0x72, 0x27, 0x28, 0x8a, 0x7f,
+    0xf5, 0xcb, 0xa6, 0xdd, 0x9d, 0xb5, 0x55, 0x8d, 0x13, 0xa4, 0xfe, 0x4a,
+    0xeb, 0xb6, 0xaf, 0x1d, 0x3e, 0x61, 0xd8, 0x7d, 0x1d, 0x3f, 0x33, 0x89,
+    0x7b, 0x04, 0xe8, 0x43, 0xd5, 0xd1, 0x44, 0xe4, 0xe3, 0x9d, 0x71, 0xa1,
+    0x9f, 0xfb, 0xfd, 0x79, 0xf7, 0xbb, 0xf6, 0x11, 0x67, 0x42, 0xcf, 0xd3,
+    0x85, 0x73, 0xfe, 0xa6, 0xdd, 0x9d, 0xb5, 0x55, 0x8d, 0x13, 0xbc, 0xfb,
+    0xdf, 0xd2, 0xd0, 0xa9, 0xff, 0x0b, 0xfb, 0x35, 0x99, 0xbb, 0x4e, 0x95,
+    0xc1, 0x4f, 0xaf, 0x23, 0x1c, 0x59, 0x15, 0x25, 0x78, 0x9e, 0x7f, 0xf5,
+    0xcb, 0xa6, 0xdd, 0x9d, 0xb5, 0x55, 0x8d, 0x14, 0x2c, 0xff, 0xff, 0xee,
+    0x7e, 0xb5, 0xd3, 0x6e, 0xb7, 0x3f, 0xf3, 0x8e, 0x6c, 0xa7, 0xee, 0xc1,
+    0xd3, 0xef, 0xf7, 0xf2, 0x58, 0xe9, 0xf6, 0x03, 0x28, 0x4e, 0x9c, 0xe0,
+    0xbb, 0x63, 0xcd, 0x12, 0x98, 0x44, 0x7f, 0x8c, 0x32, 0xe7, 0xff, 0x5c,
+    0xba, 0x6d, 0xd9, 0xdb, 0x55, 0x58, 0xd1, 0x49, 0x4f, 0xff, 0xec, 0xd5,
+    0xdf, 0x71, 0x8e, 0x52, 0xfd, 0xc7, 0xf7, 0xeb, 0x3a, 0x1d, 0x7e, 0x57,
+    0x68, 0xcd, 0x1a, 0x73, 0x68, 0xcd, 0x7a, 0x46, 0xb9, 0x48, 0x40, 0x56,
+    0xf4, 0x6a, 0xdf, 0x93, 0x5f, 0xab, 0xcf, 0xeb, 0xb3, 0xb6, 0xaa, 0xb1,
+    0xa2, 0x24, 0x9f, 0xfd, 0x72, 0xe9, 0xb7, 0x67, 0x6d, 0x55, 0x63, 0x44,
+    0xbd, 0x3d, 0xdf, 0xfd, 0xa3, 0xa7, 0xdd, 0x02, 0xd3, 0x47, 0x4f, 0xe4,
+    0x1f, 0x7d, 0x58, 0xb9, 0xd3, 0xff, 0xb9, 0x79, 0xc4, 0x0a, 0xf8, 0x1c,
+    0xee, 0xe7, 0x4c, 0xfe, 0x3a, 0x7f, 0xf7, 0xe1, 0x4e, 0xfd, 0x61, 0x57,
+    0xf4, 0x2c, 0x1d, 0x0d, 0x47, 0x32, 0x19, 0x01, 0x3b, 0x42, 0xb3, 0xff,
+    0x53, 0x1a, 0x7b, 0xd5, 0xc7, 0xdd, 0x83, 0xa7, 0xfe, 0x63, 0xe7, 0xd1,
+    0x7b, 0xd5, 0x79, 0xd8, 0x3a, 0x0e, 0x9f, 0x98, 0x6d, 0x7a, 0xaf, 0x1d,
+    0x0e, 0x88, 0x5c, 0x4c, 0xa0, 0xa9, 0xba, 0xe7, 0x40, 0x55, 0x3d, 0x21,
+    0x1b, 0x11, 0x86, 0xf4, 0xf2, 0xf4, 0x33, 0x15, 0x16, 0xcf, 0xf2, 0x50,
+    0xff, 0xe6, 0x1d, 0x43, 0xa7, 0x93, 0x60, 0x2b, 0x9d, 0x3d, 0x6a, 0xab,
+    0x1a, 0x29, 0x78, 0x60, 0xf4, 0xba, 0x4b, 0x3e, 0x1f, 0x6d, 0x8c, 0x9d,
+    0x3f, 0xe7, 0x17, 0xe7, 0xcf, 0xc7, 0xfb, 0x1d, 0x3b, 0xfa, 0xd1, 0xd3,
+    0xda, 0xcf, 0x68, 0xe8, 0x09, 0xfe, 0xb0, 0x81, 0xe1, 0xc9, 0xfe, 0x06,
+    0xba, 0xfb, 0xb5, 0x16, 0x74, 0xef, 0x55, 0xe3, 0xa7, 0xfa, 0xb6, 0xf9,
+    0xb7, 0xec, 0x3a, 0xb9, 0xd0, 0xe8, 0x97, 0xa3, 0x9f, 0xc7, 0x67, 0xf9,
+    0x34, 0xc2, 0x0f, 0x9c, 0x07, 0x43, 0x4f, 0x99, 0x65, 0xf3, 0xff, 0x76,
+    0xf3, 0x83, 0xe7, 0x1d, 0x74, 0x27, 0x46, 0x1f, 0x42, 0x11, 0x4e, 0xeb,
+    0xac, 0xe9, 0xf9, 0xc5, 0x8f, 0x22, 0x87, 0x4f, 0xdd, 0x03, 0xdb, 0x16,
+    0x74, 0xcd, 0xc3, 0xa7, 0x38, 0x34, 0x74, 0x39, 0xee, 0x04, 0xb1, 0x91,
+    0x59, 0xf7, 0x3f, 0x53, 0x04, 0xe9, 0xfe, 0x7e, 0x6a, 0xbc, 0xfd, 0x54,
+    0x74, 0xff, 0x97, 0x41, 0xfa, 0xc3, 0x5c, 0x77, 0x3a, 0x02, 0x7f, 0x48,
+    0x73, 0x3d, 0xd0, 0x7d, 0xbc, 0x74, 0xe4, 0x67, 0xc7, 0x47, 0x0f, 0x0b,
+    0x44, 0xd0, 0x14, 0xc9, 0xf9, 0x0a, 0x2f, 0x31, 0xcf, 0xff, 0x9d, 0xa2,
+    0xfb, 0x7d, 0x63, 0x5c, 0xc5, 0x5d, 0x01, 0xd3, 0xf7, 0xc5, 0xe7, 0xab,
+    0xc7, 0x4a, 0xc7, 0x4d, 0xbe, 0xb0, 0xdf, 0x51, 0x74, 0x2d, 0x18, 0x95,
+    0x09, 0x89, 0xcf, 0x7b, 0x47, 0x4e, 0xce, 0xe8, 0xe8, 0xb1, 0xb8, 0xbc,
+    0x3b, 0x3f, 0xc0, 0x70, 0x7d, 0xbc, 0xe2, 0xa8, 0xe8, 0xc3, 0xe0, 0x42,
+    0x39, 0xff, 0xff, 0xb8, 0xfd, 0xde, 0xc9, 0xbf, 0xc5, 0x2b, 0xe6, 0xb9,
+    0x56, 0x71, 0x09, 0xd3, 0xfb, 0x94, 0xc2, 0x75, 0xf6, 0x3a, 0x6c, 0x59,
+    0xd0, 0x14, 0x5f, 0xd3, 0xbd, 0xe3, 0x39, 0xf2, 0xa4, 0x5b, 0xe8, 0xe9,
+    0xf5, 0x5e, 0xce, 0xe8, 0xe8, 0x09, 0xe8, 0x2c, 0xa2, 0x7d, 0xca, 0x14,
+    0x59, 0xd0, 0xe7, 0x8f, 0x84, 0x53, 0x02, 0xc7, 0x4b, 0x47, 0x4c, 0x8a,
+    0x68, 0xd3, 0x7e, 0x2d, 0x3c, 0xe0, 0xab, 0x1d, 0x2b, 0x9d, 0x92, 0xbc,
+    0x16, 0x8c, 0x84, 0x5e, 0xe4, 0x69, 0x0a, 0x56, 0x23, 0x95, 0xe9, 0x02,
+    0xc6, 0xf9, 0x08, 0x9a, 0x8d, 0x58, 0x10, 0xfa, 0x18, 0x5f, 0xea, 0x1b,
+    0xfe, 0x86, 0x45, 0xfa, 0x37, 0xd2, 0xe9, 0xfd, 0x76, 0x76, 0xd5, 0x56,
+    0x34, 0x53, 0x93, 0xfe, 0x4e, 0xd6, 0xb9, 0x98, 0x36, 0x3a, 0x7f, 0x22,
+    0xc2, 0xfa, 0xfc, 0x4e, 0x9f, 0xf9, 0x44, 0xdf, 0x43, 0x81, 0xe5, 0x32,
+    0x74, 0xff, 0xb3, 0x8f, 0xdc, 0xb9, 0x96, 0x59, 0x2a, 0x64, 0x64, 0xe9,
+    0xb6, 0xb8, 0x29, 0x84, 0xf0, 0xef, 0xc6, 0x57, 0xe8, 0xaa, 0x90, 0x67,
+    0xdd, 0xb5, 0x55, 0x8d, 0x15, 0xe4, 0xff, 0xfd, 0x81, 0xe3, 0xfd, 0xbb,
+    0xc3, 0x40, 0xd6, 0x9c, 0x05, 0x4a, 0xec, 0x44, 0x7d, 0xf9, 0x9c, 0xff,
+    0xd7, 0x53, 0x6e, 0xce, 0xda, 0xaa, 0xc6, 0x89, 0x1e, 0x72, 0x01, 0xce,
+    0x9d, 0x6c, 0x59, 0x57, 0x17, 0x53, 0xee, 0xda, 0xaa, 0xc6, 0x89, 0x22,
+    0x7f, 0xfe, 0x74, 0xea, 0x2a, 0x71, 0xd9, 0xfc, 0x9c, 0xad, 0x8e, 0x99,
+    0xb7, 0x3a, 0x2e, 0x30, 0xaf, 0x86, 0x73, 0xec, 0xe5, 0xd8, 0xb3, 0xa5,
+    0x75, 0x1f, 0x17, 0x8e, 0xe7, 0xfe, 0xba, 0x9b, 0x76, 0x76, 0xd5, 0x56,
+    0x34, 0x49, 0x53, 0xee, 0xda, 0xaa, 0xc6, 0x8b, 0xc6, 0x7d, 0xad, 0x7b,
+    0x2c, 0x74, 0xff, 0x36, 0xec, 0xed, 0xaa, 0xac, 0x68, 0x93, 0x65, 0x76,
+    0x22, 0x7f, 0xa6, 0x74, 0x4f, 0x33, 0x3c, 0x3a, 0x7f, 0xfd, 0xaf, 0xeb,
+    0x7c, 0xc5, 0x14, 0xa6, 0xe6, 0xfe, 0x3a, 0x73, 0x03, 0xb1, 0xd3, 0x00,
+    0x4e, 0x9a, 0xfe, 0xe7, 0x45, 0x0e, 0x0b, 0xe9, 0x63, 0xe8, 0xec, 0x3b,
+    0x67, 0x49, 0xb1, 0xfb, 0x69, 0x85, 0xe1, 0x8c, 0x55, 0x23, 0x48, 0x62,
+    0x1d, 0xab, 0x2c, 0xe4, 0x70, 0xbe, 0x28, 0xfe, 0x1e, 0x1f, 0x61, 0xad,
+    0x0f, 0x2b, 0xaa, 0x73, 0x69, 0x47, 0xcd, 0x9c, 0x6a, 0x0c, 0xb6, 0x0c,
+    0xbe, 0x9e, 0x65, 0x25, 0x9b, 0x5a, 0xdf, 0xb1, 0x6f, 0x4c, 0x61, 0x4a,
+    0x47, 0xaa, 0xbc, 0xa1, 0xc6, 0x2d, 0x23, 0x67, 0x6b, 0x87, 0x15, 0xe6,
+    0x0d, 0xd7, 0xca, 0x45, 0x2d, 0x5a, 0x3f, 0xd0, 0x4e, 0xac, 0xdf, 0x51,
+    0xaa, 0x0d, 0x2e, 0xd3, 0x55, 0x84, 0xff, 0xad, 0xcd, 0x77, 0xf6, 0x86,
+    0x9a, 0xf5, 0x28, 0xcd, 0x99, 0x7a, 0x57, 0xf2, 0xb9, 0xbe, 0xcf, 0xf1,
+    0x2a, 0xad, 0x13, 0xe0,
 };
 
-static const unsigned kPreloadedHSTSBits = 177313;
+static const unsigned kPreloadedHSTSBits = 194621;
 
-static const unsigned kHSTSRootPosition = 176714;
+static const unsigned kHSTSRootPosition = 194018;
 
 #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 fdcc0e1..69bb4059 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -232,6 +232,8 @@
     { "name": "googlecode.com", "include_subdomains": true, "pins": "google" },
     { "name": "dl.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
     { "name": "translate.googleapis.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "gvt2.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    { "name": "gvt3.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
 
     { "name": "webfilings.appspot.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
     { "name": "webfilings-mirror-hrd.appspot.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
@@ -2618,7 +2620,245 @@
     { "name": "xpd.se", "include_subdomains": true, "mode": "force-https" },
     { "name": "zbasenem.pl", "include_subdomains": true, "mode": "force-https" },
     { "name": "zifb.in", "include_subdomains": true, "mode": "force-https" },
-    { "name": "zlatosnadno.cz", "include_subdomains": true, "mode": "force-https" }
+    { "name": "zlatosnadno.cz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "4sqsu.eu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "abecodes.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "abiapp.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "adambyers.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "aes256.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "akselimedia.fi", "include_subdomains": true, "mode": "force-https" },
+    { "name": "alaninkenya.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "alethearose.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "anakros.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "andrewimeson.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "antoniomarques.eu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "apachehaus.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "apibot.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "aponow.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "aranycsillag.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "arrayify.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "auszeit.bio", "include_subdomains": true, "mode": "force-https" },
+    { "name": "av.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "azirevpn.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bardiharborow.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "beach-inspector.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "biddl.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bigdinosaur.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bownty.dk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "braineet.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "branchtrack.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "brks.xyz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "businesshosting.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bygningsregistrering.dk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "bysymphony.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cardoni.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "carlosalves.info", "include_subdomains": true, "mode": "force-https" },
+    { "name": "catnapstudios.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "chippy.ch", "include_subdomains": true, "mode": "force-https" },
+    { "name": "chriswarrick.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "chroniclesofgeorge.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "clevisto.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cloudpebble.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "coindam.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "completionist.audio", "include_subdomains": true, "mode": "force-https" },
+    { "name": "cpvmatch.eu", "include_subdomains": true, "mode": "force-https" },
+    { "name": "d42.no", "include_subdomains": true, "mode": "force-https" },
+    { "name": "daknob.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "darkengine.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dbgamestudio.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "desmaakvanplanten.be", "include_subdomains": true, "mode": "force-https" },
+    { "name": "devklog.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dnmlab.it", "include_subdomains": true, "mode": "force-https" },
+    { "name": "dropboxer.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "drumbandesperanto.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "eduid.se", "include_subdomains": true, "mode": "force-https" },
+    { "name": "electromc.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "erisrenee.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "expoundite.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "f2f.cash", "include_subdomains": true, "mode": "force-https" },
+    { "name": "falconvintners.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fangs.ink", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fatherhood.gov", "include_subdomains": true, "mode": "force-https" },
+    { "name": "feen.us", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ffbans.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fiftyshadesofluca.ml", "include_subdomains": true, "mode": "force-https" },
+    { "name": "flushstudios.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "foodwise.marketing", "include_subdomains": true, "mode": "force-https" },
+    { "name": "foreignexchangeresource.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fretscha.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fruchthof24.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "frusky.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "frusky.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "fteproxy.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "g2g.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "gambitprint.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "gamercredo.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "genuxation.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "getnikola.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "github.party", "include_subdomains": true, "mode": "force-https" },
+    { "name": "go-zh.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "gopay.cz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "goshop.cz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "grigalanzsoftware.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "grimm-gastrobedarf.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "h2check.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "haircrazy.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "happyteamlabs.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "haveibeenpwned.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "heftkaufen.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "herzbotschaft.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hiv.gov", "include_subdomains": true, "mode": "force-https" },
+    { "name": "hs-group.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "impex.com.bd", "include_subdomains": true, "mode": "force-https" },
+    { "name": "informnapalm.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "iqualtech.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "isimonbrown.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ix8.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jamesbywater.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jamesbywater.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jamesbywater.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jamesbywater.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jamielinux.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "jogorama.com.br", "include_subdomains": true, "mode": "force-https" },
+    { "name": "juliansimioni.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "justlikethat.hosting", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kalevlamps.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "korinar.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kpdyer.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "kredite.sale", "include_subdomains": true, "mode": "force-https" },
+    { "name": "legoutdesplantes.be", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lellyboi.ml", "include_subdomains": true, "mode": "force-https" },
+    { "name": "leninalbertop.com.ve", "include_subdomains": true, "mode": "force-https" },
+    { "name": "libfte.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "limitededitioncomputers.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "limitededitionsolutions.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "linguaquote.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lloyd-day.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "luxwatch.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lymia.moe", "include_subdomains": true, "mode": "force-https" },
+    { "name": "lyst.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mammaw.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "markprof.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "martijnvhoof.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "maximelouet.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "me.net.nz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mebio.us", "include_subdomains": true, "mode": "force-https" },
+    { "name": "medtehnika.ua", "include_subdomains": true, "mode": "force-https" },
+    { "name": "meetingmanage.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "meetings2.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "meritz.rocks", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mertcangokgoz.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mim.properties", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mjanja.ch", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mobobe.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "modeldimension.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "moriz.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mp3juices.is", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mthode.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "multigamecard.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "mygretchen.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "naiharngym.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ndarville.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nella-project.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nellacms.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nellacms.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nellafw.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nextend.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "nmd.so", "include_subdomains": true, "mode": "force-https" },
+    { "name": "null.tips", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ocrami.us", "include_subdomains": true, "mode": "force-https" },
+    { "name": "oguya.ch", "include_subdomains": true, "mode": "force-https" },
+    { "name": "patechmasters.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "payments-reference.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pbprint.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "phcorner.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "pieterhordijk.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "poedgirl.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "poiema.com.sg", "include_subdomains": true, "mode": "force-https" },
+    { "name": "posttigo.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "presidentials2016.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "projectascension.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "prospo.co", "include_subdomains": true, "mode": "force-https" },
+    { "name": "purewebmasters.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "qualityhomesystems.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "quli.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "railgun.ac", "include_subdomains": true, "mode": "force-https" },
+    { "name": "raydobe.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "redlink.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "report-uri.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "rmmanfredi.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "roeper.party", "include_subdomains": true, "mode": "force-https" },
+    { "name": "roosterpgplus.nl", "include_subdomains": true, "mode": "force-https" },
+    { "name": "roquecenter.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ryan-goldstein.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "safescan.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sarahlicity.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "schreibnacht.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "screenlight.tv", "include_subdomains": true, "mode": "force-https" },
+    { "name": "search-one.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "securitysnobs.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "shamka.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "shanewadleigh.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "shasso.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "shoprose.ru", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sitesko.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sizzle.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "slope.haus", "include_subdomains": true, "mode": "force-https" },
+    { "name": "snailing.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "snazel.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "sny.no", "include_subdomains": true, "mode": "force-https" },
+    { "name": "soccergif.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "soci.ml", "include_subdomains": true, "mode": "force-https" },
+    { "name": "solihullcarnival.co.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "solihulllionsclub.org.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "soulfulglamour.uk", "include_subdomains": true, "mode": "force-https" },
+    { "name": "spyroszarzonis.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "stablelib.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "stereochro.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "stewartremodelingadvantage.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "streamingmagazin.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "talideon.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tdelmas.ovh", "include_subdomains": true, "mode": "force-https" },
+    { "name": "techhub.ml", "include_subdomains": true, "mode": "force-https" },
+    { "name": "thecoffeehouse.xyz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "theweilai.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tonytan.cn", "include_subdomains": true, "mode": "force-https" },
+    { "name": "topbargains.com.au", "include_subdomains": true, "mode": "force-https" },
+    { "name": "totem-eshop.cz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tribaldos.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tuxgeo.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "tzappa.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ubanquity.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "uega.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ulabox.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "univz.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "ust.space", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vbh2o.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "votocek.cz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "votockova.cz", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vrtak-cz.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "vzk.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wearvr.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "webmarketingfestival.it", "include_subdomains": true, "mode": "force-https" },
+    { "name": "webogram.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "webswitch.io", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wesecom.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "when-release.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "when.fm", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wilf1rst.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "williamsapiens.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wit.ai", "include_subdomains": true, "mode": "force-https" },
+    { "name": "worldcubeassociation.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "wurzelzwerg.net", "include_subdomains": true, "mode": "force-https" },
+    { "name": "xcoop.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "xho.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "xiaolvmu.me", "include_subdomains": true, "mode": "force-https" },
+    { "name": "yello.website", "include_subdomains": true, "mode": "force-https" },
+    { "name": "yunzhu.li", "include_subdomains": true, "mode": "force-https" },
+    { "name": "yunzhu.org", "include_subdomains": true, "mode": "force-https" },
+    { "name": "zeitpunkt-kulturmagazin.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "zentraler-kreditausschuss.de", "include_subdomains": true, "mode": "force-https" },
+    { "name": "zhang-hao.com", "include_subdomains": true, "mode": "force-https" }
   ],
 
   // |ReportUMAOnPinFailure| uses these to report which domain was associated
@@ -2883,6 +3123,8 @@
     "FACEBOOK_COM",
     "SPIDEROAK_COM",
     "BLOGGER_COM",
-    "CHROME_COM"
+    "CHROME_COM",
+    "GVT3_COM",
+    "GVT2_COM"
   ]
 }
diff --git a/net/proxy/proxy_resolver_v8.cc b/net/proxy/proxy_resolver_v8.cc
index 8a15a69..206cd34 100644
--- a/net/proxy/proxy_resolver_v8.cc
+++ b/net/proxy/proxy_resolver_v8.cc
@@ -367,6 +367,7 @@
       if (!has_initialized_v8_) {
 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
         gin::V8Initializer::LoadV8Snapshot();
+        gin::V8Initializer::LoadV8Natives();
 #endif
 
         gin::IsolateHolder::Initialize(
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index 38b25743..76a2c32 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -60,8 +60,8 @@
   dict->SetString("packet_sequence_number",
                   base::Uint64ToString(serialized_packet.sequence_number));
   dict->SetInteger("size", packet_size);
-  dict->SetInteger("sent_time_us",
-                   static_cast<int>(sent_time.ToDebuggingValue()));
+  dict->SetString("sent_time_us",
+                  base::Int64ToString(sent_time.ToDebuggingValue()));
   return dict.Pass();
 }
 
@@ -110,9 +110,9 @@
   scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
   dict->SetString("largest_observed",
                   base::Uint64ToString(frame->largest_observed));
-  dict->SetInteger(
+  dict->SetString(
       "delta_time_largest_observed_us",
-      static_cast<int>(frame->delta_time_largest_observed.ToMicroseconds()));
+      base::Int64ToString(frame->delta_time_largest_observed.ToMicroseconds()));
   dict->SetInteger("entropy_hash",
                    frame->entropy_hash);
   dict->SetBoolean("truncated", frame->is_truncated);
@@ -140,8 +140,8 @@
        it != received_times.end(); ++it) {
     base::DictionaryValue* info = new base::DictionaryValue();
     info->SetInteger("sequence_number", static_cast<int>(it->first));
-    info->SetInteger("received",
-                     static_cast<int>(it->second.ToDebuggingValue()));
+    info->SetString("received",
+                    base::Int64ToString(it->second.ToDebuggingValue()));
     received->Append(info);
   }
 
diff --git a/net/server/http_server.cc b/net/server/http_server.cc
index f496dc7..f849e70 100644
--- a/net/server/http_server.cc
+++ b/net/server/http_server.cc
@@ -417,8 +417,8 @@
         case ST_VALUE:
           base::TrimWhitespaceASCII(buffer, base::TRIM_LEADING, &header_value);
           it = info->headers.find(header_name);
-          // See last paragraph ("Multiple message-header fields...")
-          // of www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
+          // See the second paragraph ("A sender MUST NOT generate multiple
+          // header fields...") of tools.ietf.org/html/rfc7230#section-3.2.2.
           if (it == info->headers.end()) {
             info->headers[header_name] = header_value;
           } else {
diff --git a/net/socket/client_socket_pool_manager.cc b/net/socket/client_socket_pool_manager.cc
index 4af9c9b..7820cf9 100644
--- a/net/socket/client_socket_pool_manager.cc
+++ b/net/socket/client_socket_pool_manager.cc
@@ -73,7 +73,7 @@
                          RequestPriority request_priority,
                          HttpNetworkSession* session,
                          const ProxyInfo& proxy_info,
-                         bool want_spdy_over_npn,
+                         bool expect_spdy,
                          const SSLConfig& ssl_config_for_origin,
                          const SSLConfig& ssl_config_for_proxy,
                          bool force_tunnel,
@@ -182,14 +182,10 @@
                                                      resolution_callback,
                                                      combine_connect_and_write);
         // Set ssl_params, and unset proxy_tcp_params
-        ssl_params = new SSLSocketParams(proxy_tcp_params,
-                                         NULL,
-                                         NULL,
-                                         *proxy_host_port.get(),
-                                         ssl_config_for_proxy,
-                                         PRIVACY_MODE_DISABLED,
-                                         load_flags,
-                                         want_spdy_over_npn);
+        ssl_params =
+            new SSLSocketParams(proxy_tcp_params, NULL, NULL,
+                                *proxy_host_port.get(), ssl_config_for_proxy,
+                                PRIVACY_MODE_DISABLED, load_flags, expect_spdy);
         proxy_tcp_params = NULL;
       }
 
@@ -240,15 +236,9 @@
                                                  resolution_callback,
                                                  combine_connect_and_write);
     }
-    scoped_refptr<SSLSocketParams> ssl_params =
-        new SSLSocketParams(ssl_tcp_params,
-                            socks_params,
-                            http_proxy_params,
-                            origin_host_port,
-                            ssl_config_for_origin,
-                            privacy_mode,
-                            load_flags,
-                            want_spdy_over_npn);
+    scoped_refptr<SSLSocketParams> ssl_params = new SSLSocketParams(
+        ssl_tcp_params, socks_params, http_proxy_params, origin_host_port,
+        ssl_config_for_origin, privacy_mode, load_flags, expect_spdy);
     SSLClientSocketPool* ssl_pool = NULL;
     if (proxy_info.is_direct()) {
       ssl_pool = session->GetSSLSocketPool(socket_pool_type);
@@ -394,7 +384,7 @@
     RequestPriority request_priority,
     HttpNetworkSession* session,
     const ProxyInfo& proxy_info,
-    bool want_spdy_over_npn,
+    bool expect_spdy,
     const SSLConfig& ssl_config_for_origin,
     const SSLConfig& ssl_config_for_proxy,
     PrivacyMode privacy_mode,
@@ -405,10 +395,10 @@
   DCHECK(socket_handle);
   return InitSocketPoolHelper(
       group_type, endpoint, request_extra_headers, request_load_flags,
-      request_priority, session, proxy_info, want_spdy_over_npn,
-      ssl_config_for_origin, ssl_config_for_proxy, /*force_tunnel=*/false,
-      privacy_mode, net_log, 0, socket_handle,
-      HttpNetworkSession::NORMAL_SOCKET_POOL, resolution_callback, callback);
+      request_priority, session, proxy_info, expect_spdy, ssl_config_for_origin,
+      ssl_config_for_proxy, /*force_tunnel=*/false, privacy_mode, net_log, 0,
+      socket_handle, HttpNetworkSession::NORMAL_SOCKET_POOL,
+      resolution_callback, callback);
 }
 
 int InitSocketHandleForWebSocketRequest(
@@ -419,7 +409,7 @@
     RequestPriority request_priority,
     HttpNetworkSession* session,
     const ProxyInfo& proxy_info,
-    bool want_spdy_over_npn,
+    bool expect_spdy,
     const SSLConfig& ssl_config_for_origin,
     const SSLConfig& ssl_config_for_proxy,
     PrivacyMode privacy_mode,
@@ -430,10 +420,10 @@
   DCHECK(socket_handle);
   return InitSocketPoolHelper(
       group_type, endpoint, request_extra_headers, request_load_flags,
-      request_priority, session, proxy_info, want_spdy_over_npn,
-      ssl_config_for_origin, ssl_config_for_proxy, /*force_tunnel=*/true,
-      privacy_mode, net_log, 0, socket_handle,
-      HttpNetworkSession::WEBSOCKET_SOCKET_POOL, resolution_callback, callback);
+      request_priority, session, proxy_info, expect_spdy, ssl_config_for_origin,
+      ssl_config_for_proxy, /*force_tunnel=*/true, privacy_mode, net_log, 0,
+      socket_handle, HttpNetworkSession::WEBSOCKET_SOCKET_POOL,
+      resolution_callback, callback);
 }
 
 int InitSocketHandleForRawConnect(
@@ -475,7 +465,7 @@
   return InitSocketPoolHelper(
       ClientSocketPoolManager::SSL_GROUP, endpoint, request_extra_headers,
       request_load_flags, request_priority, session, proxy_info,
-      /*want_spdy_over_npn=*/false, ssl_config_for_origin, ssl_config_for_proxy,
+      /*expect_spdy=*/false, ssl_config_for_origin, ssl_config_for_proxy,
       /*force_tunnel=*/true, privacy_mode, net_log, 0, socket_handle,
       HttpNetworkSession::NORMAL_SOCKET_POOL, OnHostResolutionCallback(),
       callback);
@@ -489,7 +479,7 @@
     RequestPriority request_priority,
     HttpNetworkSession* session,
     const ProxyInfo& proxy_info,
-    bool want_spdy_over_npn,
+    bool expect_spdy,
     const SSLConfig& ssl_config_for_origin,
     const SSLConfig& ssl_config_for_proxy,
     PrivacyMode privacy_mode,
@@ -497,11 +487,10 @@
     int num_preconnect_streams) {
   return InitSocketPoolHelper(
       group_type, endpoint, request_extra_headers, request_load_flags,
-      request_priority, session, proxy_info, want_spdy_over_npn,
-      ssl_config_for_origin, ssl_config_for_proxy, /*force_tunnel=*/false,
-      privacy_mode, net_log, num_preconnect_streams, NULL,
-      HttpNetworkSession::NORMAL_SOCKET_POOL, OnHostResolutionCallback(),
-      CompletionCallback());
+      request_priority, session, proxy_info, expect_spdy, ssl_config_for_origin,
+      ssl_config_for_proxy, /*force_tunnel=*/false, privacy_mode, net_log,
+      num_preconnect_streams, NULL, HttpNetworkSession::NORMAL_SOCKET_POOL,
+      OnHostResolutionCallback(), CompletionCallback());
 }
 
 }  // namespace net
diff --git a/net/socket/client_socket_pool_manager.h b/net/socket/client_socket_pool_manager.h
index 6b8a68e..d8d22a1b 100644
--- a/net/socket/client_socket_pool_manager.h
+++ b/net/socket/client_socket_pool_manager.h
@@ -94,7 +94,7 @@
 // |resolution_callback| will be invoked after the the hostname is
 // resolved.  If |resolution_callback| does not return OK, then the
 // connection will be aborted with that value.
-// If |want_spdy_over_ssl| is true, then after the SSL handshake is complete,
+// If |expect_spdy| is true, then after the SSL handshake is complete,
 // SPDY must have been negotiated or else it will be considered an error.
 int InitSocketHandleForHttpRequest(
     ClientSocketPoolManager::SocketGroupType group_type,
@@ -104,7 +104,7 @@
     RequestPriority request_priority,
     HttpNetworkSession* session,
     const ProxyInfo& proxy_info,
-    bool want_spdy_over_npn,
+    bool expect_spdy,
     const SSLConfig& ssl_config_for_origin,
     const SSLConfig& ssl_config_for_proxy,
     PrivacyMode privacy_mode,
@@ -130,7 +130,7 @@
     RequestPriority request_priority,
     HttpNetworkSession* session,
     const ProxyInfo& proxy_info,
-    bool want_spdy_over_npn,
+    bool expect_spdy,
     const SSLConfig& ssl_config_for_origin,
     const SSLConfig& ssl_config_for_proxy,
     PrivacyMode privacy_mode,
@@ -179,7 +179,7 @@
     RequestPriority request_priority,
     HttpNetworkSession* session,
     const ProxyInfo& proxy_info,
-    bool want_spdy_over_npn,
+    bool expect_spdy,
     const SSLConfig& ssl_config_for_origin,
     const SSLConfig& ssl_config_for_proxy,
     PrivacyMode privacy_mode,
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index a2a2a2a..53bf8142 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -34,7 +34,7 @@
     const SSLConfig& ssl_config,
     PrivacyMode privacy_mode,
     int load_flags,
-    bool want_spdy_over_npn)
+    bool expect_spdy)
     : direct_params_(direct_params),
       socks_proxy_params_(socks_proxy_params),
       http_proxy_params_(http_proxy_params),
@@ -42,7 +42,7 @@
       ssl_config_(ssl_config),
       privacy_mode_(privacy_mode),
       load_flags_(load_flags),
-      want_spdy_over_npn_(want_spdy_over_npn),
+      expect_spdy_(expect_spdy),
       ignore_limits_(false) {
   if (direct_params_.get()) {
     DCHECK(!socks_proxy_params_.get());
@@ -339,7 +339,7 @@
   }
 
   // If we want SPDY over ALPN/NPN, make sure it succeeded.
-  if (params_->want_spdy_over_npn() &&
+  if (params_->expect_spdy() &&
       !NextProtoIsSPDY(ssl_socket_->GetNegotiatedProtocol())) {
     return ERR_NPN_NEGOTIATION_FAILED;
   }
@@ -349,7 +349,7 @@
     DCHECK(!connect_timing_.ssl_start.is_null());
     base::TimeDelta connect_duration =
         connect_timing_.ssl_end - connect_timing_.ssl_start;
-    if (params_->want_spdy_over_npn()) {
+    if (params_->expect_spdy()) {
       UMA_HISTOGRAM_CUSTOM_TIMES("Net.SpdyConnectionLatency_2",
                                  connect_duration,
                                  base::TimeDelta::FromMilliseconds(1),
diff --git a/net/socket/ssl_client_socket_pool.h b/net/socket/ssl_client_socket_pool.h
index 461dbfb4..2e4b20c 100644
--- a/net/socket/ssl_client_socket_pool.h
+++ b/net/socket/ssl_client_socket_pool.h
@@ -42,15 +42,14 @@
 
   // Exactly one of |direct_params|, |socks_proxy_params|, and
   // |http_proxy_params| must be non-NULL.
-  SSLSocketParams(
-      const scoped_refptr<TransportSocketParams>& direct_params,
-      const scoped_refptr<SOCKSSocketParams>& socks_proxy_params,
-      const scoped_refptr<HttpProxySocketParams>& http_proxy_params,
-      const HostPortPair& host_and_port,
-      const SSLConfig& ssl_config,
-      PrivacyMode privacy_mode,
-      int load_flags,
-      bool want_spdy_over_npn);
+  SSLSocketParams(const scoped_refptr<TransportSocketParams>& direct_params,
+                  const scoped_refptr<SOCKSSocketParams>& socks_proxy_params,
+                  const scoped_refptr<HttpProxySocketParams>& http_proxy_params,
+                  const HostPortPair& host_and_port,
+                  const SSLConfig& ssl_config,
+                  PrivacyMode privacy_mode,
+                  int load_flags,
+                  bool expect_spdy);
 
   // Returns the type of the underlying connection.
   ConnectionType GetConnectionType() const;
@@ -71,7 +70,7 @@
   const SSLConfig& ssl_config() const { return ssl_config_; }
   PrivacyMode privacy_mode() const { return privacy_mode_; }
   int load_flags() const { return load_flags_; }
-  bool want_spdy_over_npn() const { return want_spdy_over_npn_; }
+  bool expect_spdy() const { return expect_spdy_; }
   bool ignore_limits() const { return ignore_limits_; }
 
  private:
@@ -85,7 +84,7 @@
   const SSLConfig ssl_config_;
   const PrivacyMode privacy_mode_;
   const int load_flags_;
-  const bool want_spdy_over_npn_;
+  const bool expect_spdy_;
   bool ignore_limits_;
 
   DISALLOW_COPY_AND_ASSIGN(SSLSocketParams);
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc
index a9d3447..05a5127 100644
--- a/net/socket/ssl_client_socket_pool_unittest.cc
+++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -138,17 +138,14 @@
   }
 
   scoped_refptr<SSLSocketParams> SSLParams(ProxyServer::Scheme proxy,
-                                           bool want_spdy_over_npn) {
+                                           bool expect_spdy) {
     return make_scoped_refptr(new SSLSocketParams(
         proxy == ProxyServer::SCHEME_DIRECT ? direct_transport_socket_params_
                                             : NULL,
         proxy == ProxyServer::SCHEME_SOCKS5 ? socks_socket_params_ : NULL,
         proxy == ProxyServer::SCHEME_HTTP ? http_proxy_socket_params_ : NULL,
-        HostPortPair("host", 443),
-        ssl_config_,
-        PRIVACY_MODE_DISABLED,
-        0,
-        want_spdy_over_npn));
+        HostPortPair("host", 443), ssl_config_, PRIVACY_MODE_DISABLED, 0,
+        expect_spdy));
   }
 
   void AddAuthToCache() {
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
index 31682178..d14a5765 100644
--- a/net/spdy/spdy_framer_test.cc
+++ b/net/spdy/spdy_framer_test.cc
@@ -569,7 +569,7 @@
 
 class SpdyFramerPeer {
  public:
-  static size_t kControlFrameBufferSize() {
+  static size_t ControlFrameBufferSize() {
     return SpdyFramer::kControlFrameBufferSize;
   }
   static size_t GetNumberRequiredContinuationFrames(SpdyFramer* framer,
@@ -3781,8 +3781,8 @@
   SpdyFramer framer(spdy_version_);
   // Create a GoAway frame that has a few extra bytes at the end.
   // We create enough overhead to overflow the framer's control frame buffer.
-  ASSERT_LE(SpdyFramerPeer::kControlFrameBufferSize(), 250u);
-  const size_t length = SpdyFramerPeer::kControlFrameBufferSize() + 1;
+  ASSERT_LE(SpdyFramerPeer::ControlFrameBufferSize(), 250u);
+  const size_t length = SpdyFramerPeer::ControlFrameBufferSize() + 1;
   const unsigned char kV3FrameData[] = {  // Also applies for V2.
     0x80, spdy_version_ch_, 0x00, 0x07,
     0x00, 0x00, 0x00, static_cast<unsigned char>(length),
@@ -3886,7 +3886,7 @@
                          7);
 
   scoped_ptr<SpdyFrame> control_frame(framer.SerializeSettings(settings_ir));
-  EXPECT_LT(SpdyFramerPeer::kControlFrameBufferSize(), control_frame->size());
+  EXPECT_LT(SpdyFramerPeer::ControlFrameBufferSize(), control_frame->size());
   TestSpdyVisitor visitor(spdy_version_);
   visitor.use_compression_ = false;
 
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc
index 9121cec..a57e4965 100644
--- a/net/spdy/spdy_http_stream_unittest.cc
+++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -4,8 +4,6 @@
 
 #include "net/spdy/spdy_http_stream.h"
 
-#include <vector>
-
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/run_loop.h"
@@ -72,28 +70,24 @@
     session_deps_.net_log = &net_log_;
   }
 
-  DeterministicSocketData* deterministic_data() {
-    return deterministic_data_.get();
-  }
-
  protected:
   void TearDown() override {
     crypto::ECSignatureCreator::SetFactoryForTesting(NULL);
     base::MessageLoop::current()->RunUntilIdle();
+    EXPECT_TRUE(sequenced_data_->AllReadDataConsumed());
+    EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed());
   }
 
-  // Initializes the session using DeterministicSocketData.
+  // Initializes the session using SequencedSocketData.
   void InitSession(MockRead* reads,
                    size_t reads_count,
                    MockWrite* writes,
                    size_t writes_count,
                    const SpdySessionKey& key) {
-    deterministic_data_.reset(
-        new DeterministicSocketData(reads, reads_count, writes, writes_count));
-    session_deps_.deterministic_socket_factory->AddSocketDataProvider(
-        deterministic_data_.get());
-    http_session_ =
-        SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
+    sequenced_data_.reset(
+        new SequencedSocketData(reads, reads_count, writes, writes_count));
+    session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get());
+    http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
     session_ = CreateInsecureSpdySession(http_session_, key, BoundNetLog());
   }
 
@@ -105,7 +99,7 @@
   SpdyTestUtil spdy_util_;
   TestNetLog net_log_;
   SpdySessionDependencies session_deps_;
-  scoped_ptr<DeterministicSocketData> deterministic_data_;
+  scoped_ptr<SequencedSocketData> sequenced_data_;
   scoped_refptr<HttpNetworkSession> http_session_;
   base::WeakPtr<SpdySession> session_;
 
@@ -179,8 +173,6 @@
   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
   EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
 
-  deterministic_data()->RunFor(3);
-
   callback.WaitForResult();
 
   // Can get timing information once the stream connects.
@@ -189,8 +181,6 @@
   // Because we abandoned the stream, we don't expect to find a session in the
   // pool anymore.
   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key));
-  EXPECT_TRUE(deterministic_data()->AllReadDataConsumed());
-  EXPECT_TRUE(deterministic_data()->AllWriteDataConsumed());
 
   TestLoadTimingNotReused(*http_stream);
   http_stream->Close(true);
@@ -254,7 +244,6 @@
                                                       callback1.callback()));
   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
 
-  deterministic_data()->RunFor(1);
   EXPECT_LE(0, callback1.WaitForResult());
 
   TestLoadTimingNotReused(*http_stream1);
@@ -272,15 +261,11 @@
                                                       callback2.callback()));
   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
 
-  deterministic_data()->RunFor(1);
   EXPECT_LE(0, callback2.WaitForResult());
   TestLoadTimingReused(*http_stream2);
   EXPECT_TRUE(http_stream2->GetLoadTimingInfo(&load_timing_info2));
   EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
 
-  // All the reads.
-  deterministic_data()->RunFor(6);
-
   // Read stream 1 to completion, before making sure we can still read load
   // timing from both streams.
   scoped_refptr<IOBuffer> buf1(new IOBuffer(1));
@@ -300,22 +285,22 @@
       spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
   scoped_ptr<SpdyFrame> body(
       framer.CreateDataFrame(1, kUploadData, kUploadDataSize, DATA_FLAG_FIN));
-  std::vector<MockWrite> writes;
-  int seq = 0;
-  writes.push_back(CreateMockWrite(*req, seq++));
-  writes.push_back(CreateMockWrite(*body, seq++));  // POST upload frame
+  MockWrite writes[] = {
+      CreateMockWrite(*req, 0),  // request
+      CreateMockWrite(*body, 1)  // POST upload frame
+  };
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
-  std::vector<MockRead> reads;
-  reads.push_back(CreateMockRead(*resp, seq++));
-  reads.push_back(CreateMockRead(*body, seq++));
-  reads.push_back(MockRead(SYNCHRONOUS, 0, seq++));  // EOF
+  MockRead reads[] = {
+      CreateMockRead(*resp, 2),
+      CreateMockRead(*body, 3),
+      MockRead(SYNCHRONOUS, 0, 4)  // EOF
+  };
 
   HostPortPair host_port_pair("www.example.org", 80);
   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
                      PRIVACY_MODE_DISABLED);
-  InitSession(vector_as_array(&reads), reads.size(), vector_as_array(&writes),
-              writes.size(), key);
+  InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
   EXPECT_EQ(spdy_util_.spdy_version(), session_->GetProtocolVersion());
 
   ChunkedUploadDataStream upload_stream(0);
@@ -345,14 +330,11 @@
       headers, &response, callback.callback()));
   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
 
-  deterministic_data()->RunFor(seq);
   callback.WaitForResult();
 
   // Because we abandoned the stream, we don't expect to find a session in the
   // pool anymore.
   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key));
-  EXPECT_TRUE(deterministic_data()->AllReadDataConsumed());
-  EXPECT_TRUE(deterministic_data()->AllWriteDataConsumed());
 }
 
 // Test to ensure the SpdyStream state machine does not get confused when a
@@ -411,7 +393,7 @@
   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
 
   // Complete the initial request write and the first chunk.
-  deterministic_data()->RunFor(2);
+  base::RunLoop().RunUntilIdle();
   ASSERT_TRUE(callback.have_result());
   EXPECT_EQ(OK, callback.WaitForResult());
 
@@ -419,43 +401,35 @@
   upload_stream.AppendData(kUploadData1, kUploadData1Size, false);
   upload_stream.AppendData(kUploadData, kUploadDataSize, true);
 
-  // Finish writing all the chunks.
-  deterministic_data()->RunFor(2);
+  // Finish writing all the chunks and do all reads.
+  base::RunLoop().RunUntilIdle();
 
-  // Read response headers.
-  deterministic_data()->RunFor(1);
+  // Check response headers.
   ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
 
-  // Read and check |chunk1| response.
-  deterministic_data()->RunFor(1);
+  // Check |chunk1| response.
   scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
   ASSERT_EQ(kUploadDataSize,
             http_stream->ReadResponseBody(
                 buf1.get(), kUploadDataSize, callback.callback()));
   EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
 
-  // Read and check |chunk2| response.
-  deterministic_data()->RunFor(1);
+  // Check |chunk2| response.
   scoped_refptr<IOBuffer> buf2(new IOBuffer(kUploadData1Size));
   ASSERT_EQ(kUploadData1Size,
             http_stream->ReadResponseBody(
                 buf2.get(), kUploadData1Size, callback.callback()));
   EXPECT_EQ(kUploadData1, std::string(buf2->data(), kUploadData1Size));
 
-  // Read and check |chunk3| response.
-  deterministic_data()->RunFor(1);
+  // Check |chunk3| response.
   scoped_refptr<IOBuffer> buf3(new IOBuffer(kUploadDataSize));
   ASSERT_EQ(kUploadDataSize,
             http_stream->ReadResponseBody(
                 buf3.get(), kUploadDataSize, callback.callback()));
   EXPECT_EQ(kUploadData, std::string(buf3->data(), kUploadDataSize));
 
-  // Finish reading the |EOF|.
-  deterministic_data()->RunFor(1);
   ASSERT_TRUE(response.headers.get());
   ASSERT_EQ(200, response.headers->response_code());
-  EXPECT_TRUE(deterministic_data()->AllReadDataConsumed());
-  EXPECT_TRUE(deterministic_data()->AllWriteDataConsumed());
 }
 
 // Test that the SpdyStream state machine can handle sending a final empty data
@@ -508,40 +482,33 @@
   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
 
   // Complete the initial request write and the first chunk.
-  deterministic_data()->RunFor(2);
+  base::RunLoop().RunUntilIdle();
   ASSERT_TRUE(callback.have_result());
   EXPECT_EQ(OK, callback.WaitForResult());
 
   // Now end the stream with an empty data frame and the FIN set.
   upload_stream.AppendData(NULL, 0, true);
 
-  // Finish writing the final frame.
-  deterministic_data()->RunFor(1);
+  // Finish writing the final frame, and perform all reads.
+  base::RunLoop().RunUntilIdle();
 
-  // Read response headers.
-  deterministic_data()->RunFor(1);
+  // Check response headers.
   ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
 
-  // Read and check |chunk1| response.
-  deterministic_data()->RunFor(1);
+  // Check |chunk1| response.
   scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
   ASSERT_EQ(kUploadDataSize,
             http_stream->ReadResponseBody(
                 buf1.get(), kUploadDataSize, callback.callback()));
   EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
 
-  // Read and check |chunk2| response.
-  deterministic_data()->RunFor(1);
+  // Check |chunk2| response.
   ASSERT_EQ(0,
             http_stream->ReadResponseBody(
                 buf1.get(), kUploadDataSize, callback.callback()));
 
-  // Finish reading the |EOF|.
-  deterministic_data()->RunFor(1);
   ASSERT_TRUE(response.headers.get());
   ASSERT_EQ(200, response.headers->response_code());
-  EXPECT_TRUE(deterministic_data()->AllReadDataConsumed());
-  EXPECT_TRUE(deterministic_data()->AllWriteDataConsumed());
 }
 
 // Test that the SpdyStream state machine handles a chunked upload with no
@@ -591,27 +558,21 @@
   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
 
   // Complete writing request, followed by a FIN.
-  deterministic_data()->RunFor(2);
+  base::RunLoop().RunUntilIdle();
   ASSERT_TRUE(callback.have_result());
   EXPECT_EQ(OK, callback.WaitForResult());
 
-  // Read response headers.
-  deterministic_data()->RunFor(1);
+  // Check response headers.
   ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
 
-  // Read and check |chunk| response.
-  deterministic_data()->RunFor(1);
+  // Check |chunk| response.
   scoped_refptr<IOBuffer> buf(new IOBuffer(1));
   ASSERT_EQ(0,
             http_stream->ReadResponseBody(
                 buf.get(), 1, callback.callback()));
 
-  // Finish reading the |EOF|.
-  deterministic_data()->RunFor(1);
   ASSERT_TRUE(response.headers.get());
   ASSERT_EQ(200, response.headers->response_code());
-  EXPECT_TRUE(deterministic_data()->AllReadDataConsumed());
-  EXPECT_TRUE(deterministic_data()->AllWriteDataConsumed());
 }
 
 // Test case for bug: http://code.google.com/p/chromium/issues/detail?id=50058
@@ -650,18 +611,13 @@
 
   EXPECT_EQ(base_url, http_stream->stream()->GetUrlFromHeaders().spec());
 
-  deterministic_data()->RunFor(3);
   callback.WaitForResult();
 
   // Because we abandoned the stream, we don't expect to find a session in the
   // pool anymore.
   EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key));
-  EXPECT_TRUE(deterministic_data()->AllReadDataConsumed());
-  EXPECT_TRUE(deterministic_data()->AllWriteDataConsumed());
 }
 
-// The tests below are only for SPDY/3 and above.
-
 // Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be
 // made available is handled correctly.
 TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) {
@@ -675,10 +631,11 @@
   scoped_ptr<SpdyFrame> window_update(
       spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize));
   MockRead reads[] = {
-    CreateMockRead(*window_update, 2),
-    CreateMockRead(*resp, 3),
-    CreateMockRead(*chunk1, 4),
-    MockRead(ASYNC, 0, 5)  // EOF
+      CreateMockRead(*window_update, 2),
+      MockRead(ASYNC, ERR_IO_PENDING, 3),
+      CreateMockRead(*resp, 4),
+      CreateMockRead(*chunk1, 5),
+      MockRead(ASYNC, 0, 6)  // EOF
   };
 
   HostPortPair host_port_pair("www.example.org", 80);
@@ -695,7 +652,6 @@
   request.upload_data_stream = &upload_stream;
 
   ASSERT_EQ(OK, upload_stream.Init(TestCompletionCallback().callback()));
-  upload_stream.AppendData(kUploadData, kUploadDataSize, true);
 
   BoundNetLog net_log;
   scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
@@ -712,10 +668,12 @@
   EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key));
 
   // Complete the initial request write and first chunk.
-  deterministic_data_->RunFor(2);
+  base::RunLoop().RunUntilIdle();
   ASSERT_TRUE(callback.have_result());
   EXPECT_EQ(OK, callback.WaitForResult());
 
+  upload_stream.AppendData(kUploadData, kUploadDataSize, true);
+
   // Verify that the window size has decreased.
   ASSERT_TRUE(http_stream->stream() != NULL);
   EXPECT_NE(static_cast<int>(
@@ -723,7 +681,7 @@
             http_stream->stream()->send_window_size());
 
   // Read window update.
-  deterministic_data_->RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   // Verify the window update.
   ASSERT_TRUE(http_stream->stream() != NULL);
@@ -731,24 +689,22 @@
                 SpdySession::GetDefaultInitialWindowSize(session_->protocol())),
             http_stream->stream()->send_window_size());
 
-  // Read response headers.
-  deterministic_data_->RunFor(1);
+  // Read rest of data.
+  sequenced_data_->CompleteRead();
+  base::RunLoop().RunUntilIdle();
+
+  // Check response headers.
   ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
 
-  // Read and check |chunk1| response.
-  deterministic_data_->RunFor(1);
+  // Check |chunk1| response.
   scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
   ASSERT_EQ(kUploadDataSize,
             http_stream->ReadResponseBody(
                 buf1.get(), kUploadDataSize, callback.callback()));
   EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
 
-  // Finish reading the |EOF|.
-  deterministic_data_->RunFor(1);
   ASSERT_TRUE(response.headers.get());
   ASSERT_EQ(200, response.headers->response_code());
-  EXPECT_TRUE(deterministic_data_->AllReadDataConsumed());
-  EXPECT_TRUE(deterministic_data_->AllWriteDataConsumed());
 }
 
 // TODO(willchan): Write a longer test for SpdyStream that exercises all
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index a8196e4..5ed45ae 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -107,12 +107,12 @@
             HttpNetworkSession::NORMAL_SOCKET_POOL)),
         spdy_util_(GetParam()),
         session_deps_(GetParam()),
-        spdy_session_pool_(NULL),
+        spdy_session_pool_(nullptr),
         test_url_(kTestUrl),
         test_host_port_pair_(kTestHost, kTestPort),
-        key_(test_host_port_pair_, ProxyServer::Direct(),
-             PRIVACY_MODE_DISABLED) {
-  }
+        key_(test_host_port_pair_,
+             ProxyServer::Direct(),
+             PRIVACY_MODE_DISABLED) {}
 
   virtual ~SpdySessionTest() {
     // Important to restore the per-pool limit first, since the pool limit must
@@ -125,12 +125,6 @@
 
   void SetUp() override { g_time_delta = base::TimeDelta(); }
 
-  void CreateDeterministicNetworkSession() {
-    http_session_ =
-        SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
-    spdy_session_pool_ = http_session_->spdy_session_pool();
-  }
-
   void CreateNetworkSession() {
     http_session_ =
         SpdySessionDependencies::SpdyCreateSession(&session_deps_);
@@ -189,7 +183,7 @@
 // Try to create a SPDY session that will fail during
 // initialization. Nothing should blow up.
 TEST_P(SpdySessionTest, InitialReadError) {
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session = TryCreateFakeSpdySessionExpectingFailure(
       spdy_session_pool_, key_, ERR_CONNECTION_CLOSED);
@@ -238,12 +232,10 @@
 
   MockRead reads[] = {MockRead(ASYNC, 0, 0), };
 
-  DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), nullptr, 0);
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -252,7 +244,7 @@
   for (size_t i = 0; i < kInitialMaxConcurrentStreams; ++i) {
     base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
         SPDY_BIDIRECTIONAL_STREAM, session, test_url_, MEDIUM, BoundNetLog());
-    ASSERT_TRUE(spdy_stream != NULL);
+    ASSERT_TRUE(spdy_stream != nullptr);
   }
 
   SpdyStreamRequest request1;
@@ -288,16 +280,14 @@
 TEST_P(SpdySessionTest, GoAwayWithNoActiveStreams) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
   MockRead reads[] = {
     CreateMockRead(*goaway, 0),
   };
-  DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), nullptr, 0);
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -307,10 +297,9 @@
   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
 
   // Read and process the GOAWAY frame.
-  data.RunFor(1);
-  EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(session == NULL);
+  EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
+  EXPECT_FALSE(session);
 }
 
 // A session receiving a GOAWAY frame immediately with no active
@@ -318,18 +307,14 @@
 TEST_P(SpdySessionTest, GoAwayImmediatelyWithNoActiveStreams) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
   MockRead reads[] = {
-    CreateMockRead(*goaway, 0, SYNCHRONOUS),
+      CreateMockRead(*goaway, 0, SYNCHRONOUS), MockRead(ASYNC, 0, 1)  // EOF
   };
-  DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), nullptr, 0);
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
-
-  data.StopAfter(1);
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       TryCreateInsecureSpdySessionExpectingFailure(
@@ -338,6 +323,7 @@
 
   EXPECT_FALSE(session);
   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
+  EXPECT_FALSE(data.AllReadDataConsumed());
 }
 
 // A session receiving a GOAWAY frame with active streams should close
@@ -345,26 +331,25 @@
 TEST_P(SpdySessionTest, GoAwayWithActiveStreams) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
   MockRead reads[] = {
-    CreateMockRead(*goaway, 2),
-    MockRead(ASYNC, 0, 3)  // EOF
+      MockRead(ASYNC, ERR_IO_PENDING, 2),
+      CreateMockRead(*goaway, 3),
+      MockRead(ASYNC, ERR_IO_PENDING, 4),
+      MockRead(ASYNC, 0, 5)  // EOF
   };
   scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   scoped_ptr<SpdyFrame> req2(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 3, MEDIUM, true));
   MockWrite writes[] = {
     CreateMockWrite(*req1, 0),
     CreateMockWrite(*req2, 1),
   };
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -393,7 +378,7 @@
   spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
   EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
 
-  data.RunFor(2);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1u, spdy_stream1->stream_id());
   EXPECT_EQ(3u, spdy_stream2->stream_id());
@@ -401,22 +386,25 @@
   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
 
   // Read and process the GOAWAY frame.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
 
   EXPECT_FALSE(session->IsStreamActive(3));
-  EXPECT_EQ(NULL, spdy_stream2.get());
+  EXPECT_FALSE(spdy_stream2);
   EXPECT_TRUE(session->IsStreamActive(1));
 
   EXPECT_TRUE(session->IsGoingAway());
 
   // Should close the session.
   spdy_stream1->Close();
-  EXPECT_EQ(NULL, spdy_stream1.get());
+  EXPECT_FALSE(spdy_stream1);
 
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_TRUE(session == NULL);
+  EXPECT_TRUE(session);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // Have a session receive two GOAWAY frames, with the last one causing
@@ -425,28 +413,28 @@
 TEST_P(SpdySessionTest, GoAwayTwice) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> goaway1(spdy_util_.ConstructSpdyGoAway(1));
   scoped_ptr<SpdyFrame> goaway2(spdy_util_.ConstructSpdyGoAway(0));
   MockRead reads[] = {
-    CreateMockRead(*goaway1, 2),
-    CreateMockRead(*goaway2, 3),
-    MockRead(ASYNC, 0, 4)  // EOF
+      MockRead(ASYNC, ERR_IO_PENDING, 2),
+      CreateMockRead(*goaway1, 3),
+      MockRead(ASYNC, ERR_IO_PENDING, 4),
+      CreateMockRead(*goaway2, 5),
+      MockRead(ASYNC, ERR_IO_PENDING, 6),
+      MockRead(ASYNC, 0, 7)  // EOF
   };
   scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   scoped_ptr<SpdyFrame> req2(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 3, MEDIUM, true));
   MockWrite writes[] = {
     CreateMockWrite(*req1, 0),
     CreateMockWrite(*req2, 1),
   };
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -475,7 +463,7 @@
   spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
   EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
 
-  data.RunFor(2);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1u, spdy_stream1->stream_id());
   EXPECT_EQ(3u, spdy_stream2->stream_id());
@@ -483,20 +471,21 @@
   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
 
   // Read and process the first GOAWAY frame.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
 
   EXPECT_FALSE(session->IsStreamActive(3));
-  EXPECT_EQ(NULL, spdy_stream2.get());
+  EXPECT_FALSE(spdy_stream2);
   EXPECT_TRUE(session->IsStreamActive(1));
   EXPECT_TRUE(session->IsGoingAway());
 
   // Read and process the second GOAWAY frame, which should close the
   // session.
-  data.RunFor(1);
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_TRUE(session == NULL);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // Have a session with active streams receive a GOAWAY frame and then
@@ -505,26 +494,25 @@
 TEST_P(SpdySessionTest, GoAwayWithActiveStreamsThenClose) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
   MockRead reads[] = {
-    CreateMockRead(*goaway, 2),
-    MockRead(ASYNC, 0, 3)  // EOF
+      MockRead(ASYNC, ERR_IO_PENDING, 2),
+      CreateMockRead(*goaway, 3),
+      MockRead(ASYNC, ERR_IO_PENDING, 4),
+      MockRead(ASYNC, 0, 5)  // EOF
   };
   scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   scoped_ptr<SpdyFrame> req2(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 3, MEDIUM, true));
   MockWrite writes[] = {
     CreateMockWrite(*req1, 0),
     CreateMockWrite(*req2, 1),
   };
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -553,7 +541,7 @@
   spdy_stream2->SendRequestHeaders(headers2.Pass(), NO_MORE_DATA_TO_SEND);
   EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders());
 
-  data.RunFor(2);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1u, spdy_stream1->stream_id());
   EXPECT_EQ(3u, spdy_stream2->stream_id());
@@ -561,20 +549,22 @@
   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
 
   // Read and process the GOAWAY frame.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
 
   EXPECT_FALSE(session->IsStreamActive(3));
-  EXPECT_EQ(NULL, spdy_stream2.get());
+  EXPECT_FALSE(spdy_stream2);
   EXPECT_TRUE(session->IsStreamActive(1));
   EXPECT_TRUE(session->IsGoingAway());
 
   session->CloseSessionOnError(ERR_ABORTED, "Aborting session");
-  EXPECT_EQ(NULL, spdy_stream1.get());
+  EXPECT_FALSE(spdy_stream1);
 
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_TRUE(session == NULL);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // Process a joint read buffer which causes the session to begin draining, and
@@ -584,12 +574,13 @@
   session_deps_.host_resolver->set_synchronous_mode(true);
 
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   MockWrite writes[] = {
       CreateMockWrite(*req, 0),
   };
 
-  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> resp(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
   scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   size_t joint_size = goaway->size() * 2 + body->size();
@@ -613,13 +604,10 @@
       MockRead(ASYNC, 0, 3)  // EOF
   };
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  DeterministicSocketData data(
-      reads, arraysize(reads), writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
 
@@ -634,14 +622,13 @@
   spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
   EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
 
-  data.RunFor(3);
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   // Stream and session closed gracefully.
   EXPECT_TRUE(delegate.StreamIsClosed());
   EXPECT_EQ(OK, delegate.WaitForClose());
   EXPECT_EQ(kUploadData, delegate.TakeReceivedData());
-  EXPECT_TRUE(session == NULL);
+  EXPECT_FALSE(session);
 }
 
 // Try to create a stream after receiving a GOAWAY frame. It should
@@ -649,23 +636,22 @@
 TEST_P(SpdySessionTest, CreateStreamAfterGoAway) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
   MockRead reads[] = {
-    CreateMockRead(*goaway, 1),
-    MockRead(ASYNC, 0, 2)  // EOF
+      MockRead(ASYNC, ERR_IO_PENDING, 1),
+      CreateMockRead(*goaway, 2),
+      MockRead(ASYNC, ERR_IO_PENDING, 3),
+      MockRead(ASYNC, 0, 4)  // EOF
   };
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   MockWrite writes[] = {
     CreateMockWrite(*req, 0),
   };
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -684,14 +670,15 @@
   spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
   EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1u, spdy_stream->stream_id());
 
   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
 
   // Read and process the GOAWAY frame.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
   EXPECT_TRUE(session->IsStreamActive(1));
@@ -702,10 +689,10 @@
       CompletionCallback());
   EXPECT_EQ(ERR_FAILED, rv);
 
-  // Read and process EOF.
-  data.RunFor(1);
-
-  EXPECT_TRUE(session == NULL);
+  EXPECT_TRUE(session);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // Receiving a SYN_STREAM frame after a GOAWAY frame should result in
@@ -713,29 +700,25 @@
 TEST_P(SpdySessionTest, SynStreamAfterGoAway) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
-  scoped_ptr<SpdyFrame>
-      push(spdy_util_.ConstructSpdyPush(NULL, 0, 2, 1, kDefaultURL));
+  scoped_ptr<SpdyFrame> push(
+      spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kDefaultURL));
   MockRead reads[] = {
-    CreateMockRead(*goaway, 1),
-    CreateMockRead(*push, 2),
-    MockRead(ASYNC, 0, 4)  // EOF
+      MockRead(ASYNC, ERR_IO_PENDING, 1),
+      CreateMockRead(*goaway, 2),
+      MockRead(ASYNC, ERR_IO_PENDING, 3),
+      CreateMockRead(*push, 4),
+      MockRead(ASYNC, 0, 6)  // EOF
   };
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
-  MockWrite writes[] = {
-    CreateMockWrite(*req, 0),
-    CreateMockWrite(*rst, 3)
-  };
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*rst, 5)};
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -754,23 +737,24 @@
   spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
   EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1u, spdy_stream->stream_id());
 
   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
 
   // Read and process the GOAWAY frame.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
   EXPECT_TRUE(session->IsStreamActive(1));
 
   // Read and process the SYN_STREAM frame, the subsequent RST_STREAM,
   // and EOF.
-  data.RunFor(3);
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_TRUE(session == NULL);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // A session observing a network change with active streams should close
@@ -778,21 +762,18 @@
 TEST_P(SpdySessionTest, NetworkChangeWithActiveStreams) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   MockRead reads[] = {
-    MockRead(ASYNC, 0, 1)  // EOF
+      MockRead(ASYNC, ERR_IO_PENDING, 1), MockRead(ASYNC, 0, 2)  // EOF
   };
   scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   MockWrite writes[] = {
     CreateMockWrite(*req1, 0),
   };
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -811,7 +792,7 @@
   spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
   EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1u, spdy_stream->stream_id());
 
@@ -835,32 +816,31 @@
   // Should close the session.
   spdy_stream->Close();
 #endif
-  EXPECT_EQ(NULL, spdy_stream.get());
+  EXPECT_FALSE(spdy_stream);
 
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_TRUE(session == NULL);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 TEST_P(SpdySessionTest, ClientPing) {
   session_deps_.enable_ping = true;
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> read_ping(spdy_util_.ConstructSpdyPing(1, true));
   MockRead reads[] = {
-    CreateMockRead(*read_ping, 1),
-    MockRead(ASYNC, 0, 0, 2)  // EOF
+      CreateMockRead(*read_ping, 1),
+      MockRead(ASYNC, ERR_IO_PENDING, 2),
+      MockRead(ASYNC, 0, 3)  // EOF
   };
   scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false));
   MockWrite writes[] = {
     CreateMockWrite(*write_ping, 0),
   };
-  DeterministicSocketData data(
-      reads, arraysize(reads), writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -868,8 +848,8 @@
   base::WeakPtr<SpdyStream> spdy_stream1 =
       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                 session, test_url_, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
-  test::StreamDelegateSendImmediate delegate(spdy_stream1, NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
+  test::StreamDelegateSendImmediate delegate(spdy_stream1, nullptr);
   spdy_stream1->SetDelegate(&delegate);
 
   base::TimeTicks before_ping_time = base::TimeTicks::Now();
@@ -880,7 +860,7 @@
 
   session->SendPrefacePingIfNoneInFlight();
 
-  data.RunFor(2);
+  base::RunLoop().RunUntilIdle();
 
   session->CheckPingStatus(before_ping_time);
 
@@ -889,18 +869,18 @@
   EXPECT_FALSE(session->check_ping_status_pending());
   EXPECT_GE(session->last_activity_time(), before_ping_time);
 
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
 
   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
-  EXPECT_TRUE(session == NULL);
+  EXPECT_FALSE(session);
 }
 
 TEST_P(SpdySessionTest, ServerPing) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> read_ping(spdy_util_.ConstructSpdyPing(2, false));
   MockRead reads[] = {
     CreateMockRead(*read_ping),
@@ -912,7 +892,6 @@
   };
   StaticSocketDataProvider data(
       reads, arraysize(reads), writes, arraysize(writes));
-  data.set_connect_data(connect_data);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   CreateNetworkSession();
@@ -923,17 +902,17 @@
   base::WeakPtr<SpdyStream> spdy_stream1 =
       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                 session, test_url_, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
-  test::StreamDelegateSendImmediate delegate(spdy_stream1, NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
+  test::StreamDelegateSendImmediate delegate(spdy_stream1, nullptr);
   spdy_stream1->SetDelegate(&delegate);
 
   // Flush the read completion task.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
 
-  EXPECT_TRUE(session == NULL);
-  EXPECT_EQ(NULL, spdy_stream1.get());
+  EXPECT_FALSE(session);
+  EXPECT_FALSE(spdy_stream1);
 }
 
 // Cause a ping to be sent out while producing a write. The write loop
@@ -944,27 +923,24 @@
   session_deps_.enable_ping = true;
   session_deps_.time_func = TheNearFuture;
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false));
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
   MockWrite writes[] = {
     CreateMockWrite(*req, 0),
     CreateMockWrite(*write_ping, 1),
   };
 
   MockRead reads[] = {
-    MockRead(ASYNC, 0, 2)  // EOF
+      MockRead(ASYNC, ERR_IO_PENDING, 2), MockRead(ASYNC, 0, 3)  // EOF
   };
 
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -983,9 +959,12 @@
   // Shift time so that a ping will be sent out.
   g_time_delta = base::TimeDelta::FromSeconds(11);
 
-  data.RunFor(2);
-
+  base::RunLoop().RunUntilIdle();
   session->CloseSessionOnError(ERR_ABORTED, "Aborting");
+
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 TEST_P(SpdySessionTest, StreamIdSpaceExhausted) {
@@ -1000,18 +979,18 @@
   // at which point the session closes.
 
   scoped_ptr<SpdyFrame> req1(spdy_util_.ConstructSpdyGet(
-      NULL, 0, false, kLastStreamId - 2, MEDIUM, true));
-  scoped_ptr<SpdyFrame> req2(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, kLastStreamId, MEDIUM, true));
+      nullptr, 0, false, kLastStreamId - 2, MEDIUM, true));
+  scoped_ptr<SpdyFrame> req2(spdy_util_.ConstructSpdyGet(
+      nullptr, 0, false, kLastStreamId, MEDIUM, true));
 
   MockWrite writes[] = {
       CreateMockWrite(*req1, 0), CreateMockWrite(*req2, 1),
   };
 
   scoped_ptr<SpdyFrame> resp1(
-      spdy_util_.ConstructSpdyGetSynReply(NULL, 0, kLastStreamId - 2));
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, kLastStreamId - 2));
   scoped_ptr<SpdyFrame> resp2(
-      spdy_util_.ConstructSpdyGetSynReply(NULL, 0, kLastStreamId));
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, kLastStreamId));
 
   scoped_ptr<SpdyFrame> body1(
       spdy_util_.ConstructSpdyBodyFrame(kLastStreamId - 2, true));
@@ -1019,19 +998,18 @@
       spdy_util_.ConstructSpdyBodyFrame(kLastStreamId, true));
 
   MockRead reads[] = {
-      CreateMockRead(*resp1, 2), CreateMockRead(*resp2, 3),
-      CreateMockRead(*body1, 4), CreateMockRead(*body2, 5),
-      MockRead(ASYNC, 0, 6)  // EOF
+      CreateMockRead(*resp1, 2),
+      CreateMockRead(*resp2, 3),
+      MockRead(ASYNC, ERR_IO_PENDING, 4),
+      CreateMockRead(*body1, 5),
+      CreateMockRead(*body2, 6),
+      MockRead(ASYNC, 0, 7)  // EOF
   };
 
-  DeterministicSocketData data(
-      reads, arraysize(reads), writes, arraysize(writes));
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
-
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
 
@@ -1077,7 +1055,7 @@
       scoped_ptr<SpdyHeaderBlock>(
           spdy_util_.ConstructGetHeaderBlock(url.spec())),
       NO_MORE_DATA_TO_SEND);
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(kLastStreamId - 2u, stream1->stream_id());
   EXPECT_EQ(1u, session->num_active_streams());
@@ -1089,7 +1067,7 @@
       scoped_ptr<SpdyHeaderBlock>(
           spdy_util_.ConstructGetHeaderBlock(url.spec())),
       NO_MORE_DATA_TO_SEND);
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   // Active streams remain active.
   EXPECT_EQ(kLastStreamId, stream2->stream_id());
@@ -1103,15 +1081,15 @@
   EXPECT_EQ(0u, session->pending_create_stream_queue_size(MEDIUM));
 
   // Read responses on remaining active streams.
-  data.RunFor(4);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(OK, delegate1.WaitForClose());
   EXPECT_EQ(kUploadData, delegate1.TakeReceivedData());
   EXPECT_EQ(OK, delegate2.WaitForClose());
   EXPECT_EQ(kUploadData, delegate2.TakeReceivedData());
 
   // Session was destroyed.
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_FALSE(session.get());
+  EXPECT_FALSE(session);
 }
 
 // Verifies that an unstalled pending stream creation racing with a new stream
@@ -1124,10 +1102,7 @@
       MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
   };
 
-  StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
-
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
+  StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   CreateNetworkSession();
@@ -1169,15 +1144,15 @@
   EXPECT_EQ(1u, session->num_created_streams());
   EXPECT_EQ(0u, session->pending_create_stream_queue_size(MEDIUM));
 
-  // NOW run the message loop. The unstalled stream will re-stall itself.
-  base::MessageLoop::current()->RunUntilIdle();
+  // Now run the message loop. The unstalled stream will re-stall itself.
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, session->num_created_streams());
   EXPECT_EQ(1u, session->pending_create_stream_queue_size(MEDIUM));
 
   // Cancel the third stream and run the message loop. Verify that the second
   // stream creation now completes.
   stream3->Cancel();
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1u, session->num_created_streams());
   EXPECT_EQ(0u, session->pending_create_stream_queue_size(MEDIUM));
@@ -1189,31 +1164,32 @@
   session_deps_.time_func = TheNearFuture;
 
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
+  MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*rst, 5)};
 
   scoped_ptr<SpdyFrame> push_a(spdy_util_.ConstructSpdyPush(
-      NULL, 0, 2, 1, "http://www.example.org/a.dat"));
+      nullptr, 0, 2, 1, "http://www.example.org/a.dat"));
   scoped_ptr<SpdyFrame> push_a_body(
       spdy_util_.ConstructSpdyBodyFrame(2, false));
   // In ascii "0" < "a". We use it to verify that we properly handle std::map
   // iterators inside. See http://crbug.com/443490
   scoped_ptr<SpdyFrame> push_b(spdy_util_.ConstructSpdyPush(
-      NULL, 0, 4, 1, "http://www.example.org/0.dat"));
-  MockWrite writes[] = {CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4)};
+      nullptr, 0, 4, 1, "http://www.example.org/0.dat"));
   MockRead reads[] = {
-      CreateMockRead(*push_a, 1), CreateMockRead(*push_a_body, 2),
-      CreateMockRead(*push_b, 3), MockRead(ASYNC, 0, 5),  // EOF
+      CreateMockRead(*push_a, 1),
+      CreateMockRead(*push_a_body, 2),
+      MockRead(ASYNC, ERR_IO_PENDING, 3),
+      CreateMockRead(*push_b, 4),
+      MockRead(ASYNC, ERR_IO_PENDING, 6),
+      MockRead(ASYNC, 0, 7)  // EOF
   };
-  DeterministicSocketData data(
-      reads, arraysize(reads), writes, arraysize(writes));
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
 
@@ -1228,7 +1204,7 @@
       spdy_util_.ConstructGetHeaderBlock(url.spec()));
   spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
 
-  data.RunFor(3);
+  base::RunLoop().RunUntilIdle();
 
   // Verify that there is one unclaimed push stream.
   EXPECT_EQ(1u, session->num_unclaimed_pushed_streams());
@@ -1249,7 +1225,8 @@
   // Shift time to expire the push stream. Read the second SYN_STREAM,
   // and verify a RST_STREAM was written.
   g_time_delta = base::TimeDelta::FromSeconds(301);
-  data.RunFor(2);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
 
   // Verify that the second pushed stream evicted the first pushed stream.
   EXPECT_EQ(1u, session->num_unclaimed_pushed_streams());
@@ -1266,15 +1243,15 @@
   }
 
   // Read and process EOF.
-  data.RunFor(1);
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_TRUE(session == NULL);
+  EXPECT_TRUE(session);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 TEST_P(SpdySessionTest, FailedPing) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   MockRead reads[] = {
       MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
   };
@@ -1282,9 +1259,9 @@
   scoped_ptr<SpdyFrame> goaway(
       spdy_util_.ConstructSpdyGoAway(0, GOAWAY_PROTOCOL_ERROR, "Failed ping."));
   MockWrite writes[] = {CreateMockWrite(*write_ping), CreateMockWrite(*goaway)};
+
   StaticSocketDataProvider data(
       reads, arraysize(reads), writes, arraysize(writes));
-  data.set_connect_data(connect_data);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   CreateNetworkSession();
@@ -1295,8 +1272,8 @@
   base::WeakPtr<SpdyStream> spdy_stream1 =
       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                 session, test_url_, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
-  test::StreamDelegateSendImmediate delegate(spdy_stream1, NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
+  test::StreamDelegateSendImmediate delegate(spdy_stream1, nullptr);
   spdy_stream1->SetDelegate(&delegate);
 
   session->set_connection_at_risk_of_loss_time(base::TimeDelta::FromSeconds(0));
@@ -1318,11 +1295,11 @@
   base::TimeTicks now = base::TimeTicks::Now();
   session->last_activity_time_ = now - base::TimeDelta::FromSeconds(1);
   session->CheckPingStatus(now);
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
-  EXPECT_TRUE(session == NULL);
+  EXPECT_FALSE(session);
   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
-  EXPECT_EQ(NULL, spdy_stream1.get());
+  EXPECT_FALSE(spdy_stream1);
 }
 
 // Request kInitialMaxConcurrentStreams + 1 streams.  Receive a
@@ -1334,6 +1311,13 @@
 
   const SpdySettingsIds kSpdySettingsIds = SETTINGS_MAX_CONCURRENT_STREAMS;
 
+  int seq = 0;
+  std::vector<MockWrite> writes;
+  scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
+  if (GetParam() >= kProtoSPDY4MinimumVersion) {
+    writes.push_back(CreateMockWrite(*settings_ack, ++seq));
+  }
+
   SettingsMap new_settings;
   const uint32 max_concurrent_streams = kInitialMaxConcurrentStreams + 1;
   new_settings[kSpdySettingsIds] =
@@ -1341,22 +1325,16 @@
   scoped_ptr<SpdyFrame> settings_frame(
       spdy_util_.ConstructSpdySettings(new_settings));
   MockRead reads[] = {
-    CreateMockRead(*settings_frame, 0),
-    MockRead(ASYNC, 0, 1),
+      CreateMockRead(*settings_frame, 0),
+      MockRead(ASYNC, ERR_IO_PENDING, ++seq),
+      MockRead(ASYNC, 0, ++seq),
   };
 
-  scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
-  MockWrite writes[] = {
-    CreateMockWrite(*settings_ack, 2),
-  };
+  SequencedSocketData data(reads, arraysize(reads), vector_as_array(&writes),
+                           writes.size());
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
-
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -1366,7 +1344,7 @@
     base::WeakPtr<SpdyStream> spdy_stream =
         CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                   session, test_url_, MEDIUM, BoundNetLog());
-    ASSERT_TRUE(spdy_stream != NULL);
+    ASSERT_TRUE(spdy_stream != nullptr);
   }
 
   StreamReleaserCallback stream_releaser;
@@ -1377,17 +1355,16 @@
                 BoundNetLog(),
                 stream_releaser.MakeCallback(&request)));
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(OK, stream_releaser.WaitForResult());
 
-  data.RunFor(1);
-  if (spdy_util_.spdy_version() >= SPDY4) {
-    // Allow the SETTINGS+ACK to write, so the session finishes draining.
-    data.RunFor(1);
-  }
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_TRUE(session == NULL);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
+
+  EXPECT_TRUE(data.AllWriteDataConsumed());
+  EXPECT_TRUE(data.AllReadDataConsumed());
 }
 
 // Start with a persisted value for max concurrent streams. Receive a
@@ -1411,16 +1388,15 @@
   uint8 flags = SETTINGS_FLAG_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS;
   test::SetFrameFlags(settings_frame.get(), flags, spdy_util_.spdy_version());
   MockRead reads[] = {
-    CreateMockRead(*settings_frame, 0),
-    MockRead(ASYNC, 0, 1),
+      CreateMockRead(*settings_frame, 0),
+      MockRead(ASYNC, ERR_IO_PENDING, 1),
+      MockRead(ASYNC, 0, 2),
   };
 
-  DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), nullptr, 0);
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   // Initialize the SpdySetting with the default.
   spdy_session_pool_->http_server_properties()->SetSpdySetting(
@@ -1441,7 +1417,7 @@
     base::WeakPtr<SpdyStream> spdy_stream =
         CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                   session, test_url_, MEDIUM, BoundNetLog());
-    ASSERT_TRUE(spdy_stream != NULL);
+    ASSERT_TRUE(spdy_stream != nullptr);
   }
 
   StreamReleaserCallback stream_releaser;
@@ -1453,7 +1429,7 @@
                 BoundNetLog(),
                 stream_releaser.MakeCallback(&request)));
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(OK, stream_releaser.WaitForResult());
 
@@ -1466,8 +1442,9 @@
   EXPECT_EQ(kInitialMaxConcurrentStreams + 1,
             session->max_concurrent_streams());
 
-  data.RunFor(1);
-  EXPECT_TRUE(session == NULL);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // Start with max concurrent streams set to 1.  Request two streams.
@@ -1482,10 +1459,7 @@
     MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
   };
 
-  StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
-  MockConnect connect_data(SYNCHRONOUS, OK);
-
-  data.set_connect_data(connect_data);
+  StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   CreateNetworkSession();
@@ -1505,14 +1479,14 @@
     base::WeakPtr<SpdyStream> spdy_stream =
         CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                   session, test_url_, MEDIUM, BoundNetLog());
-    ASSERT_TRUE(spdy_stream != NULL);
+    ASSERT_TRUE(spdy_stream != nullptr);
   }
 
   // Create 2 more streams.  First will succeed.  Second will be pending.
   base::WeakPtr<SpdyStream> spdy_stream1 =
       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                 session, test_url_, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
 
   // Use scoped_ptr to let us invalidate the memory when we want to, to trigger
   // a valgrind error if the callback is invoked when it's not supposed to be.
@@ -1527,13 +1501,13 @@
 
   // Release the first one, this will allow the second to be created.
   spdy_stream1->Cancel();
-  EXPECT_EQ(NULL, spdy_stream1.get());
+  EXPECT_FALSE(spdy_stream1);
 
   request.CancelRequest();
   callback.reset();
 
   // Should not crash when running the pending callback.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 }
 
 TEST_P(SpdySessionTest, SendInitialDataOnNewSession) {
@@ -1546,7 +1520,6 @@
   SettingsMap settings;
   settings[SETTINGS_MAX_CONCURRENT_STREAMS] =
       SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams);
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> settings_frame(
       spdy_util_.ConstructSpdySettings(settings));
   std::vector<MockWrite> writes;
@@ -1572,7 +1545,6 @@
 
   StaticSocketDataProvider data(reads, arraysize(reads),
                                 vector_as_array(&writes), writes.size());
-  data.set_connect_data(connect_data);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   CreateNetworkSession();
@@ -1589,7 +1561,7 @@
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
 
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(data.AllWriteDataConsumed());
 }
 
@@ -1616,13 +1588,11 @@
   session_deps_.net_log = log.bound().net_log();
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   MockRead reads[] = {
     MockRead(ASYNC, 0, 0)  // EOF
   };
 
-  StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
-  data.set_connect_data(connect_data);
+  StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   CreateNetworkSession();
@@ -1632,7 +1602,7 @@
   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
 
   // Flush the read completion task.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   TestNetLogEntry::List entries;
   log.GetEntries(&entries);
@@ -1654,15 +1624,13 @@
 TEST_P(SpdySessionTest, NetLogOnSessionGoaway) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway());
   MockRead reads[] = {
     CreateMockRead(*goaway),
     MockRead(SYNCHRONOUS, 0, 0)  // EOF
   };
 
-  StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
-  data.set_connect_data(connect_data);
+  StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   CreateNetworkSession();
@@ -1673,10 +1641,10 @@
   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
 
   // Flush the read completion task.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
-  EXPECT_TRUE(session == NULL);
+  EXPECT_FALSE(session);
 
   // Check that the NetLog was filled reasonably.
   TestNetLogEntry::List entries;
@@ -1700,13 +1668,11 @@
 TEST_P(SpdySessionTest, NetLogOnSessionEOF) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   MockRead reads[] = {
       MockRead(SYNCHRONOUS, 0, 0)  // EOF
   };
 
-  StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
-  data.set_connect_data(connect_data);
+  StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   CreateNetworkSession();
@@ -1717,10 +1683,10 @@
   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
 
   // Flush the read completion task.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
-  EXPECT_TRUE(session == NULL);
+  EXPECT_FALSE(session);
 
   // Check that the NetLog was filled reasonably.
   TestNetLogEntry::List entries;
@@ -1745,20 +1711,17 @@
   session_deps_.enable_compression = true;
 
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyGet(NULL, 0, true, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, true, 1, MEDIUM, true));
   MockWrite writes[] = {
     CreateMockWrite(*req, 0),
   };
   MockRead reads[] = {
-    MockRead(ASYNC, 0, 1)  // EOF
+      MockRead(ASYNC, ERR_IO_PENDING, 1), MockRead(ASYNC, 0, 2)  // EOF
   };
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
 
@@ -1777,7 +1740,7 @@
   // Write request headers & capture resulting histogram update.
   base::HistogramTester histogram_tester;
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
   // Regression test of compression performance under the request fixture.
   switch (spdy_util_.spdy_version()) {
     case SPDY3:
@@ -1793,9 +1756,10 @@
   }
 
   // Read and process EOF.
-  data.RunFor(1);
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_TRUE(session == NULL);
+  EXPECT_TRUE(session);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // Queue up a low-priority SYN_STREAM followed by a high-priority
@@ -1803,22 +1767,21 @@
 // first.
 TEST_P(SpdySessionTest, OutOfOrderSynStreams) {
   // Construct the request.
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> req_highest(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, HIGHEST, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, HIGHEST, true));
   scoped_ptr<SpdyFrame> req_lowest(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 3, LOWEST, true));
   MockWrite writes[] = {
     CreateMockWrite(*req_highest, 0),
     CreateMockWrite(*req_lowest, 1),
   };
 
   scoped_ptr<SpdyFrame> resp_highest(
-      spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
   scoped_ptr<SpdyFrame> body_highest(
       spdy_util_.ConstructSpdyBodyFrame(1, true));
   scoped_ptr<SpdyFrame> resp_lowest(
-      spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 3));
   scoped_ptr<SpdyFrame> body_lowest(
       spdy_util_.ConstructSpdyBodyFrame(3, true));
   MockRead reads[] = {
@@ -1831,12 +1794,10 @@
 
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -1873,7 +1834,7 @@
       headers_highest.Pass(), NO_MORE_DATA_TO_SEND);
   EXPECT_TRUE(spdy_stream_highest->HasUrlFromHeaders());
 
-  data.RunFor(7);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(spdy_stream_lowest);
   EXPECT_FALSE(spdy_stream_highest);
@@ -1882,31 +1843,30 @@
 }
 
 TEST_P(SpdySessionTest, CancelStream) {
-  MockConnect connect_data(SYNCHRONOUS, OK);
   // Request 1, at HIGHEST priority, will be cancelled before it writes data.
   // Request 2, at LOWEST priority, will be a full request and will be id 1.
   scoped_ptr<SpdyFrame> req2(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
   MockWrite writes[] = {
     CreateMockWrite(*req2, 0),
   };
 
-  scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> resp2(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
   scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    CreateMockRead(*resp2, 1),
-    CreateMockRead(*body2, 2),
-    MockRead(ASYNC, 0, 3)  // EOF
+      CreateMockRead(*resp2, 1),
+      MockRead(ASYNC, ERR_IO_PENDING, 2),
+      CreateMockRead(*body2, 3),
+      MockRead(ASYNC, 0, 4)  // EOF
   };
 
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -1915,7 +1875,7 @@
   base::WeakPtr<SpdyStream> spdy_stream1 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url1, HIGHEST, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream1->stream_id());
   test::StreamDelegateDoNothing delegate1(spdy_stream1);
   spdy_stream1->SetDelegate(&delegate1);
@@ -1924,7 +1884,7 @@
   base::WeakPtr<SpdyStream> spdy_stream2 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url2, LOWEST, BoundNetLog());
-  ASSERT_TRUE(spdy_stream2.get() != NULL);
+  ASSERT_TRUE(spdy_stream2.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream2->stream_id());
   test::StreamDelegateDoNothing delegate2(spdy_stream2);
   spdy_stream2->SetDelegate(&delegate2);
@@ -1942,17 +1902,17 @@
   EXPECT_EQ(0u, spdy_stream1->stream_id());
 
   spdy_stream1->Cancel();
-  EXPECT_EQ(NULL, spdy_stream1.get());
+  EXPECT_FALSE(spdy_stream1);
 
   EXPECT_EQ(0u, delegate1.stream_id());
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(0u, delegate1.stream_id());
   EXPECT_EQ(1u, delegate2.stream_id());
 
   spdy_stream2->Cancel();
-  EXPECT_EQ(NULL, spdy_stream2.get());
+  EXPECT_FALSE(spdy_stream2);
 }
 
 // Create two streams that are set to re-close themselves on close,
@@ -1961,7 +1921,6 @@
 TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedSelfClosingStreams) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
 
   // No actual data will be sent.
   MockWrite writes[] = {
@@ -1971,12 +1930,10 @@
   MockRead reads[] = {
     MockRead(ASYNC, 0, 0)  // EOF
   };
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -1985,14 +1942,14 @@
   base::WeakPtr<SpdyStream> spdy_stream1 =
       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                 session, url1, HIGHEST, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream1->stream_id());
 
   GURL url2(kDefaultURL);
   base::WeakPtr<SpdyStream> spdy_stream2 =
       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                 session, url2, LOWEST, BoundNetLog());
-  ASSERT_TRUE(spdy_stream2.get() != NULL);
+  ASSERT_TRUE(spdy_stream2.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream2->stream_id());
 
   test::ClosingDelegate delegate1(spdy_stream1);
@@ -2018,14 +1975,14 @@
   // Ensure we don't crash while closing the session.
   session->CloseSessionOnError(ERR_ABORTED, std::string());
 
-  EXPECT_EQ(NULL, spdy_stream1.get());
-  EXPECT_EQ(NULL, spdy_stream2.get());
+  EXPECT_FALSE(spdy_stream1);
+  EXPECT_FALSE(spdy_stream2);
 
   EXPECT_TRUE(delegate1.StreamIsClosed());
   EXPECT_TRUE(delegate2.StreamIsClosed());
 
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_TRUE(session == NULL);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // Create two streams that are set to close each other on close, and
@@ -2033,22 +1990,10 @@
 TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedMutuallyClosingStreams) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
+  SequencedSocketData data(nullptr, 0, nullptr, 0);
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  // No actual data will be sent.
-  MockWrite writes[] = {
-    MockWrite(ASYNC, 0, 1)  // EOF
-  };
-
-  MockRead reads[] = {
-    MockRead(ASYNC, 0, 0)  // EOF
-  };
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
-
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -2057,14 +2002,14 @@
   base::WeakPtr<SpdyStream> spdy_stream1 =
       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                 session, url1, HIGHEST, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1);
   EXPECT_EQ(0u, spdy_stream1->stream_id());
 
   GURL url2(kDefaultURL);
   base::WeakPtr<SpdyStream> spdy_stream2 =
       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                 session, url2, LOWEST, BoundNetLog());
-  ASSERT_TRUE(spdy_stream2.get() != NULL);
+  ASSERT_TRUE(spdy_stream2);
   EXPECT_EQ(0u, spdy_stream2->stream_id());
 
   // Make |spdy_stream1| close |spdy_stream2|.
@@ -2092,14 +2037,14 @@
   // Ensure we don't crash while closing the session.
   session->CloseSessionOnError(ERR_ABORTED, std::string());
 
-  EXPECT_EQ(NULL, spdy_stream1.get());
-  EXPECT_EQ(NULL, spdy_stream2.get());
+  EXPECT_FALSE(spdy_stream1);
+  EXPECT_FALSE(spdy_stream2);
 
   EXPECT_TRUE(delegate1.StreamIsClosed());
   EXPECT_TRUE(delegate2.StreamIsClosed());
 
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_TRUE(session == NULL);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // Create two streams that are set to re-close themselves on close,
@@ -2107,27 +2052,23 @@
 TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedSelfClosingStreams) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
-
   scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   scoped_ptr<SpdyFrame> req2(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 3, MEDIUM, true));
   MockWrite writes[] = {
     CreateMockWrite(*req1, 0),
     CreateMockWrite(*req2, 1),
   };
 
   MockRead reads[] = {
-    MockRead(ASYNC, 0, 2)  // EOF
+      MockRead(ASYNC, ERR_IO_PENDING, 2), MockRead(ASYNC, 0, 3)  // EOF
   };
 
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -2136,14 +2077,14 @@
   base::WeakPtr<SpdyStream> spdy_stream1 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url1, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream1->stream_id());
 
   GURL url2(kDefaultURL);
   base::WeakPtr<SpdyStream> spdy_stream2 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url2, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(spdy_stream2.get() != NULL);
+  ASSERT_TRUE(spdy_stream2.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream2->stream_id());
 
   test::ClosingDelegate delegate1(spdy_stream1);
@@ -2166,7 +2107,7 @@
   EXPECT_EQ(0u, spdy_stream1->stream_id());
   EXPECT_EQ(0u, spdy_stream2->stream_id());
 
-  data.RunFor(2);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1u, spdy_stream1->stream_id());
   EXPECT_EQ(3u, spdy_stream2->stream_id());
@@ -2174,14 +2115,16 @@
   // Ensure we don't crash while closing the session.
   session->CloseSessionOnError(ERR_ABORTED, std::string());
 
-  EXPECT_EQ(NULL, spdy_stream1.get());
-  EXPECT_EQ(NULL, spdy_stream2.get());
+  EXPECT_FALSE(spdy_stream1);
+  EXPECT_FALSE(spdy_stream2);
 
   EXPECT_TRUE(delegate1.StreamIsClosed());
   EXPECT_TRUE(delegate2.StreamIsClosed());
 
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_TRUE(session == NULL);
+  EXPECT_TRUE(session);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // Create two streams that are set to close each other on close,
@@ -2189,27 +2132,23 @@
 TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedMutuallyClosingStreams) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
-
   scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   scoped_ptr<SpdyFrame> req2(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 3, MEDIUM, true));
   MockWrite writes[] = {
     CreateMockWrite(*req1, 0),
     CreateMockWrite(*req2, 1),
   };
 
   MockRead reads[] = {
-    MockRead(ASYNC, 0, 2)  // EOF
+      MockRead(ASYNC, ERR_IO_PENDING, 2), MockRead(ASYNC, 0, 3)  // EOF
   };
 
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -2218,14 +2157,14 @@
   base::WeakPtr<SpdyStream> spdy_stream1 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url1, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1);
   EXPECT_EQ(0u, spdy_stream1->stream_id());
 
   GURL url2(kDefaultURL);
   base::WeakPtr<SpdyStream> spdy_stream2 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url2, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(spdy_stream2.get() != NULL);
+  ASSERT_TRUE(spdy_stream2);
   EXPECT_EQ(0u, spdy_stream2->stream_id());
 
   // Make |spdy_stream1| close |spdy_stream2|.
@@ -2250,7 +2189,7 @@
   EXPECT_EQ(0u, spdy_stream1->stream_id());
   EXPECT_EQ(0u, spdy_stream2->stream_id());
 
-  data.RunFor(2);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1u, spdy_stream1->stream_id());
   EXPECT_EQ(3u, spdy_stream2->stream_id());
@@ -2258,14 +2197,16 @@
   // Ensure we don't crash while closing the session.
   session->CloseSessionOnError(ERR_ABORTED, std::string());
 
-  EXPECT_EQ(NULL, spdy_stream1.get());
-  EXPECT_EQ(NULL, spdy_stream2.get());
+  EXPECT_FALSE(spdy_stream1);
+  EXPECT_FALSE(spdy_stream2);
 
   EXPECT_TRUE(delegate1.StreamIsClosed());
   EXPECT_TRUE(delegate2.StreamIsClosed());
 
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_TRUE(session == NULL);
+  EXPECT_TRUE(session);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // Delegate that closes a given session when the stream is closed.
@@ -2287,14 +2228,12 @@
 };
 
 // Close an activated stream that closes its session. Nothing should
-// blow up. This is a regression test for http://crbug.com/263691 .
+// blow up. This is a regression test for https://crbug.com/263691.
 TEST_P(SpdySessionTest, CloseActivatedStreamThatClosesSession) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
-
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
   scoped_ptr<SpdyFrame> goaway(
@@ -2302,19 +2241,18 @@
   // The GOAWAY has higher-priority than the RST_STREAM, and is written first
   // despite being queued second.
   MockWrite writes[] = {
-      CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 1),
-      CreateMockWrite(*rst, 2),
+      CreateMockWrite(*req, 0),
+      CreateMockWrite(*goaway, 1),
+      CreateMockWrite(*rst, 3),
   };
 
   MockRead reads[] = {
-      MockRead(ASYNC, 0, 3)  // EOF
+      MockRead(ASYNC, 0, 2)  // EOF
   };
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -2323,7 +2261,7 @@
   base::WeakPtr<SpdyStream> spdy_stream =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(spdy_stream.get() != NULL);
+  ASSERT_TRUE(spdy_stream.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream->stream_id());
 
   SessionClosingDelegate delegate(spdy_stream, session);
@@ -2336,7 +2274,7 @@
 
   EXPECT_EQ(0u, spdy_stream->stream_id());
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1u, spdy_stream->stream_id());
 
@@ -2344,31 +2282,20 @@
   // session).
   spdy_stream->Cancel();
 
-  EXPECT_EQ(NULL, spdy_stream.get());
+  EXPECT_FALSE(spdy_stream);
   EXPECT_TRUE(delegate.StreamIsClosed());
 
-  data.RunFor(2);  // Write the RST_STREAM & GOAWAY.
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_TRUE(session == NULL);
+  // Write the RST_STREAM & GOAWAY.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(data.AllWriteDataConsumed());
+  EXPECT_TRUE(data.AllReadDataConsumed());
 }
 
 TEST_P(SpdySessionTest, VerifyDomainAuthentication) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
-
-  // No actual data will be sent.
-  MockWrite writes[] = {
-    MockWrite(ASYNC, 0, 1)  // EOF
-  };
-
-  MockRead reads[] = {
-    MockRead(ASYNC, 0, 0)  // EOF
-  };
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(nullptr, 0, nullptr, 0);
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   // Load a cert that is valid for:
   //   www.example.org
@@ -2377,13 +2304,13 @@
   base::FilePath certs_dir = GetTestCertsDirectory();
   scoped_refptr<X509Certificate> test_cert(
       ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
-  ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert.get());
+  ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
 
   SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
   ssl.cert = test_cert;
-  session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateSecureSpdySession(http_session_, key_, BoundNetLog());
@@ -2397,20 +2324,8 @@
 TEST_P(SpdySessionTest, ConnectionPooledWithTlsChannelId) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
-
-  // No actual data will be sent.
-  MockWrite writes[] = {
-    MockWrite(ASYNC, 0, 1)  // EOF
-  };
-
-  MockRead reads[] = {
-    MockRead(ASYNC, 0, 0)  // EOF
-  };
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(nullptr, 0, nullptr, 0);
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   // Load a cert that is valid for:
   //   www.example.org
@@ -2419,14 +2334,14 @@
   base::FilePath certs_dir = GetTestCertsDirectory();
   scoped_refptr<X509Certificate> test_cert(
       ImportCertFromFile(certs_dir, "spdy_pooling.pem"));
-  ASSERT_NE(static_cast<X509Certificate*>(NULL), test_cert.get());
+  ASSERT_NE(static_cast<X509Certificate*>(nullptr), test_cert.get());
 
   SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
   ssl.channel_id_sent = true;
   ssl.cert = test_cert;
-  session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateSecureSpdySession(http_session_, key_, BoundNetLog());
@@ -2440,8 +2355,6 @@
 TEST_P(SpdySessionTest, CloseTwoStalledCreateStream) {
   // TODO(rtenneti): Define a helper class/methods and move the common code in
   // this file.
-  MockConnect connect_data(SYNCHRONOUS, OK);
-
   SettingsMap new_settings;
   const SpdySettingsIds kSpdySettingsIds1 = SETTINGS_MAX_CONCURRENT_STREAMS;
   const uint32 max_concurrent_streams = 1;
@@ -2450,11 +2363,11 @@
 
   scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
   scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> req2(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 3, LOWEST, true));
   scoped_ptr<SpdyFrame> req3(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 5, LOWEST, true));
   MockWrite writes[] = {
     CreateMockWrite(*settings_ack, 1),
     CreateMockWrite(*req1, 2),
@@ -2467,44 +2380,46 @@
   scoped_ptr<SpdyFrame> settings_frame(
       spdy_util_.ConstructSpdySettings(new_settings));
 
-  scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> resp1(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
   scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true));
 
-  scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
+  scoped_ptr<SpdyFrame> resp2(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 3));
   scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, true));
 
-  scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
+  scoped_ptr<SpdyFrame> resp3(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 5));
   scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, true));
 
   MockRead reads[] = {
-    CreateMockRead(*settings_frame),
-    CreateMockRead(*resp1, 3),
-    CreateMockRead(*body1, 4),
-    CreateMockRead(*resp2, 6),
-    CreateMockRead(*body2, 7),
-    CreateMockRead(*resp3, 9),
-    CreateMockRead(*body3, 10),
-    MockRead(ASYNC, 0, 11)  // EOF
+      CreateMockRead(*settings_frame, 0),
+      CreateMockRead(*resp1, 3),
+      CreateMockRead(*body1, 4),
+      CreateMockRead(*resp2, 6),
+      CreateMockRead(*body2, 7),
+      CreateMockRead(*resp3, 9),
+      CreateMockRead(*body3, 10),
+      MockRead(ASYNC, ERR_IO_PENDING, 11),
+      MockRead(ASYNC, 0, 12)  // EOF
   };
 
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
 
   // Read the settings frame.
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   GURL url1(kDefaultURL);
   base::WeakPtr<SpdyStream> spdy_stream1 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url1, LOWEST, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream1->stream_id());
   test::StreamDelegateDoNothing delegate1(spdy_stream1);
   spdy_stream1->SetDelegate(&delegate1);
@@ -2536,17 +2451,16 @@
 
   // Run until 1st stream is activated and then closed.
   EXPECT_EQ(0u, delegate1.stream_id());
-  data.RunFor(4);
-  EXPECT_EQ(NULL, spdy_stream1.get());
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(spdy_stream1);
   EXPECT_EQ(1u, delegate1.stream_id());
 
   EXPECT_EQ(0u, session->num_active_streams());
-  EXPECT_EQ(0u, session->num_created_streams());
   EXPECT_EQ(1u, session->pending_create_stream_queue_size(LOWEST));
 
   // Pump loop for SpdySession::ProcessPendingStreamRequests() to
   // create the 2nd stream.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(0u, session->num_active_streams());
   EXPECT_EQ(1u, session->num_created_streams());
@@ -2562,17 +2476,16 @@
 
   // Run until 2nd stream is activated and then closed.
   EXPECT_EQ(0u, delegate2.stream_id());
-  data.RunFor(3);
-  EXPECT_EQ(NULL, stream2.get());
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(stream2);
   EXPECT_EQ(3u, delegate2.stream_id());
 
   EXPECT_EQ(0u, session->num_active_streams());
-  EXPECT_EQ(0u, session->num_created_streams());
   EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
 
   // Pump loop for SpdySession::ProcessPendingStreamRequests() to
   // create the 3rd stream.
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(0u, session->num_active_streams());
   EXPECT_EQ(1u, session->num_created_streams());
@@ -2588,15 +2501,16 @@
 
   // Run until 2nd stream is activated and then closed.
   EXPECT_EQ(0u, delegate3.stream_id());
-  data.RunFor(3);
-  EXPECT_EQ(NULL, stream3.get());
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(stream3);
   EXPECT_EQ(5u, delegate3.stream_id());
 
   EXPECT_EQ(0u, session->num_active_streams());
   EXPECT_EQ(0u, session->num_created_streams());
   EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
 
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
 }
 
 TEST_P(SpdySessionTest, CancelTwoStalledCreateStream) {
@@ -2606,10 +2520,7 @@
     MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
   };
 
-  StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
-  MockConnect connect_data(SYNCHRONOUS, OK);
-
-  data.set_connect_data(connect_data);
+  StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   CreateNetworkSession();
@@ -2622,14 +2533,14 @@
     base::WeakPtr<SpdyStream> spdy_stream =
         CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                   session, test_url_, MEDIUM, BoundNetLog());
-    ASSERT_TRUE(spdy_stream != NULL);
+    ASSERT_TRUE(spdy_stream != nullptr);
   }
 
   GURL url1(kDefaultURL);
   base::WeakPtr<SpdyStream> spdy_stream1 =
       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                 session, url1, LOWEST, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream1->stream_id());
 
   TestCompletionCallback callback2;
@@ -2653,9 +2564,9 @@
   EXPECT_EQ(2u, session->pending_create_stream_queue_size(LOWEST));
 
   // Cancel the first stream; this will allow the second stream to be created.
-  EXPECT_TRUE(spdy_stream1.get() != NULL);
+  EXPECT_TRUE(spdy_stream1);
   spdy_stream1->Cancel();
-  EXPECT_EQ(NULL, spdy_stream1.get());
+  EXPECT_FALSE(spdy_stream1);
 
   EXPECT_EQ(OK, callback2.WaitForResult());
   EXPECT_EQ(0u, session->num_active_streams());
@@ -2665,7 +2576,7 @@
   // Cancel the second stream; this will allow the third stream to be created.
   base::WeakPtr<SpdyStream> spdy_stream2 = request2.ReleaseStream();
   spdy_stream2->Cancel();
-  EXPECT_EQ(NULL, spdy_stream2.get());
+  EXPECT_FALSE(spdy_stream2);
 
   EXPECT_EQ(OK, callback3.WaitForResult());
   EXPECT_EQ(0u, session->num_active_streams());
@@ -2675,7 +2586,7 @@
   // Cancel the third stream.
   base::WeakPtr<SpdyStream> spdy_stream3 = request3.ReleaseStream();
   spdy_stream3->Cancel();
-  EXPECT_EQ(NULL, spdy_stream3.get());
+  EXPECT_FALSE(spdy_stream3);
   EXPECT_EQ(0u, session->num_active_streams());
   EXPECT_EQ(kInitialMaxConcurrentStreams - 1, session->num_created_streams());
   EXPECT_EQ(0u, session->pending_create_stream_queue_size(LOWEST));
@@ -2686,11 +2597,12 @@
 // on the socket for reading. It then verifies that it has read all
 // the available data without yielding.
 TEST_P(SpdySessionTest, ReadDataWithoutYielding) {
-  MockConnect connect_data(SYNCHRONOUS, OK);
+  session_deps_.host_resolver->set_synchronous_mode(true);
+
   BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
 
   scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   MockWrite writes[] = {
     CreateMockWrite(*req1, 0),
   };
@@ -2710,27 +2622,26 @@
   scoped_ptr<SpdyFrame> finish_data_frame(
       framer.CreateDataFrame(1, payload_data, kPayloadSize - 1, DATA_FLAG_FIN));
 
-  scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> resp1(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
 
   // Write 1 byte less than kMaxReadBytes to check that DoRead reads up to 32k
   // bytes.
   MockRead reads[] = {
-    CreateMockRead(*resp1, 1),
-    CreateMockRead(*partial_data_frame, 2),
-    CreateMockRead(*partial_data_frame, 3, SYNCHRONOUS),
-    CreateMockRead(*partial_data_frame, 4, SYNCHRONOUS),
-    CreateMockRead(*finish_data_frame, 5, SYNCHRONOUS),
-    MockRead(ASYNC, 0, 6)  // EOF
+      CreateMockRead(*resp1, 1),
+      MockRead(ASYNC, ERR_IO_PENDING, 2),
+      CreateMockRead(*partial_data_frame, 3),
+      CreateMockRead(*partial_data_frame, 4, SYNCHRONOUS),
+      CreateMockRead(*partial_data_frame, 5, SYNCHRONOUS),
+      CreateMockRead(*finish_data_frame, 6, SYNCHRONOUS),
+      MockRead(ASYNC, 0, 7)  // EOF
   };
 
   // Create SpdySession and SpdyStream and send the request.
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.host_resolver->set_synchronous_mode(true);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -2739,7 +2650,7 @@
   base::WeakPtr<SpdyStream> spdy_stream1 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url1, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream1->stream_id());
   test::StreamDelegateDoNothing delegate1(spdy_stream1);
   spdy_stream1->SetDelegate(&delegate1);
@@ -2755,14 +2666,15 @@
 
   // Run until 1st read.
   EXPECT_EQ(0u, delegate1.stream_id());
-  data.RunFor(2);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, delegate1.stream_id());
   EXPECT_EQ(0u, observer.executed_count());
 
   // Read all the data and verify SpdySession::DoReadLoop has not
   // posted a task.
-  data.RunFor(4);
-  EXPECT_EQ(NULL, spdy_stream1.get());
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(spdy_stream1);
 
   // Verify task observer's executed_count is zero, which indicates DoRead read
   // all the available data.
@@ -2777,11 +2689,12 @@
 // there is data available for it to read (i.e, socket()->Read didn't
 // return ERR_IO_PENDING during socket reads).
 TEST_P(SpdySessionTest, TestYieldingDuringReadData) {
-  MockConnect connect_data(SYNCHRONOUS, OK);
+  session_deps_.host_resolver->set_synchronous_mode(true);
+
   BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
 
   scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   MockWrite writes[] = {
     CreateMockWrite(*req1, 0),
   };
@@ -2801,27 +2714,26 @@
   scoped_ptr<SpdyFrame> finish_data_frame(
       framer.CreateDataFrame(1, "h", 1, DATA_FLAG_FIN));
 
-  scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> resp1(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
 
   // Write 1 byte more than kMaxReadBytes to check that DoRead yields.
   MockRead reads[] = {
-    CreateMockRead(*resp1, 1),
-    CreateMockRead(*partial_data_frame, 2),
-    CreateMockRead(*partial_data_frame, 3, SYNCHRONOUS),
-    CreateMockRead(*partial_data_frame, 4, SYNCHRONOUS),
-    CreateMockRead(*partial_data_frame, 5, SYNCHRONOUS),
-    CreateMockRead(*finish_data_frame, 6, SYNCHRONOUS),
-    MockRead(ASYNC, 0, 7)  // EOF
+      CreateMockRead(*resp1, 1),
+      MockRead(ASYNC, ERR_IO_PENDING, 2),
+      CreateMockRead(*partial_data_frame, 3),
+      CreateMockRead(*partial_data_frame, 4, SYNCHRONOUS),
+      CreateMockRead(*partial_data_frame, 5, SYNCHRONOUS),
+      CreateMockRead(*partial_data_frame, 6, SYNCHRONOUS),
+      CreateMockRead(*finish_data_frame, 7, SYNCHRONOUS),
+      MockRead(ASYNC, 0, 8)  // EOF
   };
 
   // Create SpdySession and SpdyStream and send the request.
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.host_resolver->set_synchronous_mode(true);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -2830,7 +2742,7 @@
   base::WeakPtr<SpdyStream> spdy_stream1 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url1, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream1->stream_id());
   test::StreamDelegateDoNothing delegate1(spdy_stream1);
   spdy_stream1->SetDelegate(&delegate1);
@@ -2846,14 +2758,15 @@
 
   // Run until 1st read.
   EXPECT_EQ(0u, delegate1.stream_id());
-  data.RunFor(2);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, delegate1.stream_id());
   EXPECT_EQ(0u, observer.executed_count());
 
   // Read all the data and verify SpdySession::DoReadLoop has posted a
   // task.
-  data.RunFor(6);
-  EXPECT_EQ(NULL, spdy_stream1.get());
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(spdy_stream1);
 
   // Verify task observer's executed_count is 1, which indicates DoRead has
   // posted only one task and thus yielded though there is data available for it
@@ -2875,11 +2788,12 @@
 // yield. When we come back, DoRead() will read the results from the
 // async read, and rest of the data synchronously.
 TEST_P(SpdySessionTest, TestYieldingDuringAsyncReadData) {
-  MockConnect connect_data(SYNCHRONOUS, OK);
+  session_deps_.host_resolver->set_synchronous_mode(true);
+
   BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
 
   scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   MockWrite writes[] = {
     CreateMockWrite(*req1, 0),
   };
@@ -2908,31 +2822,30 @@
   scoped_ptr<SpdyFrame> finish_data_frame(framer.CreateDataFrame(
       1, "h", 1, DATA_FLAG_FIN));
 
-  scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> resp1(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
 
   MockRead reads[] = {
-    CreateMockRead(*resp1, 1),
-    CreateMockRead(*eightk_data_frame, 2),
-    CreateMockRead(*eightk_data_frame, 3, SYNCHRONOUS),
-    CreateMockRead(*eightk_data_frame, 4, SYNCHRONOUS),
-    CreateMockRead(*twok_data_frame, 5, SYNCHRONOUS),
-    CreateMockRead(*eightk_data_frame, 6, ASYNC),
-    CreateMockRead(*eightk_data_frame, 7, SYNCHRONOUS),
-    CreateMockRead(*eightk_data_frame, 8, SYNCHRONOUS),
-    CreateMockRead(*eightk_data_frame, 9, SYNCHRONOUS),
-    CreateMockRead(*twok_data_frame, 10, SYNCHRONOUS),
-    CreateMockRead(*finish_data_frame, 11, SYNCHRONOUS),
-    MockRead(ASYNC, 0, 12)  // EOF
+      CreateMockRead(*resp1, 1),
+      MockRead(ASYNC, ERR_IO_PENDING, 2),
+      CreateMockRead(*eightk_data_frame, 3),
+      CreateMockRead(*eightk_data_frame, 4, SYNCHRONOUS),
+      CreateMockRead(*eightk_data_frame, 5, SYNCHRONOUS),
+      CreateMockRead(*twok_data_frame, 6, SYNCHRONOUS),
+      CreateMockRead(*eightk_data_frame, 7, ASYNC),
+      CreateMockRead(*eightk_data_frame, 8, SYNCHRONOUS),
+      CreateMockRead(*eightk_data_frame, 9, SYNCHRONOUS),
+      CreateMockRead(*eightk_data_frame, 10, SYNCHRONOUS),
+      CreateMockRead(*twok_data_frame, 11, SYNCHRONOUS),
+      CreateMockRead(*finish_data_frame, 12, SYNCHRONOUS),
+      MockRead(ASYNC, 0, 13)  // EOF
   };
 
   // Create SpdySession and SpdyStream and send the request.
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.host_resolver->set_synchronous_mode(true);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -2941,7 +2854,7 @@
   base::WeakPtr<SpdyStream> spdy_stream1 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url1, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream1->stream_id());
   test::StreamDelegateDoNothing delegate1(spdy_stream1);
   spdy_stream1->SetDelegate(&delegate1);
@@ -2957,14 +2870,15 @@
 
   // Run until 1st read.
   EXPECT_EQ(0u, delegate1.stream_id());
-  data.RunFor(2);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, delegate1.stream_id());
   EXPECT_EQ(0u, observer.executed_count());
 
   // Read all the data and verify SpdySession::DoReadLoop has posted a
   // task.
-  data.RunFor(12);
-  EXPECT_EQ(NULL, spdy_stream1.get());
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(spdy_stream1);
 
   // Verify task observer's executed_count is 1, which indicates DoRead has
   // posted only one task and thus yielded though there is data available for
@@ -2977,33 +2891,33 @@
 // Send a GoAway frame when SpdySession is in DoReadLoop. Make sure
 // nothing blows up.
 TEST_P(SpdySessionTest, GoAwayWhileInDoReadLoop) {
-  MockConnect connect_data(SYNCHRONOUS, OK);
+  session_deps_.host_resolver->set_synchronous_mode(true);
+
   BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
 
   scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   MockWrite writes[] = {
     CreateMockWrite(*req1, 0),
   };
 
-  scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> resp1(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
   scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true));
   scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway());
 
   MockRead reads[] = {
-    CreateMockRead(*resp1, 1),
-    CreateMockRead(*body1, 2),
-    CreateMockRead(*goaway, 3),
+      CreateMockRead(*resp1, 1),
+      MockRead(ASYNC, ERR_IO_PENDING, 2),
+      CreateMockRead(*body1, 3),
+      CreateMockRead(*goaway, 4),
   };
 
   // Create SpdySession and SpdyStream and send the request.
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.host_resolver->set_synchronous_mode(true);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -3014,7 +2928,7 @@
                                 session, url1, MEDIUM, BoundNetLog());
   test::StreamDelegateDoNothing delegate1(spdy_stream1);
   spdy_stream1->SetDelegate(&delegate1);
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream1->stream_id());
 
   scoped_ptr<SpdyHeaderBlock> headers1(
@@ -3024,15 +2938,16 @@
 
   // Run until 1st read.
   EXPECT_EQ(0u, spdy_stream1->stream_id());
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, spdy_stream1->stream_id());
 
   // Run until GoAway.
-  data.RunFor(3);
-  EXPECT_EQ(NULL, spdy_stream1.get());
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(spdy_stream1);
   EXPECT_TRUE(data.AllWriteDataConsumed());
   EXPECT_TRUE(data.AllReadDataConsumed());
-  EXPECT_TRUE(session == NULL);
+  EXPECT_FALSE(session);
 }
 
 // Within this framework, a SpdySession should be initialized with
@@ -3042,12 +2957,10 @@
 TEST_P(SpdySessionTest, ProtocolNegotiation) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   MockRead reads[] = {
     MockRead(SYNCHRONOUS, 0, 0)  // EOF
   };
-  StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
-  data.set_connect_data(connect_data);
+  StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   CreateNetworkSession();
@@ -3073,12 +2986,10 @@
   ClientSocketPoolManager::set_max_sockets_per_pool(
       HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   MockRead reads[] = {
     MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
   };
-  StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
-  data.set_connect_data(connect_data);
+  StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
@@ -3113,7 +3024,7 @@
   // new connection.
   EXPECT_EQ(OK, callback2.WaitForResult());
   EXPECT_FALSE(pool->IsStalled());
-  EXPECT_TRUE(session1 == NULL);
+  EXPECT_FALSE(session1);
 }
 
 // Tests the case of a non-SPDY request closing an idle SPDY session when no
@@ -3125,12 +3036,10 @@
   ClientSocketPoolManager::set_max_sockets_per_pool(
       HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   MockRead reads[] = {
     MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
   };
-  StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
-  data.set_connect_data(connect_data);
+  StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
@@ -3163,11 +3072,8 @@
   AddressList addresses;
   // Pre-populate the DNS cache, since a synchronous resolution is required in
   // order to create the alias.
-  session_deps_.host_resolver->Resolve(info,
-                                       DEFAULT_PRIORITY,
-                                       &addresses,
-                                       CompletionCallback(),
-                                       NULL,
+  session_deps_.host_resolver->Resolve(info, DEFAULT_PRIORITY, &addresses,
+                                       CompletionCallback(), nullptr,
                                        BoundNetLog());
   // Get a session for |key2|, which should return the session created earlier.
   base::WeakPtr<SpdySession> session2 =
@@ -3193,8 +3099,8 @@
   // new connection.
   EXPECT_EQ(OK, callback3.WaitForResult());
   EXPECT_FALSE(pool->IsStalled());
-  EXPECT_TRUE(session1 == NULL);
-  EXPECT_TRUE(session2 == NULL);
+  EXPECT_FALSE(session1);
+  EXPECT_FALSE(session2);
 }
 
 // Tests that when a SPDY session becomes idle, it closes itself if there is
@@ -3205,12 +3111,11 @@
   ClientSocketPoolManager::set_max_sockets_per_pool(
       HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   MockRead reads[] = {
     MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
   };
   scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> cancel1(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
   MockWrite writes[] = {
@@ -3219,15 +3124,13 @@
   };
   StaticSocketDataProvider data(reads, arraysize(reads),
                                 writes, arraysize(writes));
-  data.set_connect_data(connect_data);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   MockRead http_reads[] = {
     MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
   };
-  StaticSocketDataProvider http_data(http_reads, arraysize(http_reads),
-                                     NULL, 0);
-  http_data.set_connect_data(connect_data);
+  StaticSocketDataProvider http_data(http_reads, arraysize(http_reads), nullptr,
+                                     0);
   session_deps_.socket_factory->AddSocketDataProvider(&http_data);
 
 
@@ -3263,7 +3166,7 @@
                 headers1.Pass(), NO_MORE_DATA_TO_SEND));
   EXPECT_TRUE(spdy_stream1->HasUrlFromHeaders());
 
-  base::MessageLoop::current()->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
 
   // Trying to create a new connection should cause the pool to be stalled, and
   // post a task asynchronously to try and close the session.
@@ -3298,7 +3201,7 @@
 // Verify that SpdySessionKey and therefore SpdySession is different when
 // privacy mode is enabled or disabled.
 TEST_P(SpdySessionTest, SpdySessionKeyPrivacyMode) {
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   HostPortPair host_port_pair("www.example.org", 443);
   SpdySessionKey key_privacy_enabled(host_port_pair, ProxyServer::Direct(),
@@ -3359,10 +3262,8 @@
 TEST_P(SpdySessionTest, CreateStreamOnStreamReset) {
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
-
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, MEDIUM, true));
   MockWrite writes[] = {
     CreateMockWrite(*req, 0),
   };
@@ -3370,15 +3271,15 @@
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM));
   MockRead reads[] = {
-    CreateMockRead(*rst, 1),
-    MockRead(ASYNC, 0, 2)  // EOF
+      MockRead(ASYNC, ERR_IO_PENDING, 1),
+      CreateMockRead(*rst, 2),
+      MockRead(ASYNC, ERR_IO_PENDING, 3),
+      MockRead(ASYNC, 0, 4)  // EOF
   };
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -3387,7 +3288,7 @@
   base::WeakPtr<SpdyStream> spdy_stream =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(spdy_stream.get() != NULL);
+  ASSERT_TRUE(spdy_stream.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream->stream_id());
 
   StreamCreatingDelegate delegate(spdy_stream, session);
@@ -3400,18 +3301,23 @@
 
   EXPECT_EQ(0u, spdy_stream->stream_id());
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(1u, spdy_stream->stream_id());
 
   // Cause the stream to be reset, which should cause another stream
   // to be created.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(NULL, spdy_stream.get());
+  EXPECT_FALSE(spdy_stream);
   EXPECT_TRUE(delegate.StreamIsClosed());
   EXPECT_EQ(0u, session->num_active_streams());
   EXPECT_EQ(1u, session->num_created_streams());
+
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // The tests below are only for SPDY/3 and above.
@@ -3426,60 +3332,63 @@
 
   // Set up the socket so we read a SETTINGS frame that sets
   // INITIAL_WINDOW_SIZE.
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> settings_frame(
       spdy_util_.ConstructSpdySettings(new_settings));
   MockRead reads[] = {
-    CreateMockRead(*settings_frame, 0),
-    MockRead(ASYNC, 0, 1)  // EOF
+      CreateMockRead(*settings_frame, 0),
+      MockRead(ASYNC, ERR_IO_PENDING, 1),
+      MockRead(ASYNC, 0, 2)  // EOF
   };
 
   scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
   MockWrite writes[] = {
-    CreateMockWrite(*settings_ack, 2),
+      CreateMockWrite(*settings_ack, 3),
   };
 
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
   base::WeakPtr<SpdyStream> spdy_stream1 =
       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                 session, test_url_, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
   TestCompletionCallback callback1;
   EXPECT_NE(spdy_stream1->send_window_size(), window_size);
 
-  data.RunFor(1);  // Process the SETTINGS frame, but not the EOF
-  base::MessageLoop::current()->RunUntilIdle();
+  // Process the SETTINGS frame.
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(session->stream_initial_send_window_size(), window_size);
   EXPECT_EQ(spdy_stream1->send_window_size(), window_size);
 
   // Release the first one, this will allow the second to be created.
   spdy_stream1->Cancel();
-  EXPECT_EQ(NULL, spdy_stream1.get());
+  EXPECT_FALSE(spdy_stream1);
 
   base::WeakPtr<SpdyStream> spdy_stream2 =
       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                 session, test_url_, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(spdy_stream2.get() != NULL);
+  ASSERT_TRUE(spdy_stream2.get() != nullptr);
   EXPECT_EQ(spdy_stream2->send_window_size(), window_size);
   spdy_stream2->Cancel();
-  EXPECT_EQ(NULL, spdy_stream2.get());
+  EXPECT_FALSE(spdy_stream2);
+
+  EXPECT_TRUE(session);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // The tests below are only for SPDY/3.1 and above.
 
 // SpdySession::{Increase,Decrease}RecvWindowSize should properly
-// adjust the session receive window size for SPDY 3.1 and higher. In
-// addition, SpdySession::IncreaseRecvWindowSize should trigger
+// adjust the session receive window size. In addition,
+// SpdySession::IncreaseRecvWindowSize should trigger
 // sending a WINDOW_UPDATE frame for a large enough delta.
 TEST_P(SpdySessionTest, AdjustRecvWindowSize) {
   if (GetParam() < kProtoSPDY31)
@@ -3491,21 +3400,18 @@
       SpdySession::GetDefaultInitialWindowSize(GetParam());
   const int32 delta_window_size = 100;
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   MockRead reads[] = {
-    MockRead(ASYNC, 0, 1)  // EOF
+      MockRead(ASYNC, ERR_IO_PENDING, 1), MockRead(ASYNC, 0, 2)  // EOF
   };
   scoped_ptr<SpdyFrame> window_update(spdy_util_.ConstructSpdyWindowUpdate(
       kSessionFlowControlStreamId, initial_window_size + delta_window_size));
   MockWrite writes[] = {
     CreateMockWrite(*window_update, 0),
   };
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
   EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
@@ -3525,7 +3431,7 @@
             session->session_recv_window_size_);
   EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   // DecreaseRecvWindowSize() expects |in_io_loop_| to be true.
   session->in_io_loop_ = true;
@@ -3534,6 +3440,11 @@
   session->in_io_loop_ = false;
   EXPECT_EQ(0, session->session_recv_window_size_);
   EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
+
+  EXPECT_TRUE(session);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // SpdySession::{Increase,Decrease}SendWindowSize should properly
@@ -3545,12 +3456,10 @@
 
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   MockRead reads[] = {
     MockRead(SYNCHRONOUS, 0, 0)  // EOF
   };
-  StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
-  data.set_connect_data(connect_data);
+  StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   CreateNetworkSession();
@@ -3582,17 +3491,16 @@
 
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyBodyFrame(1, false));
   MockRead reads[] = {
-    CreateMockRead(*resp, 0),
-    MockRead(ASYNC, 0, 1)  // EOF
+      CreateMockRead(*resp, 0),
+      MockRead(ASYNC, ERR_IO_PENDING, 1),
+      MockRead(ASYNC, 0, 2)  // EOF
   };
-  DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), nullptr, 0);
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
   EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
@@ -3602,13 +3510,16 @@
             session->session_recv_window_size_);
   EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetParam()),
             session->session_recv_window_size_);
   EXPECT_EQ(kUploadDataSize, session->session_unacked_recv_window_bytes_);
 
-  data.RunFor(1);
+  EXPECT_TRUE(session);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // The frame header is not included in flow control, but frame payload
@@ -3621,17 +3532,17 @@
   session_deps_.host_resolver->set_synchronous_mode(true);
 
   const int padding_length = 42;
-  MockConnect connect_data(SYNCHRONOUS, OK);
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyBodyFrame(
       1, kUploadData, kUploadDataSize, false, padding_length));
   MockRead reads[] = {
-      CreateMockRead(*resp, 0), MockRead(ASYNC, 0, 1)  // EOF
+      CreateMockRead(*resp, 0),
+      MockRead(ASYNC, ERR_IO_PENDING, 1),
+      MockRead(ASYNC, 0, 2)  // EOF
   };
-  DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), nullptr, 0);
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
   EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
@@ -3641,14 +3552,16 @@
             session->session_recv_window_size_);
   EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetParam()),
             session->session_recv_window_size_);
   EXPECT_EQ(kUploadDataSize + padding_length,
             session->session_unacked_recv_window_bytes_);
 
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // Peer sends more data than stream level receiving flow control window.
@@ -3657,26 +3570,29 @@
   const int32 data_frame_size = 2 * stream_max_recv_window_size;
 
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
+  scoped_ptr<SpdyFrame> rst(
+      spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
   MockWrite writes[] = {
-      CreateMockWrite(*req, 0),
+      CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
   };
 
-  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> resp(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
   const std::string payload(data_frame_size, 'a');
   scoped_ptr<SpdyFrame> data_frame(spdy_util_.ConstructSpdyBodyFrame(
       1, payload.data(), data_frame_size, false));
   MockRead reads[] = {
       CreateMockRead(*resp, 1),
-      CreateMockRead(*data_frame, 2),
-      MockRead(ASYNC, 0, 3),
+      MockRead(ASYNC, ERR_IO_PENDING, 2),
+      CreateMockRead(*data_frame, 3),
+      MockRead(ASYNC, ERR_IO_PENDING, 5),
+      MockRead(ASYNC, 0, 6),
   };
 
-  DeterministicSocketData data(reads, arraysize(reads), writes,
-                               arraysize(writes));
-  data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
-  CreateDeterministicNetworkSession();
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
+  CreateNetworkSession();
 
   SpdySessionPoolPeer pool_peer(spdy_session_pool_);
   pool_peer.SetStreamInitialRecvWindowSize(stream_max_recv_window_size);
@@ -3698,12 +3614,18 @@
                                 headers.Pass(), NO_MORE_DATA_TO_SEND));
 
   // Request and response.
-  data.RunFor(2);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, spdy_stream->stream_id());
 
   // Too large data frame causes flow control error, should close stream.
-  data.RunFor(1);
-  EXPECT_EQ(nullptr, spdy_stream.get());
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(spdy_stream);
+
+  EXPECT_TRUE(session);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // Regression test for a bug that was caused by including unsent WINDOW_UPDATE
@@ -3728,6 +3650,14 @@
 
   session_deps_.host_resolver->set_synchronous_mode(true);
 
+  scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+      0, GOAWAY_FLOW_CONTROL_ERROR,
+      "delta_window_size is 400 in DecreaseRecvWindowSize, which is larger "
+      "than the receive window size of 500"));
+  MockWrite writes[] = {
+      CreateMockWrite(*goaway, 4),
+  };
+
   const std::string first_data_frame(first_data_frame_size, 'a');
   scoped_ptr<SpdyFrame> first(spdy_util_.ConstructSpdyBodyFrame(
       1, first_data_frame.data(), first_data_frame_size, false));
@@ -3736,14 +3666,14 @@
       1, second_data_frame.data(), second_data_frame_size, false));
   MockRead reads[] = {
       CreateMockRead(*first, 0),
-      CreateMockRead(*second, 1),
-      MockRead(ASYNC, 0, 2),
+      MockRead(ASYNC, ERR_IO_PENDING, 1),
+      CreateMockRead(*second, 2),
+      MockRead(ASYNC, 0, 3),
   };
-  DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
-  data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
   EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
@@ -3754,13 +3684,14 @@
 
   // First data frame is immediately consumed and does not trigger
   // WINDOW_UPDATE.
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(first_data_frame_size, session->session_unacked_recv_window_bytes_);
   EXPECT_EQ(session_max_recv_window_size, session->session_recv_window_size_);
   EXPECT_EQ(SpdySession::STATE_AVAILABLE, session->availability_state_);
 
   // Second data frame overflows receiving window, causes session to close.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(SpdySession::STATE_DRAINING, session->availability_state_);
 }
 
@@ -3784,14 +3715,15 @@
             first_data_frame_size + second_data_frame_size);
 
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR));
   MockWrite writes[] = {
-      CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
+      CreateMockWrite(*req, 0), CreateMockWrite(*rst, 6),
   };
 
-  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> resp(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
   const std::string first_data_frame(first_data_frame_size, 'a');
   scoped_ptr<SpdyFrame> first(spdy_util_.ConstructSpdyBodyFrame(
       1, first_data_frame.data(), first_data_frame_size, false));
@@ -3800,17 +3732,18 @@
       1, second_data_frame.data(), second_data_frame_size, false));
   MockRead reads[] = {
       CreateMockRead(*resp, 1),
-      CreateMockRead(*first, 2),
-      CreateMockRead(*second, 3),
-      MockRead(ASYNC, 0, 5),
+      MockRead(ASYNC, ERR_IO_PENDING, 2),
+      CreateMockRead(*first, 3),
+      MockRead(ASYNC, ERR_IO_PENDING, 4),
+      CreateMockRead(*second, 5),
+      MockRead(ASYNC, ERR_IO_PENDING, 7),
+      MockRead(ASYNC, 0, 8),
   };
 
-  DeterministicSocketData data(reads, arraysize(reads), writes,
-                               arraysize(writes));
-  data.set_connect_data(MockConnect(SYNCHRONOUS, OK));
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
   SpdySessionPoolPeer pool_peer(spdy_session_pool_);
   pool_peer.SetStreamInitialRecvWindowSize(stream_max_recv_window_size);
 
@@ -3829,12 +3762,13 @@
                                 headers.Pass(), NO_MORE_DATA_TO_SEND));
 
   // Request and response.
-  data.RunFor(2);
+  base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(spdy_stream->IsLocallyClosed());
   EXPECT_EQ(stream_max_recv_window_size, spdy_stream->recv_window_size());
 
   // First data frame.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(spdy_stream->IsLocallyClosed());
   EXPECT_EQ(stream_max_recv_window_size - first_data_frame_size,
             spdy_stream->recv_window_size());
@@ -3845,11 +3779,15 @@
   EXPECT_EQ(stream_max_recv_window_size, spdy_stream->recv_window_size());
 
   // Second data frame overflows receiving window, causes the stream to close.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(spdy_stream.get());
 
   // RST_STREAM
-  data.RunFor(1);
+  EXPECT_TRUE(session);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // A delegate that drops any received data.
@@ -3877,11 +3815,8 @@
   const int32 msg_data_size = 100;
   const std::string msg_data(msg_data_size, 'a');
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
-
-  scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyPost(
-          kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0));
+  scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
+      kStreamUrl, 1, msg_data_size, MEDIUM, nullptr, 0));
   scoped_ptr<SpdyFrame> msg(
       spdy_util_.ConstructSpdyBodyFrame(
           1, msg_data.data(), msg_data_size, false));
@@ -3890,7 +3825,8 @@
     CreateMockWrite(*msg, 2),
   };
 
-  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> resp(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
   scoped_ptr<SpdyFrame> echo(
       spdy_util_.ConstructSpdyBodyFrame(
           1, msg_data.data(), msg_data_size, false));
@@ -3898,19 +3834,18 @@
       spdy_util_.ConstructSpdyWindowUpdate(
           kSessionFlowControlStreamId, msg_data_size));
   MockRead reads[] = {
-    CreateMockRead(*resp, 1),
-    CreateMockRead(*echo, 3),
-    MockRead(ASYNC, 0, 4)  // EOF
+      CreateMockRead(*resp, 1),
+      CreateMockRead(*echo, 3),
+      MockRead(ASYNC, ERR_IO_PENDING, 4),
+      MockRead(ASYNC, 0, 5)  // EOF
   };
 
   // Create SpdySession and SpdyStream and send the request.
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   session_deps_.host_resolver->set_synchronous_mode(true);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -3919,7 +3854,7 @@
   base::WeakPtr<SpdyStream> stream =
       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                 session, url, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(stream.get() != NULL);
+  ASSERT_TRUE(stream.get() != nullptr);
   EXPECT_EQ(0u, stream->stream_id());
 
   DropReceivedDataDelegate delegate(stream, msg_data);
@@ -3936,21 +3871,22 @@
   EXPECT_EQ(initial_window_size, session->session_recv_window_size_);
   EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
 
-  data.RunFor(4);
-
-  EXPECT_TRUE(data.AllWriteDataConsumed());
-  EXPECT_TRUE(data.AllReadDataConsumed());
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(initial_window_size, session->session_recv_window_size_);
   EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
 
   stream->Close();
-  EXPECT_EQ(NULL, stream.get());
+  EXPECT_FALSE(stream);
 
   EXPECT_EQ(OK, delegate.WaitForClose());
 
   EXPECT_EQ(initial_window_size, session->session_recv_window_size_);
   EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
+
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // Send data back and forth but close the stream before its data frame
@@ -3965,29 +3901,26 @@
   const int32 msg_data_size = 100;
   const std::string msg_data(msg_data_size, 'a');
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
-
-  scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyPost(
-          kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0));
+  scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
+      kStreamUrl, 1, msg_data_size, MEDIUM, nullptr, 0));
   MockWrite writes[] = {
-    CreateMockWrite(*req, 0),
+      CreateMockWrite(*req, 0),
   };
 
-  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> resp(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
   MockRead reads[] = {
-    CreateMockRead(*resp, 1),
-    MockRead(ASYNC, 0, 2)  // EOF
+      MockRead(ASYNC, ERR_IO_PENDING, 1),
+      CreateMockRead(*resp, 2),
+      MockRead(ASYNC, 0, 3)  // EOF
   };
 
   // Create SpdySession and SpdyStream and send the request.
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   session_deps_.host_resolver->set_synchronous_mode(true);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -3996,7 +3929,7 @@
   base::WeakPtr<SpdyStream> stream =
       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                 session, url, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(stream.get() != NULL);
+  ASSERT_TRUE(stream.get() != nullptr);
   EXPECT_EQ(0u, stream->stream_id());
 
   test::StreamDelegateSendImmediate delegate(stream, msg_data);
@@ -4012,25 +3945,31 @@
       SpdySession::GetDefaultInitialWindowSize(GetParam());
   EXPECT_EQ(initial_window_size, session->session_send_window_size_);
 
-  data.RunFor(1);
+  // Write request.
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(initial_window_size, session->session_send_window_size_);
 
-  data.RunFor(1);
-
-  EXPECT_TRUE(data.AllWriteDataConsumed());
-  EXPECT_TRUE(data.AllReadDataConsumed());
+  // Read response, but do not run the message loop, so that the body is not
+  // written to the socket.
+  data.CompleteRead();
 
   EXPECT_EQ(initial_window_size - msg_data_size,
             session->session_send_window_size_);
 
   // Closing the stream should increase the session's send window.
   stream->Close();
-  EXPECT_EQ(NULL, stream.get());
+  EXPECT_FALSE(stream);
 
   EXPECT_EQ(initial_window_size, session->session_send_window_size_);
 
   EXPECT_EQ(OK, delegate.WaitForClose());
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
+
+  EXPECT_TRUE(data.AllWriteDataConsumed());
+  EXPECT_TRUE(data.AllReadDataConsumed());
 }
 
 // Send data back and forth; the send and receive windows should
@@ -4044,11 +3983,8 @@
   const int32 msg_data_size = 100;
   const std::string msg_data(msg_data_size, 'a');
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
-
-  scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyPost(
-          kStreamUrl, 1, msg_data_size, MEDIUM, NULL, 0));
+  scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
+      kStreamUrl, 1, msg_data_size, MEDIUM, nullptr, 0));
   scoped_ptr<SpdyFrame> msg(
       spdy_util_.ConstructSpdyBodyFrame(
           1, msg_data.data(), msg_data_size, false));
@@ -4057,7 +3993,8 @@
     CreateMockWrite(*msg, 2),
   };
 
-  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> resp(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
   scoped_ptr<SpdyFrame> echo(
       spdy_util_.ConstructSpdyBodyFrame(
           1, msg_data.data(), msg_data_size, false));
@@ -4065,20 +4002,21 @@
       spdy_util_.ConstructSpdyWindowUpdate(
           kSessionFlowControlStreamId, msg_data_size));
   MockRead reads[] = {
-    CreateMockRead(*resp, 1),
-    CreateMockRead(*echo, 3),
-    CreateMockRead(*window_update, 4),
-    MockRead(ASYNC, 0, 5)  // EOF
+      CreateMockRead(*resp, 1),
+      MockRead(ASYNC, ERR_IO_PENDING, 3),
+      CreateMockRead(*echo, 4),
+      MockRead(ASYNC, ERR_IO_PENDING, 5),
+      CreateMockRead(*window_update, 6),
+      MockRead(ASYNC, ERR_IO_PENDING, 7),
+      MockRead(ASYNC, 0, 8)  // EOF
   };
 
   // Create SpdySession and SpdyStream and send the request.
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  data.set_connect_data(connect_data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
   session_deps_.host_resolver->set_synchronous_mode(true);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -4087,7 +4025,7 @@
   base::WeakPtr<SpdyStream> stream =
       CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
                                 session, url, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(stream.get() != NULL);
+  ASSERT_TRUE(stream.get() != nullptr);
   EXPECT_EQ(0u, stream->stream_id());
 
   test::StreamDelegateSendImmediate delegate(stream, msg_data);
@@ -4105,27 +4043,17 @@
   EXPECT_EQ(initial_window_size, session->session_recv_window_size_);
   EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
 
-  data.RunFor(1);
-
-  EXPECT_EQ(initial_window_size, session->session_send_window_size_);
-  EXPECT_EQ(initial_window_size, session->session_recv_window_size_);
-  EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
-
-  data.RunFor(1);
+  // Send request and message.
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(initial_window_size - msg_data_size,
             session->session_send_window_size_);
   EXPECT_EQ(initial_window_size, session->session_recv_window_size_);
   EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
 
-  data.RunFor(1);
-
-  EXPECT_EQ(initial_window_size - msg_data_size,
-            session->session_send_window_size_);
-  EXPECT_EQ(initial_window_size, session->session_recv_window_size_);
-  EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
-
-  data.RunFor(1);
+  // Read echo.
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(initial_window_size - msg_data_size,
             session->session_send_window_size_);
@@ -4133,16 +4061,15 @@
             session->session_recv_window_size_);
   EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
 
-  data.RunFor(1);
+  // Read window update.
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(initial_window_size, session->session_send_window_size_);
   EXPECT_EQ(initial_window_size - msg_data_size,
             session->session_recv_window_size_);
   EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
 
-  EXPECT_TRUE(data.AllWriteDataConsumed());
-  EXPECT_TRUE(data.AllReadDataConsumed());
-
   EXPECT_EQ(msg_data, delegate.TakeReceivedData());
 
   // Draining the delegate's read queue should increase the session's
@@ -4152,13 +4079,17 @@
   EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
 
   stream->Close();
-  EXPECT_EQ(NULL, stream.get());
+  EXPECT_FALSE(stream);
 
   EXPECT_EQ(OK, delegate.WaitForClose());
 
   EXPECT_EQ(initial_window_size, session->session_send_window_size_);
   EXPECT_EQ(initial_window_size, session->session_recv_window_size_);
   EXPECT_EQ(msg_data_size, session->session_unacked_recv_window_bytes_);
+
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 // Given a stall function and an unstall function, runs a test to make
@@ -4172,9 +4103,8 @@
 
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyPost(
-          kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
+  scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
+      kStreamUrl, 1, kBodyDataSize, LOWEST, nullptr, 0));
   scoped_ptr<SpdyFrame> body(
       spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, true));
   MockWrite writes[] = {
@@ -4183,22 +4113,17 @@
   };
 
   scoped_ptr<SpdyFrame> resp(
-      spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
   scoped_ptr<SpdyFrame> echo(
       spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, false));
   MockRead reads[] = {
-    CreateMockRead(*resp, 2),
-    MockRead(ASYNC, 0, 0, 3), // EOF
+      CreateMockRead(*resp, 2), MockRead(ASYNC, 0, 3)  // EOF
   };
 
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
-
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
   EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
@@ -4207,7 +4132,7 @@
   base::WeakPtr<SpdyStream> stream =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url, LOWEST, BoundNetLog());
-  ASSERT_TRUE(stream.get() != NULL);
+  ASSERT_TRUE(stream.get() != nullptr);
 
   test::StreamDelegateWithBody delegate(stream, kBodyDataStringPiece);
   stream->SetDelegate(&delegate);
@@ -4224,7 +4149,7 @@
 
   stall_function.Run(session.get(), stream.get());
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_TRUE(stream->send_stalled_by_flow_control());
 
@@ -4232,13 +4157,12 @@
 
   EXPECT_FALSE(stream->send_stalled_by_flow_control());
 
-  data.RunFor(3);
-
   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
 
   EXPECT_TRUE(delegate.send_headers_completed());
   EXPECT_EQ("200", delegate.GetResponseHeaderValue(":status"));
   EXPECT_EQ(std::string(), delegate.TakeReceivedData());
+  EXPECT_FALSE(session);
   EXPECT_TRUE(data.AllWriteDataConsumed());
 }
 
@@ -4325,12 +4249,10 @@
 
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyPost(
-          kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
-  scoped_ptr<SpdyFrame> req2(
-      spdy_util_.ConstructSpdyPost(
-          kStreamUrl, 3, kBodyDataSize, MEDIUM, NULL, 0));
+  scoped_ptr<SpdyFrame> req1(spdy_util_.ConstructSpdyPost(
+      kStreamUrl, 1, kBodyDataSize, LOWEST, nullptr, 0));
+  scoped_ptr<SpdyFrame> req2(spdy_util_.ConstructSpdyPost(
+      kStreamUrl, 3, kBodyDataSize, MEDIUM, nullptr, 0));
   scoped_ptr<SpdyFrame> body1(
       spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, true));
   scoped_ptr<SpdyFrame> body2(
@@ -4342,22 +4264,20 @@
     CreateMockWrite(*body1, 3),
   };
 
-  scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
-  scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
+  scoped_ptr<SpdyFrame> resp1(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
+  scoped_ptr<SpdyFrame> resp2(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 3));
   MockRead reads[] = {
-    CreateMockRead(*resp1, 4),
-    CreateMockRead(*resp2, 5),
-    MockRead(ASYNC, 0, 0, 6), // EOF
+      CreateMockRead(*resp1, 4),
+      CreateMockRead(*resp2, 5),
+      MockRead(ASYNC, 0, 6)  // EOF
   };
 
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
-
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
   EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
@@ -4366,7 +4286,7 @@
   base::WeakPtr<SpdyStream> stream1 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url, LOWEST, BoundNetLog());
-  ASSERT_TRUE(stream1.get() != NULL);
+  ASSERT_TRUE(stream1.get() != nullptr);
 
   test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
   stream1->SetDelegate(&delegate1);
@@ -4376,7 +4296,7 @@
   base::WeakPtr<SpdyStream> stream2 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url, MEDIUM, BoundNetLog());
-  ASSERT_TRUE(stream2.get() != NULL);
+  ASSERT_TRUE(stream2.get() != nullptr);
 
   test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece);
   stream2->SetDelegate(&delegate2);
@@ -4395,7 +4315,7 @@
   EXPECT_TRUE(stream1->HasUrlFromHeaders());
   EXPECT_EQ(kStreamUrl, stream1->GetUrlFromHeaders().spec());
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, stream1->stream_id());
   EXPECT_TRUE(stream1->send_stalled_by_flow_control());
 
@@ -4406,7 +4326,7 @@
   EXPECT_TRUE(stream2->HasUrlFromHeaders());
   EXPECT_EQ(kStreamUrl, stream2->GetUrlFromHeaders().spec());
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(3u, stream2->stream_id());
   EXPECT_TRUE(stream2->send_stalled_by_flow_control());
 
@@ -4416,7 +4336,7 @@
   EXPECT_TRUE(stream1->send_stalled_by_flow_control());
   EXPECT_FALSE(stream2->send_stalled_by_flow_control());
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_TRUE(stream1->send_stalled_by_flow_control());
   EXPECT_FALSE(stream2->send_stalled_by_flow_control());
@@ -4427,7 +4347,7 @@
   EXPECT_FALSE(stream1->send_stalled_by_flow_control());
   EXPECT_FALSE(stream2->send_stalled_by_flow_control());
 
-  data.RunFor(4);
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose());
   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose());
@@ -4440,7 +4360,9 @@
   EXPECT_EQ("200", delegate2.GetResponseHeaderValue(":status"));
   EXPECT_EQ(std::string(), delegate2.TakeReceivedData());
 
+  EXPECT_FALSE(session);
   EXPECT_TRUE(data.AllWriteDataConsumed());
+  EXPECT_TRUE(data.AllReadDataConsumed());
 }
 
 // Delegate that closes a given stream after sending its body.
@@ -4460,7 +4382,7 @@
     test::StreamDelegateWithBody::OnDataSent();
     if (stream_to_close_.get()) {
       stream_to_close_->Close();
-      EXPECT_EQ(NULL, stream_to_close_.get());
+      EXPECT_FALSE(stream_to_close_);
     }
   }
 
@@ -4479,15 +4401,12 @@
 
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyPost(
-          kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
-  scoped_ptr<SpdyFrame> req2(
-      spdy_util_.ConstructSpdyPost(
-          kStreamUrl, 3, kBodyDataSize, LOWEST, NULL, 0));
-  scoped_ptr<SpdyFrame> req3(
-      spdy_util_.ConstructSpdyPost(
-          kStreamUrl, 5, kBodyDataSize, LOWEST, NULL, 0));
+  scoped_ptr<SpdyFrame> req1(spdy_util_.ConstructSpdyPost(
+      kStreamUrl, 1, kBodyDataSize, LOWEST, nullptr, 0));
+  scoped_ptr<SpdyFrame> req2(spdy_util_.ConstructSpdyPost(
+      kStreamUrl, 3, kBodyDataSize, LOWEST, nullptr, 0));
+  scoped_ptr<SpdyFrame> req3(spdy_util_.ConstructSpdyPost(
+      kStreamUrl, 5, kBodyDataSize, LOWEST, nullptr, 0));
   scoped_ptr<SpdyFrame> body2(
       spdy_util_.ConstructSpdyBodyFrame(3, kBodyData, kBodyDataSize, true));
   MockWrite writes[] = {
@@ -4497,20 +4416,18 @@
     CreateMockWrite(*body2, 3),
   };
 
-  scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
+  scoped_ptr<SpdyFrame> resp2(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 3));
   MockRead reads[] = {
-    CreateMockRead(*resp2, 4),
-    MockRead(ASYNC, 0, 0, 5), // EOF
+      CreateMockRead(*resp2, 4),
+      MockRead(ASYNC, ERR_IO_PENDING, 5),
+      MockRead(ASYNC, 0, 6)  // EOF
   };
 
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
-
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
   EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
@@ -4519,7 +4436,7 @@
   base::WeakPtr<SpdyStream> stream1 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url, LOWEST, BoundNetLog());
-  ASSERT_TRUE(stream1.get() != NULL);
+  ASSERT_TRUE(stream1.get() != nullptr);
 
   test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
   stream1->SetDelegate(&delegate1);
@@ -4529,7 +4446,7 @@
   base::WeakPtr<SpdyStream> stream2 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url, LOWEST, BoundNetLog());
-  ASSERT_TRUE(stream2.get() != NULL);
+  ASSERT_TRUE(stream2.get() != nullptr);
 
   StreamClosingDelegate delegate2(stream2, kBodyDataStringPiece);
   stream2->SetDelegate(&delegate2);
@@ -4539,7 +4456,7 @@
   base::WeakPtr<SpdyStream> stream3 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url, LOWEST, BoundNetLog());
-  ASSERT_TRUE(stream3.get() != NULL);
+  ASSERT_TRUE(stream3.get() != nullptr);
 
   test::StreamDelegateWithBody delegate3(stream3, kBodyDataStringPiece);
   stream3->SetDelegate(&delegate3);
@@ -4559,7 +4476,7 @@
   EXPECT_TRUE(stream1->HasUrlFromHeaders());
   EXPECT_EQ(kStreamUrl, stream1->GetUrlFromHeaders().spec());
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, stream1->stream_id());
   EXPECT_TRUE(stream1->send_stalled_by_flow_control());
 
@@ -4570,7 +4487,7 @@
   EXPECT_TRUE(stream2->HasUrlFromHeaders());
   EXPECT_EQ(kStreamUrl, stream2->GetUrlFromHeaders().spec());
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(3u, stream2->stream_id());
   EXPECT_TRUE(stream2->send_stalled_by_flow_control());
 
@@ -4581,7 +4498,7 @@
   EXPECT_TRUE(stream3->HasUrlFromHeaders());
   EXPECT_EQ(kStreamUrl, stream3->GetUrlFromHeaders().spec());
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(5u, stream3->stream_id());
   EXPECT_TRUE(stream3->send_stalled_by_flow_control());
 
@@ -4591,7 +4508,7 @@
 
   // Close stream1 preemptively.
   session->CloseActiveStream(stream_id1, ERR_CONNECTION_CLOSED);
-  EXPECT_EQ(NULL, stream1.get());
+  EXPECT_FALSE(stream1);
 
   EXPECT_FALSE(session->IsStreamActive(stream_id1));
   EXPECT_TRUE(session->IsStreamActive(stream_id2));
@@ -4601,16 +4518,18 @@
   delegate2.set_stream_to_close(stream3);
   UnstallSessionSend(session.get(), kBodyDataSize);
 
-  data.RunFor(1);
-  EXPECT_EQ(NULL, stream3.get());
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(stream3);
 
   EXPECT_FALSE(stream2->send_stalled_by_flow_control());
   EXPECT_FALSE(session->IsStreamActive(stream_id1));
   EXPECT_TRUE(session->IsStreamActive(stream_id2));
   EXPECT_FALSE(session->IsStreamActive(stream_id3));
 
-  data.RunFor(2);
-  EXPECT_EQ(NULL, stream2.get());
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(stream2);
+  EXPECT_FALSE(session);
 
   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate1.WaitForClose());
   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate2.WaitForClose());
@@ -4641,12 +4560,10 @@
 
   session_deps_.host_resolver->set_synchronous_mode(true);
 
-  scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyPost(
-          kStreamUrl, 1, kBodyDataSize, LOWEST, NULL, 0));
-  scoped_ptr<SpdyFrame> req2(
-      spdy_util_.ConstructSpdyPost(
-          kStreamUrl, 3, kBodyDataSize, LOWEST, NULL, 0));
+  scoped_ptr<SpdyFrame> req1(spdy_util_.ConstructSpdyPost(
+      kStreamUrl, 1, kBodyDataSize, LOWEST, nullptr, 0));
+  scoped_ptr<SpdyFrame> req2(spdy_util_.ConstructSpdyPost(
+      kStreamUrl, 3, kBodyDataSize, LOWEST, nullptr, 0));
   scoped_ptr<SpdyFrame> body1(
       spdy_util_.ConstructSpdyBodyFrame(1, kBodyData, kBodyDataSize, false));
   MockWrite writes[] = {
@@ -4655,17 +4572,13 @@
   };
 
   MockRead reads[] = {
-    MockRead(ASYNC, 0, 0, 2), // EOF
+      MockRead(ASYNC, ERR_IO_PENDING, 2), MockRead(ASYNC, 0, 3)  // EOF
   };
 
-  DeterministicSocketData data(reads, arraysize(reads),
-                               writes, arraysize(writes));
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
-
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
   EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
@@ -4674,7 +4587,7 @@
   base::WeakPtr<SpdyStream> stream1 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url, LOWEST, BoundNetLog());
-  ASSERT_TRUE(stream1.get() != NULL);
+  ASSERT_TRUE(stream1.get() != nullptr);
 
   test::StreamDelegateWithBody delegate1(stream1, kBodyDataStringPiece);
   stream1->SetDelegate(&delegate1);
@@ -4684,7 +4597,7 @@
   base::WeakPtr<SpdyStream> stream2 =
       CreateStreamSynchronously(SPDY_REQUEST_RESPONSE_STREAM,
                                 session, url, LOWEST, BoundNetLog());
-  ASSERT_TRUE(stream2.get() != NULL);
+  ASSERT_TRUE(stream2.get() != nullptr);
 
   test::StreamDelegateWithBody delegate2(stream2, kBodyDataStringPiece);
   stream2->SetDelegate(&delegate2);
@@ -4703,7 +4616,7 @@
   EXPECT_TRUE(stream1->HasUrlFromHeaders());
   EXPECT_EQ(kStreamUrl, stream1->GetUrlFromHeaders().spec());
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, stream1->stream_id());
   EXPECT_TRUE(stream1->send_stalled_by_flow_control());
 
@@ -4714,7 +4627,7 @@
   EXPECT_TRUE(stream2->HasUrlFromHeaders());
   EXPECT_EQ(kStreamUrl, stream2->GetUrlFromHeaders().spec());
 
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(3u, stream2->stream_id());
   EXPECT_TRUE(stream2->send_stalled_by_flow_control());
 
@@ -4726,8 +4639,9 @@
   // Close the session (since we can't do it from within the delegate
   // method, since it's in the stream's loop).
   session->CloseSessionOnError(ERR_CONNECTION_CLOSED, "Closing session");
+  data.CompleteRead();
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(session == NULL);
+  EXPECT_FALSE(session);
 
   EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
 
@@ -4747,31 +4661,29 @@
   if (GetParam() < kProtoSPDY31)
     return;
 
-  MockConnect connect_data(SYNCHRONOUS, OK);
-
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
-      0,
-      GOAWAY_FLOW_CONTROL_ERROR,
+      0, GOAWAY_FLOW_CONTROL_ERROR,
       "delta_window_size is 6 in DecreaseRecvWindowSize, which is larger than "
       "the receive window size of 1"));
   MockWrite writes[] = {
-      CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 3),
+      CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 4),
   };
 
-  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> resp(
+      spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-      CreateMockRead(*resp, 1), CreateMockRead(*body, 2),
+      MockRead(ASYNC, ERR_IO_PENDING, 1),
+      CreateMockRead(*resp, 2),
+      CreateMockRead(*body, 3),
   };
 
-  DeterministicSocketData data(
-      reads, arraysize(reads), writes, arraysize(writes));
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -4779,7 +4691,7 @@
   GURL url(kDefaultURL);
   base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
       SPDY_REQUEST_RESPONSE_STREAM, session, url, LOWEST, BoundNetLog());
-  ASSERT_TRUE(spdy_stream.get() != NULL);
+  ASSERT_TRUE(spdy_stream.get() != nullptr);
   test::StreamDelegateDoNothing delegate(spdy_stream);
   spdy_stream->SetDelegate(&delegate);
 
@@ -4787,18 +4699,19 @@
       spdy_util_.ConstructGetHeaderBlock(url.spec()));
   spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
 
-  data.RunFor(1);  // Write request.
+  // Write request.
+  base::RunLoop().RunUntilIdle();
 
   // Put session on the edge of overflowing it's recv window.
   session->session_recv_window_size_ = 1;
 
   // Read response headers & body. Body overflows the session window, and a
   // goaway is written.
-  data.RunFor(3);
-  base::MessageLoop::current()->RunUntilIdle();
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(ERR_SPDY_FLOW_CONTROL_ERROR, delegate.WaitForClose());
-  EXPECT_TRUE(session == NULL);
+  EXPECT_FALSE(session);
 }
 
 TEST_P(SpdySessionTest, SplitHeaders) {
@@ -4832,37 +4745,37 @@
   scoped_ptr<SpdyFrame> settings_frame(
       spdy_util_.ConstructSpdySettings(new_settings));
   scoped_ptr<SpdyFrame> pushed(spdy_util_.ConstructSpdyPush(
-      NULL, 0, 2, 1, "http://www.example.org/a.dat"));
+      nullptr, 0, 2, 1, "http://www.example.org/a.dat"));
   MockRead reads[] = {
-      CreateMockRead(*settings_frame), CreateMockRead(*pushed, 3),
-      MockRead(ASYNC, 0, 4),
+      CreateMockRead(*settings_frame, 0),
+      MockRead(ASYNC, ERR_IO_PENDING, 3),
+      CreateMockRead(*pushed, 4),
+      MockRead(ASYNC, ERR_IO_PENDING, 5),
+      MockRead(ASYNC, 0, 6),
   };
 
   scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
   MockWrite writes[] = {
       CreateMockWrite(*settings_ack, 1), CreateMockWrite(*req, 2),
   };
 
-  DeterministicSocketData data(
-      reads, arraysize(reads), writes, arraysize(writes));
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
 
   // Read the settings frame.
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
 
   GURL url1(kDefaultURL);
   base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
       SPDY_REQUEST_RESPONSE_STREAM, session, url1, LOWEST, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream1->stream_id());
   test::StreamDelegateDoNothing delegate1(spdy_stream1);
   spdy_stream1->SetDelegate(&delegate1);
@@ -4879,7 +4792,7 @@
 
   // Run until 1st stream is activated.
   EXPECT_EQ(0u, delegate1.stream_id());
-  data.RunFor(2);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, delegate1.stream_id());
   EXPECT_EQ(1u, session->num_active_streams());
   EXPECT_EQ(0u, session->num_created_streams());
@@ -4887,7 +4800,8 @@
   EXPECT_EQ(0u, session->num_active_pushed_streams());
 
   // Run until pushed stream is created.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(2u, session->num_active_streams());
   EXPECT_EQ(0u, session->num_created_streams());
   EXPECT_EQ(1u, session->num_pushed_streams());
@@ -4898,41 +4812,44 @@
   // create streams on the client.
   base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously(
       SPDY_REQUEST_RESPONSE_STREAM, session, url1, LOWEST, BoundNetLog());
-  EXPECT_TRUE(spdy_stream2.get() != NULL);
+  EXPECT_TRUE(spdy_stream2);
   EXPECT_EQ(2u, session->num_active_streams());
   EXPECT_EQ(1u, session->num_created_streams());
   EXPECT_EQ(1u, session->num_pushed_streams());
   EXPECT_EQ(1u, session->num_active_pushed_streams());
 
   // Read EOF.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 TEST_P(SpdySessionTest, RejectPushedStreamExceedingConcurrencyLimit) {
   scoped_ptr<SpdyFrame> push_a(spdy_util_.ConstructSpdyPush(
-      NULL, 0, 2, 1, "http://www.example.org/a.dat"));
+      nullptr, 0, 2, 1, "http://www.example.org/a.dat"));
   scoped_ptr<SpdyFrame> push_b(spdy_util_.ConstructSpdyPush(
-      NULL, 0, 4, 1, "http://www.example.org/b.dat"));
+      nullptr, 0, 4, 1, "http://www.example.org/b.dat"));
   MockRead reads[] = {
-      CreateMockRead(*push_a, 1), CreateMockRead(*push_b, 2),
-      MockRead(ASYNC, 0, 4),
+      MockRead(ASYNC, ERR_IO_PENDING, 1),
+      CreateMockRead(*push_a, 2),
+      MockRead(ASYNC, ERR_IO_PENDING, 3),
+      CreateMockRead(*push_b, 4),
+      MockRead(ASYNC, ERR_IO_PENDING, 6),
+      MockRead(ASYNC, 0, 7),
   };
 
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(4, RST_STREAM_REFUSED_STREAM));
   MockWrite writes[] = {
-      CreateMockWrite(*req, 0), CreateMockWrite(*rst, 3),
+      CreateMockWrite(*req, 0), CreateMockWrite(*rst, 5),
   };
 
-  DeterministicSocketData data(
-      reads, arraysize(reads), writes, arraysize(writes));
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -4941,7 +4858,7 @@
   GURL url1(kDefaultURL);
   base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
       SPDY_REQUEST_RESPONSE_STREAM, session, url1, LOWEST, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream1->stream_id());
   test::StreamDelegateDoNothing delegate1(spdy_stream1);
   spdy_stream1->SetDelegate(&delegate1);
@@ -4958,7 +4875,7 @@
 
   // Run until 1st stream is activated.
   EXPECT_EQ(0u, delegate1.stream_id());
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, delegate1.stream_id());
   EXPECT_EQ(1u, session->num_active_streams());
   EXPECT_EQ(0u, session->num_created_streams());
@@ -4966,21 +4883,25 @@
   EXPECT_EQ(0u, session->num_active_pushed_streams());
 
   // Run until pushed stream is created.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(2u, session->num_active_streams());
   EXPECT_EQ(0u, session->num_created_streams());
   EXPECT_EQ(1u, session->num_pushed_streams());
   EXPECT_EQ(1u, session->num_active_pushed_streams());
 
   // Reset incoming pushed stream.
-  data.RunFor(2);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(2u, session->num_active_streams());
   EXPECT_EQ(0u, session->num_created_streams());
   EXPECT_EQ(1u, session->num_pushed_streams());
   EXPECT_EQ(1u, session->num_active_pushed_streams());
 
   // Read EOF.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 TEST_P(SpdySessionTest, IgnoreReservedRemoteStreamsCount) {
@@ -4989,34 +4910,37 @@
     return;
 
   scoped_ptr<SpdyFrame> push_a(spdy_util_.ConstructSpdyPush(
-      NULL, 0, 2, 1, "http://www.example.org/a.dat"));
+      nullptr, 0, 2, 1, "http://www.example.org/a.dat"));
   scoped_ptr<SpdyHeaderBlock> push_headers(new SpdyHeaderBlock);
   spdy_util_.AddUrlToHeaderBlock("http://www.example.org/b.dat",
                                  push_headers.get());
   scoped_ptr<SpdyFrame> push_b(
       spdy_util_.ConstructInitialSpdyPushFrame(push_headers.Pass(), 4, 1));
   scoped_ptr<SpdyFrame> headers_b(
-      spdy_util_.ConstructSpdyPushHeaders(4, NULL, 0));
+      spdy_util_.ConstructSpdyPushHeaders(4, nullptr, 0));
   MockRead reads[] = {
-      CreateMockRead(*push_a, 1), CreateMockRead(*push_b, 2),
-      CreateMockRead(*headers_b, 3), MockRead(ASYNC, 0, 5),
+      MockRead(ASYNC, ERR_IO_PENDING, 1),
+      CreateMockRead(*push_a, 2),
+      MockRead(ASYNC, ERR_IO_PENDING, 3),
+      CreateMockRead(*push_b, 4),
+      MockRead(ASYNC, ERR_IO_PENDING, 5),
+      CreateMockRead(*headers_b, 6),
+      MockRead(ASYNC, ERR_IO_PENDING, 8),
+      MockRead(ASYNC, 0, 9),
   };
 
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(4, RST_STREAM_REFUSED_STREAM));
   MockWrite writes[] = {
-      CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
+      CreateMockWrite(*req, 0), CreateMockWrite(*rst, 7),
   };
 
-  DeterministicSocketData data(
-      reads, arraysize(reads), writes, arraysize(writes));
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -5025,7 +4949,7 @@
   GURL url1(kDefaultURL);
   base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
       SPDY_REQUEST_RESPONSE_STREAM, session, url1, LOWEST, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream1->stream_id());
   test::StreamDelegateDoNothing delegate1(spdy_stream1);
   spdy_stream1->SetDelegate(&delegate1);
@@ -5042,7 +4966,7 @@
 
   // Run until 1st stream is activated.
   EXPECT_EQ(0u, delegate1.stream_id());
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, delegate1.stream_id());
   EXPECT_EQ(1u, session->num_active_streams());
   EXPECT_EQ(0u, session->num_created_streams());
@@ -5050,14 +4974,16 @@
   EXPECT_EQ(0u, session->num_active_pushed_streams());
 
   // Run until pushed stream is created.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(2u, session->num_active_streams());
   EXPECT_EQ(0u, session->num_created_streams());
   EXPECT_EQ(1u, session->num_pushed_streams());
   EXPECT_EQ(1u, session->num_active_pushed_streams());
 
   // Accept promised stream. It should not count towards pushed stream limit.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(3u, session->num_active_streams());
   EXPECT_EQ(0u, session->num_created_streams());
   EXPECT_EQ(2u, session->num_pushed_streams());
@@ -5065,14 +4991,17 @@
 
   // Reset last pushed stream upon headers reception as it is going to be 2nd,
   // while we accept only one.
-  data.RunFor(2);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(2u, session->num_active_streams());
   EXPECT_EQ(0u, session->num_created_streams());
   EXPECT_EQ(1u, session->num_pushed_streams());
   EXPECT_EQ(1u, session->num_active_pushed_streams());
 
   // Read EOF.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(session);
 }
 
 TEST_P(SpdySessionTest, CancelReservedStreamOnHeadersReceived) {
@@ -5086,27 +5015,28 @@
   scoped_ptr<SpdyFrame> push_promise(
       spdy_util_.ConstructInitialSpdyPushFrame(push_headers.Pass(), 2, 1));
   scoped_ptr<SpdyFrame> headers_frame(
-      spdy_util_.ConstructSpdyPushHeaders(2, NULL, 0));
+      spdy_util_.ConstructSpdyPushHeaders(2, nullptr, 0));
   MockRead reads[] = {
-      CreateMockRead(*push_promise, 1), CreateMockRead(*headers_frame, 2),
-      MockRead(ASYNC, 0, 4),
+      MockRead(ASYNC, ERR_IO_PENDING, 1),
+      CreateMockRead(*push_promise, 2),
+      MockRead(ASYNC, ERR_IO_PENDING, 3),
+      CreateMockRead(*headers_frame, 4),
+      MockRead(ASYNC, ERR_IO_PENDING, 6),
+      MockRead(ASYNC, 0, 7),
   };
 
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+      spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_CANCEL));
   MockWrite writes[] = {
-      CreateMockWrite(*req, 0), CreateMockWrite(*rst, 3),
+      CreateMockWrite(*req, 0), CreateMockWrite(*rst, 5),
   };
 
-  DeterministicSocketData data(
-      reads, arraysize(reads), writes, arraysize(writes));
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
-  session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
 
-  CreateDeterministicNetworkSession();
+  CreateNetworkSession();
 
   base::WeakPtr<SpdySession> session =
       CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -5114,7 +5044,7 @@
   GURL url1(kDefaultURL);
   base::WeakPtr<SpdyStream> spdy_stream1 = CreateStreamSynchronously(
       SPDY_REQUEST_RESPONSE_STREAM, session, url1, LOWEST, BoundNetLog());
-  ASSERT_TRUE(spdy_stream1.get() != NULL);
+  ASSERT_TRUE(spdy_stream1.get() != nullptr);
   EXPECT_EQ(0u, spdy_stream1->stream_id());
   test::StreamDelegateDoNothing delegate1(spdy_stream1);
   spdy_stream1->SetDelegate(&delegate1);
@@ -5131,7 +5061,7 @@
 
   // Run until 1st stream is activated.
   EXPECT_EQ(0u, delegate1.stream_id());
-  data.RunFor(1);
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, delegate1.stream_id());
   EXPECT_EQ(1u, session->num_active_streams());
   EXPECT_EQ(0u, session->num_created_streams());
@@ -5139,7 +5069,8 @@
   EXPECT_EQ(0u, session->num_active_pushed_streams());
 
   // Run until pushed stream is created.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(2u, session->num_active_streams());
   EXPECT_EQ(0u, session->num_created_streams());
   EXPECT_EQ(1u, session->num_pushed_streams());
@@ -5149,20 +5080,24 @@
   int rv =
       session->GetPushStream(GURL(kPushedUrl), &pushed_stream, BoundNetLog());
   ASSERT_EQ(OK, rv);
-  ASSERT_TRUE(pushed_stream.get() != NULL);
+  ASSERT_TRUE(pushed_stream.get() != nullptr);
   test::StreamDelegateCloseOnHeaders delegate2(pushed_stream);
   pushed_stream->SetDelegate(&delegate2);
 
   // Receive headers for pushed stream. Delegate will cancel the stream, ensure
   // that all our counters are in consistent state.
-  data.RunFor(1);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1u, session->num_active_streams());
   EXPECT_EQ(0u, session->num_created_streams());
   EXPECT_EQ(0u, session->num_pushed_streams());
   EXPECT_EQ(0u, session->num_active_pushed_streams());
 
   // Read EOF.
-  data.RunFor(2);
+  data.CompleteRead();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(data.AllWriteDataConsumed());
+  EXPECT_TRUE(data.AllReadDataConsumed());
 }
 
 TEST_P(SpdySessionTest, RejectInvalidUnknownFrames) {
@@ -5172,10 +5107,7 @@
       MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
   };
 
-  StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
-
-  MockConnect connect_data(SYNCHRONOUS, OK);
-  data.set_connect_data(connect_data);
+  StaticSocketDataProvider data(reads, arraysize(reads), nullptr, 0);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   CreateNetworkSession();
diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc
index 55522c2a..0ffbeaf1 100644
--- a/net/spdy/spdy_stream.cc
+++ b/net/spdy/spdy_stream.cc
@@ -474,7 +474,7 @@
     // It should be valid for this to happen in the server push case.
     // We'll return received data when delegate gets attached to the stream.
     if (buffer) {
-      pending_recv_data_.push_back(buffer.release());
+      pending_recv_data_.push_back(buffer.Pass());
     } else {
       pending_recv_data_.push_back(NULL);
       // Note: we leave the stream open in the session until the stream
diff --git a/net/test/url_request/url_request_mock_http_job.cc b/net/test/url_request/url_request_mock_http_job.cc
index b7b4cdb..297d0ffb 100644
--- a/net/test/url_request/url_request_mock_http_job.cc
+++ b/net/test/url_request/url_request_mock_http_job.cc
@@ -91,13 +91,8 @@
 
 // For a given file |path| and |scheme|, return the URL served by the
 // URlRequestMockHTTPJob.
-GURL GetMockUrlForScheme(const base::FilePath& path,
-                         const std::string& scheme) {
-  std::string url = scheme + "://" + kMockHostname + "/";
-  std::string path_str = path.MaybeAsASCII();
-  DCHECK(!path_str.empty());  // We only expect ASCII paths in tests.
-  url.append(path_str);
-  return GURL(url);
+GURL GetMockUrlForScheme(const std::string& path, const std::string& scheme) {
+  return GURL(scheme + "://" + kMockHostname + "/" + path);
 }
 
 }  // namespace
@@ -115,16 +110,30 @@
 }
 
 // static
-GURL URLRequestMockHTTPJob::GetMockUrl(const base::FilePath& path) {
+GURL URLRequestMockHTTPJob::GetMockUrl(const std::string& path) {
   return GetMockUrlForScheme(path, "http");
 }
 
 // static
-GURL URLRequestMockHTTPJob::GetMockHttpsUrl(const base::FilePath& path) {
+GURL URLRequestMockHTTPJob::GetMockHttpsUrl(const std::string& path) {
   return GetMockUrlForScheme(path, "https");
 }
 
 // static
+GURL URLRequestMockHTTPJob::GetMockUrl(const base::FilePath& path) {
+  std::string path_str = path.MaybeAsASCII();
+  DCHECK(!path_str.empty());  // We only expect ASCII paths in tests.
+  return GetMockUrlForScheme(path_str, "http");
+}
+
+// static
+GURL URLRequestMockHTTPJob::GetMockHttpsUrl(const base::FilePath& path) {
+  std::string path_str = path.MaybeAsASCII();
+  DCHECK(!path_str.empty());  // We only expect ASCII paths in tests.
+  return GetMockUrlForScheme(path_str, "https");
+}
+
+// static
 scoped_ptr<URLRequestInterceptor> URLRequestMockHTTPJob::CreateInterceptor(
     const base::FilePath& base_path,
     const scoped_refptr<base::SequencedWorkerPool>& worker_pool) {
diff --git a/net/test/url_request/url_request_mock_http_job.h b/net/test/url_request/url_request_mock_http_job.h
index 06c3100..70839f52 100644
--- a/net/test/url_request/url_request_mock_http_job.h
+++ b/net/test/url_request/url_request_mock_http_job.h
@@ -48,6 +48,11 @@
 
   // Given the path to a file relative to the path passed to AddUrlHandler(),
   // construct a mock URL.
+  static GURL GetMockUrl(const std::string& path);
+  static GURL GetMockHttpsUrl(const std::string& path);
+
+  // Like above, but takes a FilePath. These methods are deprecated. Prefer the
+  // std::string versions. See http://crbug.com/496936.
   static GURL GetMockUrl(const base::FilePath& path);
   static GURL GetMockHttpsUrl(const base::FilePath& path);
 
diff --git a/net/third_party/nss/ssl.gyp b/net/third_party/nss/ssl.gyp
index 1d2bab8..c09f306 100644
--- a/net/third_party/nss/ssl.gyp
+++ b/net/third_party/nss/ssl.gyp
@@ -3,22 +3,6 @@
 # found in the LICENSE file.
 
 {
-  'conditions': [
-    [ 'os_posix == 1 and OS != "mac" and OS != "ios"', {
-      'conditions': [
-        ['sysroot!=""', {
-          'variables': {
-            'pkg-config': '../../../build/linux/pkg-config-wrapper "<(sysroot)" "<(target_arch)" "<(system_libdir)"',
-          },
-        }, {
-          'variables': {
-            'pkg-config': 'pkg-config'
-          },
-        }],
-      ],
-    }],
-  ],
-
   'targets': [
     {
       'target_name': 'libssl',
diff --git a/net/url_request/ftp_protocol_handler.cc b/net/url_request/ftp_protocol_handler.cc
index 56d15e6..418b6f6 100644
--- a/net/url_request/ftp_protocol_handler.cc
+++ b/net/url_request/ftp_protocol_handler.cc
@@ -27,9 +27,11 @@
 
 URLRequestJob* FtpProtocolHandler::MaybeCreateJob(
     URLRequest* request, NetworkDelegate* network_delegate) const {
-  int port = request->url().IntPort();
-  if (request->url().has_port() &&
-      !IsPortAllowedByFtp(port) && !IsPortAllowedByOverride(port)) {
+  DCHECK_EQ("ftp", request->url().scheme());
+
+  if (!IsPortAllowedForScheme(request->url().EffectiveIntPort(),
+                              request->url().scheme(),
+                              PORT_OVERRIDES_ALLOWED)) {
     return new URLRequestErrorJob(request, network_delegate, ERR_UNSAFE_PORT);
   }
 
diff --git a/net/url_request/url_request_ftp_job_unittest.cc b/net/url_request/url_request_ftp_job_unittest.cc
index c7cdecf1..4a8178d 100644
--- a/net/url_request/url_request_ftp_job_unittest.cc
+++ b/net/url_request/url_request_ftp_job_unittest.cc
@@ -234,16 +234,14 @@
 
   ~URLRequestFtpJobTest() override {
     // Clean up any remaining tasks that mess up unrelated tests.
-    base::RunLoop run_loop;
-    run_loop.RunUntilIdle();
+    base::RunLoop().RunUntilIdle();
   }
 
   void AddSocket(MockRead* reads, size_t reads_size,
                  MockWrite* writes, size_t writes_size) {
-    DeterministicSocketData* socket_data = new DeterministicSocketData(
-        reads, reads_size, writes, writes_size);
+    SequencedSocketData* socket_data =
+        new SequencedSocketData(reads, reads_size, writes, writes_size);
     socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
-    socket_data->StopAfter(reads_size + writes_size - 1);
     socket_factory_.AddSocketDataProvider(socket_data);
 
     socket_data_.push_back(socket_data);
@@ -251,13 +249,10 @@
 
   FtpTestURLRequestContext* request_context() { return &request_context_; }
   TestNetworkDelegate* network_delegate() { return &network_delegate_; }
-  DeterministicSocketData* socket_data(size_t index) {
-    return socket_data_[index];
-  }
 
  private:
-  ScopedVector<DeterministicSocketData> socket_data_;
-  DeterministicMockClientSocketFactory socket_factory_;
+  ScopedVector<SequencedSocketData> socket_data_;
+  MockClientSocketFactory socket_factory_;
   TestNetworkDelegate network_delegate_;
   MockFtpTransactionFactory ftp_transaction_factory_;
 
@@ -283,7 +278,9 @@
       GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate));
   url_request->Start();
   ASSERT_TRUE(url_request->is_pending());
-  socket_data(0)->RunFor(4);
+
+  // The TestDelegate will by default quit the message loop on completion.
+  base::RunLoop().Run();
 
   EXPECT_TRUE(url_request->status().is_success());
   EXPECT_TRUE(url_request->proxy_server().Equals(
@@ -333,7 +330,9 @@
       GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate));
   url_request->Start();
   ASSERT_TRUE(url_request->is_pending());
-  socket_data(0)->RunFor(5);
+
+  // The TestDelegate will by default quit the message loop on completion.
+  base::RunLoop().Run();
 
   EXPECT_TRUE(url_request->status().is_success());
   EXPECT_TRUE(url_request->proxy_server().Equals(
@@ -377,7 +376,9 @@
       GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate));
   url_request->Start();
   ASSERT_TRUE(url_request->is_pending());
-  socket_data(0)->RunFor(9);
+
+  // The TestDelegate will by default quit the message loop on completion.
+  base::RunLoop().Run();
 
   EXPECT_TRUE(url_request->status().is_success());
   EXPECT_EQ(1, network_delegate()->completed_requests());
@@ -408,7 +409,9 @@
       GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate));
   url_request->Start();
   ASSERT_TRUE(url_request->is_pending());
-  socket_data(0)->RunFor(5);
+
+  // The TestDelegate will by default quit the message loop on completion.
+  base::RunLoop().Run();
 
   EXPECT_TRUE(url_request->status().is_success());
   EXPECT_EQ(1, network_delegate()->completed_requests());
@@ -450,7 +453,9 @@
       GURL("ftp://ftp.example.com/"), DEFAULT_PRIORITY, &request_delegate));
   url_request->Start();
   ASSERT_TRUE(url_request->is_pending());
-  socket_data(0)->RunFor(9);
+
+  // The TestDelegate will by default quit the message loop on completion.
+  base::RunLoop().Run();
 
   EXPECT_TRUE(url_request->status().is_success());
   EXPECT_EQ(1, network_delegate()->completed_requests());
@@ -508,17 +513,32 @@
                       ASCIIToUTF16("passworddonotuse")));
 
   TestDelegate request_delegate;
-  request_delegate.set_credentials(
-      AuthCredentials(ASCIIToUTF16("proxyuser"), ASCIIToUTF16("proxypass")));
+  request_delegate.set_quit_on_auth_required(true);
   scoped_ptr<URLRequest> url_request(request_context()->CreateRequest(
       url, DEFAULT_PRIORITY, &request_delegate));
   url_request->Start();
   ASSERT_TRUE(url_request->is_pending());
-  socket_data(0)->RunFor(5);
 
-  request_delegate.set_credentials(
+  // Run until proxy auth is requested.
+  base::RunLoop().Run();
+
+  ASSERT_TRUE(request_delegate.auth_required_called());
+  EXPECT_EQ(0, network_delegate()->completed_requests());
+  EXPECT_EQ(0, network_delegate()->error_count());
+  url_request->SetAuth(
+      AuthCredentials(ASCIIToUTF16("proxyuser"), ASCIIToUTF16("proxypass")));
+
+  // Run until server auth is requested.
+  base::RunLoop().Run();
+
+  EXPECT_TRUE(url_request->status().is_success());
+  EXPECT_EQ(0, network_delegate()->completed_requests());
+  EXPECT_EQ(0, network_delegate()->error_count());
+  url_request->SetAuth(
       AuthCredentials(ASCIIToUTF16("myuser"), ASCIIToUTF16("mypass")));
-  socket_data(0)->RunFor(9);
+
+  // The TestDelegate will by default quit the message loop on completion.
+  base::RunLoop().Run();
 
   EXPECT_TRUE(url_request->status().is_success());
   EXPECT_EQ(1, network_delegate()->completed_requests());
@@ -548,7 +568,8 @@
   url_request->Start();
   ASSERT_TRUE(url_request->is_pending());
 
-  socket_data(0)->RunFor(5);
+  // The TestDelegate will by default quit the message loop on completion.
+  base::RunLoop().Run();
 
   EXPECT_TRUE(url_request->status().is_success());
   EXPECT_EQ(1, network_delegate()->completed_requests());
@@ -580,14 +601,8 @@
   url_request->Start();
   EXPECT_TRUE(url_request->is_pending());
 
-  base::MessageLoop::current()->RunUntilIdle();
-
-  EXPECT_TRUE(url_request->is_pending());
-  EXPECT_EQ(0, request_delegate.response_started_count());
-  EXPECT_EQ(0, network_delegate()->error_count());
-  ASSERT_TRUE(url_request->status().is_success());
-
-  socket_data(0)->RunFor(1);
+  // The TestDelegate will by default quit the message loop on completion.
+  base::RunLoop().Run();
 
   EXPECT_EQ(1, network_delegate()->completed_requests());
   EXPECT_EQ(1, network_delegate()->error_count());
@@ -623,7 +638,9 @@
                                        DEFAULT_PRIORITY, &request_delegate1));
   url_request1->Start();
   ASSERT_TRUE(url_request1->is_pending());
-  socket_data(0)->RunFor(4);
+
+  // The TestDelegate will by default quit the message loop on completion.
+  base::RunLoop().Run();
 
   EXPECT_TRUE(url_request1->status().is_success());
   EXPECT_TRUE(url_request1->proxy_server().Equals(
@@ -639,7 +656,9 @@
                                        DEFAULT_PRIORITY, &request_delegate2));
   url_request2->Start();
   ASSERT_TRUE(url_request2->is_pending());
-  socket_data(0)->RunFor(4);
+
+  // The TestDelegate will by default quit the message loop on completion.
+  base::RunLoop().Run();
 
   EXPECT_TRUE(url_request2->status().is_success());
   EXPECT_EQ(2, network_delegate()->completed_requests());
@@ -684,7 +703,9 @@
                                        DEFAULT_PRIORITY, &request_delegate1));
   url_request1->Start();
   ASSERT_TRUE(url_request1->is_pending());
-  socket_data(0)->RunFor(4);
+
+  // The TestDelegate will by default quit the message loop on completion.
+  base::RunLoop().Run();
 
   EXPECT_TRUE(url_request1->status().is_success());
   EXPECT_EQ(1, network_delegate()->completed_requests());
@@ -698,7 +719,9 @@
                                        DEFAULT_PRIORITY, &request_delegate2));
   url_request2->Start();
   ASSERT_TRUE(url_request2->is_pending());
-  socket_data(1)->RunFor(4);
+
+  // The TestDelegate will by default quit the message loop on completion.
+  base::RunLoop().Run();
 
   EXPECT_TRUE(url_request2->status().is_success());
   EXPECT_EQ(2, network_delegate()->completed_requests());
diff --git a/net/url_request/url_request_job_unittest.cc b/net/url_request/url_request_job_unittest.cc
index 080eda9..f9ea1fe 100644
--- a/net/url_request/url_request_job_unittest.cc
+++ b/net/url_request/url_request_job_unittest.cc
@@ -50,8 +50,10 @@
     "",
     TEST_MODE_NORMAL,
     &GZipServer,
+    nullptr,
     0,
-    OK
+    0,
+    OK,
 };
 
 const MockTransaction kRedirect_Transaction = {
@@ -67,9 +69,11 @@
     base::Time(),
     "hello",
     TEST_MODE_NORMAL,
-    NULL,
+    nullptr,
+    nullptr,
     0,
-    OK
+    0,
+    OK,
 };
 
 }  // namespace
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc
index ef99e99..9ed2227 100644
--- a/net/url_request/url_request_test_util.cc
+++ b/net/url_request/url_request_test_util.cc
@@ -162,6 +162,7 @@
       cancel_in_rd_pending_(false),
       quit_on_complete_(true),
       quit_on_redirect_(false),
+      quit_on_auth_required_(false),
       quit_on_before_network_start_(false),
       allow_certificate_errors_(false),
       response_started_count_(0),
@@ -214,6 +215,11 @@
 void TestDelegate::OnAuthRequired(URLRequest* request,
                                   AuthChallengeInfo* auth_info) {
   auth_required_ = true;
+  if (quit_on_auth_required_) {
+    base::MessageLoop::current()->PostTask(FROM_HERE,
+                                           base::MessageLoop::QuitClosure());
+    return;
+  }
   if (!credentials_.Empty()) {
     request->SetAuth(credentials_);
   } else {
diff --git a/net/url_request/url_request_test_util.h b/net/url_request/url_request_test_util.h
index 2b965533..585aca9 100644
--- a/net/url_request/url_request_test_util.h
+++ b/net/url_request/url_request_test_util.h
@@ -134,11 +134,16 @@
   void set_cancel_in_received_data_pending(bool val) {
     cancel_in_rd_pending_ = val;
   }
+
   void set_quit_on_complete(bool val) { quit_on_complete_ = val; }
   void set_quit_on_redirect(bool val) { quit_on_redirect_ = val; }
+  // Enables quitting the message loop in response to auth requests, as opposed
+  // to returning credentials or cancelling the request.
+  void set_quit_on_auth_required(bool val) { quit_on_auth_required_ = val; }
   void set_quit_on_network_start(bool val) {
     quit_on_before_network_start_ = val;
   }
+
   void set_allow_certificate_errors(bool val) {
     allow_certificate_errors_ = val;
   }
@@ -197,6 +202,7 @@
   bool cancel_in_rd_pending_;
   bool quit_on_complete_;
   bool quit_on_redirect_;
+  bool quit_on_auth_required_;
   bool quit_on_before_network_start_;
   bool allow_certificate_errors_;
   AuthCredentials credentials_;
diff --git a/net/websockets/websocket_handshake_stream_create_helper_test.cc b/net/websockets/websocket_handshake_stream_create_helper_test.cc
index a269655b..458ea44 100644
--- a/net/websockets/websocket_handshake_stream_create_helper_test.cc
+++ b/net/websockets/websocket_handshake_stream_create_helper_test.cc
@@ -49,7 +49,7 @@
   }
 
  private:
-  WebSocketDeterministicMockClientSocketFactoryMaker socket_factory_maker_;
+  WebSocketMockClientSocketFactoryMaker socket_factory_maker_;
   MockTransportClientSocketPool pool_;
 
   DISALLOW_COPY_AND_ASSIGN(MockClientSocketHandleFactory);
diff --git a/net/websockets/websocket_stream_test.cc b/net/websockets/websocket_stream_test.cc
index 644ef0ff4..aa3c043 100644
--- a/net/websockets/websocket_stream_test.cc
+++ b/net/websockets/websocket_stream_test.cc
@@ -38,27 +38,26 @@
 namespace net {
 namespace {
 
-// Simple builder for a DeterministicSocketData object to save repetitive code.
+// Simple builder for a SequencedSocketData object to save repetitive code.
 // It always sets the connect data to MockConnect(SYNCHRONOUS, OK), so it cannot
 // be used in tests where the connect fails. In practice, those tests never have
 // any read/write data and so can't benefit from it anyway.  The arrays are not
 // copied. It is up to the caller to ensure they stay in scope until the test
 // ends.
 template <size_t reads_count, size_t writes_count>
-scoped_ptr<DeterministicSocketData> BuildSocketData(
-    MockRead (&reads)[reads_count],
-    MockWrite (&writes)[writes_count]) {
-  scoped_ptr<DeterministicSocketData> socket_data(
-      new DeterministicSocketData(reads, reads_count, writes, writes_count));
+scoped_ptr<SequencedSocketData> BuildSocketData(
+    MockRead(&reads)[reads_count],
+    MockWrite(&writes)[writes_count]) {
+  scoped_ptr<SequencedSocketData> socket_data(
+      new SequencedSocketData(reads, reads_count, writes, writes_count));
   socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
-  socket_data->SetStop(reads_count + writes_count);
   return socket_data.Pass();
 }
 
-// Builder for a DeterministicSocketData that expects nothing. This does not
+// Builder for a SequencedSocketData that expects nothing. This does not
 // set the connect data, so the calling code must do that explicitly.
-scoped_ptr<DeterministicSocketData> BuildNullSocketData() {
-  return make_scoped_ptr(new DeterministicSocketData(NULL, 0, NULL, 0));
+scoped_ptr<SequencedSocketData> BuildNullSocketData() {
+  return make_scoped_ptr(new SequencedSocketData(NULL, 0, NULL, 0));
 }
 
 class MockWeakTimer : public base::MockTimer,
@@ -115,14 +114,14 @@
       const std::string& socket_url,
       const std::vector<std::string>& sub_protocols,
       const std::string& origin,
-      scoped_ptr<DeterministicSocketData> socket_data,
+      scoped_ptr<SequencedSocketData> socket_data,
       scoped_ptr<base::Timer> timer = scoped_ptr<base::Timer>()) {
     AddRawExpectations(socket_data.Pass());
     CreateAndConnectStream(socket_url, sub_protocols, origin, timer.Pass());
   }
 
   // Add additional raw expectations for sockets created before the final one.
-  void AddRawExpectations(scoped_ptr<DeterministicSocketData> socket_data) {
+  void AddRawExpectations(scoped_ptr<SequencedSocketData> socket_data) {
     url_request_context_host_.AddRawExpectations(socket_data.Pass());
   }
 };
@@ -151,7 +150,7 @@
  public:
   CommonAuthTestHelper() : reads1_(), writes1_(), reads2_(), writes2_() {}
 
-  scoped_ptr<DeterministicSocketData> BuildSocketData1(
+  scoped_ptr<SequencedSocketData> BuildSocketData1(
       const std::string& response) {
     request1_ =
         WebSocketStandardRequest("/", "localhost", "http://localhost", "");
@@ -163,7 +162,7 @@
     return BuildSocketData(reads1_, writes1_);
   }
 
-  scoped_ptr<DeterministicSocketData> BuildSocketData2(
+  scoped_ptr<SequencedSocketData> BuildSocketData2(
       const std::string& request,
       const std::string& response) {
     request2_ = request;
@@ -903,7 +902,7 @@
 
 // Connect failure must look just like negotiation failure.
 TEST_F(WebSocketStreamCreateTest, ConnectionFailure) {
-  scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData());
+  scoped_ptr<SequencedSocketData> socket_data(BuildNullSocketData());
   socket_data->set_connect_data(
       MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED));
   CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(),
@@ -918,7 +917,7 @@
 
 // Connect timeout must look just like any other failure.
 TEST_F(WebSocketStreamCreateTest, ConnectionTimeout) {
-  scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData());
+  scoped_ptr<SequencedSocketData> socket_data(BuildNullSocketData());
   socket_data->set_connect_data(
       MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT));
   CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(),
@@ -931,7 +930,7 @@
 
 // The server doesn't respond to the opening handshake.
 TEST_F(WebSocketStreamCreateTest, HandshakeTimeout) {
-  scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData());
+  scoped_ptr<SequencedSocketData> socket_data(BuildNullSocketData());
   socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
   scoped_ptr<MockWeakTimer> timer(new MockWeakTimer(false, false));
   base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
@@ -973,7 +972,7 @@
 
 // When the connection fails the timer should be stopped.
 TEST_F(WebSocketStreamCreateTest, HandshakeTimerOnFailure) {
-  scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData());
+  scoped_ptr<SequencedSocketData> socket_data(BuildNullSocketData());
   socket_data->set_connect_data(
       MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED));
   scoped_ptr<MockWeakTimer> timer(new MockWeakTimer(false, false));
@@ -996,7 +995,7 @@
 
 // Cancellation during connect works.
 TEST_F(WebSocketStreamCreateTest, CancellationDuringConnect) {
-  scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData());
+  scoped_ptr<SequencedSocketData> socket_data(BuildNullSocketData());
   socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
   CreateAndConnectRawExpectations("ws://localhost/",
                                   NoSubProtocols(),
@@ -1011,19 +1010,17 @@
 
 // Cancellation during write of the request headers works.
 TEST_F(WebSocketStreamCreateTest, CancellationDuringWrite) {
-  // We seem to need at least two operations in order to use SetStop().
-  MockWrite writes[] = {MockWrite(ASYNC, 0, "GET / HTTP/"),
-                        MockWrite(ASYNC, 1, "1.1\r\n")};
-  // We keep a copy of the pointer so that we can call RunFor() on it later.
-  DeterministicSocketData* socket_data(
-      new DeterministicSocketData(NULL, 0, writes, arraysize(writes)));
+  // First write never completes.
+  MockWrite writes[] = {MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 0)};
+  SequencedSocketData* socket_data(
+      new SequencedSocketData(NULL, 0, writes, arraysize(writes)));
   socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
-  socket_data->SetStop(1);
   CreateAndConnectRawExpectations("ws://localhost/",
                                   NoSubProtocols(),
                                   "http://localhost",
                                   make_scoped_ptr(socket_data));
-  socket_data->Run();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(socket_data->AllWriteDataConsumed());
   stream_request_.reset();
   // WaitUntilConnectDone doesn't work in this case.
   base::RunLoop().RunUntilIdle();
@@ -1039,17 +1036,16 @@
       WebSocketStandardRequest("/", "localhost", "http://localhost", "");
   MockWrite writes[] = {MockWrite(ASYNC, 0, request.c_str())};
   MockRead reads[] = {
-    MockRead(ASYNC, 1, "HTTP/1.1 101 Switching Protocols\r\nUpgr"),
+      MockRead(SYNCHRONOUS, ERR_IO_PENDING, 1),
   };
-  scoped_ptr<DeterministicSocketData> socket_data(
-      BuildSocketData(reads, writes));
-  socket_data->SetStop(1);
-  DeterministicSocketData* socket_data_raw_ptr = socket_data.get();
+  scoped_ptr<SequencedSocketData> socket_data(BuildSocketData(reads, writes));
+  SequencedSocketData* socket_data_raw_ptr = socket_data.get();
   CreateAndConnectRawExpectations("ws://localhost/",
                                   NoSubProtocols(),
                                   "http://localhost",
                                   socket_data.Pass());
-  socket_data_raw_ptr->Run();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(socket_data_raw_ptr->AllReadDataConsumed());
   stream_request_.reset();
   // WaitUntilConnectDone doesn't work in this case.
   base::RunLoop().RunUntilIdle();
@@ -1085,14 +1081,14 @@
       WebSocketStandardRequest("/", "localhost", "http://localhost", "");
   MockWrite writes[] = {MockWrite(ASYNC, request.data(), request.size(), 0)};
   MockRead reads[] = {MockRead(ASYNC, 0, 1)};
-  scoped_ptr<DeterministicSocketData> socket_data(
-      BuildSocketData(reads, writes));
-  DeterministicSocketData* socket_data_raw_ptr = socket_data.get();
+  scoped_ptr<SequencedSocketData> socket_data(BuildSocketData(reads, writes));
+  SequencedSocketData* socket_data_raw_ptr = socket_data.get();
   CreateAndConnectRawExpectations("ws://localhost/",
                                   NoSubProtocols(),
                                   "http://localhost",
                                   socket_data.Pass());
-  socket_data_raw_ptr->RunFor(2);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(socket_data_raw_ptr->AllReadDataConsumed());
   EXPECT_TRUE(has_failed());
   EXPECT_FALSE(stream_);
   EXPECT_FALSE(response_info_);
@@ -1106,7 +1102,7 @@
   ssl_data_[0]->cert =
       ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
   ASSERT_TRUE(ssl_data_[0]->cert.get());
-  scoped_ptr<DeterministicSocketData> raw_socket_data(BuildNullSocketData());
+  scoped_ptr<SequencedSocketData> raw_socket_data(BuildNullSocketData());
   CreateAndConnectRawExpectations("wss://localhost/",
                                   NoSubProtocols(),
                                   "http://localhost",
@@ -1279,8 +1275,7 @@
       MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED, 2),
   };
   MockWrite writes[] = {MockWrite(SYNCHRONOUS, 0, request.c_str())};
-  scoped_ptr<DeterministicSocketData> socket_data(
-      BuildSocketData(reads, writes));
+  scoped_ptr<SequencedSocketData> socket_data(BuildSocketData(reads, writes));
   socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
   CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(),
                                   "http://localhost", socket_data.Pass());
@@ -1305,8 +1300,7 @@
 
   MockRead reads[] = {MockRead(SYNCHRONOUS, 1, kProxyResponse)};
   MockWrite writes[] = {MockWrite(SYNCHRONOUS, 0, kConnectRequest)};
-  scoped_ptr<DeterministicSocketData> socket_data(
-      BuildSocketData(reads, writes));
+  scoped_ptr<SequencedSocketData> socket_data(BuildSocketData(reads, writes));
   url_request_context_host_.SetProxyConfig("https=proxy:8000");
   CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(),
                                   "http://localhost", socket_data.Pass());
diff --git a/net/websockets/websocket_test_util.cc b/net/websockets/websocket_test_util.cc
index 00cf68e5..5396020 100644
--- a/net/websockets/websocket_test_util.cc
+++ b/net/websockets/websocket_test_util.cc
@@ -80,29 +80,29 @@
       extra_headers.c_str());
 }
 
-struct WebSocketDeterministicMockClientSocketFactoryMaker::Detail {
+struct WebSocketMockClientSocketFactoryMaker::Detail {
   std::string expect_written;
   std::string return_to_read;
   std::vector<MockRead> reads;
   MockWrite write;
-  ScopedVector<DeterministicSocketData> socket_data_vector;
+  ScopedVector<SequencedSocketData> socket_data_vector;
   ScopedVector<SSLSocketDataProvider> ssl_socket_data_vector;
-  DeterministicMockClientSocketFactory factory;
+  MockClientSocketFactory factory;
 };
 
-WebSocketDeterministicMockClientSocketFactoryMaker::
-    WebSocketDeterministicMockClientSocketFactoryMaker()
-    : detail_(new Detail) {}
+WebSocketMockClientSocketFactoryMaker::WebSocketMockClientSocketFactoryMaker()
+    : detail_(new Detail) {
+}
 
-WebSocketDeterministicMockClientSocketFactoryMaker::
-    ~WebSocketDeterministicMockClientSocketFactoryMaker() {}
+WebSocketMockClientSocketFactoryMaker::
+    ~WebSocketMockClientSocketFactoryMaker() {
+}
 
-DeterministicMockClientSocketFactory*
-WebSocketDeterministicMockClientSocketFactoryMaker::factory() {
+MockClientSocketFactory* WebSocketMockClientSocketFactoryMaker::factory() {
   return &detail_->factory;
 }
 
-void WebSocketDeterministicMockClientSocketFactoryMaker::SetExpectations(
+void WebSocketMockClientSocketFactoryMaker::SetExpectations(
     const std::string& expect_written,
     const std::string& return_to_read) {
   const size_t kHttpStreamParserBufferSize = 4096;
@@ -124,24 +124,20 @@
                           kHttpStreamParserBufferSize),
                  sequence++));
   }
-  scoped_ptr<DeterministicSocketData> socket_data(
-      new DeterministicSocketData(vector_as_array(&detail_->reads),
-                                  detail_->reads.size(),
-                                  &detail_->write,
-                                  1));
+  scoped_ptr<SequencedSocketData> socket_data(
+      new SequencedSocketData(vector_as_array(&detail_->reads),
+                              detail_->reads.size(), &detail_->write, 1));
   socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
-  socket_data->SetStop(sequence);
   AddRawExpectations(socket_data.Pass());
 }
 
-void WebSocketDeterministicMockClientSocketFactoryMaker::AddRawExpectations(
-    scoped_ptr<DeterministicSocketData> socket_data) {
+void WebSocketMockClientSocketFactoryMaker::AddRawExpectations(
+    scoped_ptr<SequencedSocketData> socket_data) {
   detail_->factory.AddSocketDataProvider(socket_data.get());
   detail_->socket_data_vector.push_back(socket_data.Pass());
 }
 
-void
-WebSocketDeterministicMockClientSocketFactoryMaker::AddSSLSocketDataProvider(
+void WebSocketMockClientSocketFactoryMaker::AddSSLSocketDataProvider(
     scoped_ptr<SSLSocketDataProvider> ssl_socket_data) {
   detail_->factory.AddSSLSocketDataProvider(ssl_socket_data.get());
   detail_->ssl_socket_data_vector.push_back(ssl_socket_data.Pass());
@@ -155,7 +151,7 @@
 WebSocketTestURLRequestContextHost::~WebSocketTestURLRequestContextHost() {}
 
 void WebSocketTestURLRequestContextHost::AddRawExpectations(
-    scoped_ptr<DeterministicSocketData> socket_data) {
+    scoped_ptr<SequencedSocketData> socket_data) {
   maker_.AddRawExpectations(socket_data.Pass());
 }
 
diff --git a/net/websockets/websocket_test_util.h b/net/websockets/websocket_test_util.h
index a433ca9a..5b909e2 100644
--- a/net/websockets/websocket_test_util.h
+++ b/net/websockets/websocket_test_util.h
@@ -25,11 +25,11 @@
 namespace net {
 
 class BoundNetLog;
-class DeterministicMockClientSocketFactory;
-class DeterministicSocketData;
+class MockClientSocketFactory;
 class ProxyService;
-class URLRequestContext;
+class SequencedSocketData;
 struct SSLSocketDataProvider;
+class URLRequestContext;
 
 class LinearCongruentialGenerator {
  public:
@@ -62,12 +62,12 @@
 // key. Each header in |extra_headers| must be terminated with "\r\n".
 std::string WebSocketStandardResponse(const std::string& extra_headers);
 
-// This class provides a convenient way to construct a
-// DeterministicMockClientSocketFactory for WebSocket tests.
-class WebSocketDeterministicMockClientSocketFactoryMaker {
+// This class provides a convenient way to construct a MockClientSocketFactory
+// for WebSocket tests.
+class WebSocketMockClientSocketFactoryMaker {
  public:
-  WebSocketDeterministicMockClientSocketFactoryMaker();
-  ~WebSocketDeterministicMockClientSocketFactoryMaker();
+  WebSocketMockClientSocketFactoryMaker();
+  ~WebSocketMockClientSocketFactoryMaker();
 
   // Tell the factory to create a socket which expects |expect_written| to be
   // written, and responds with |return_to_read|. The test will fail if the
@@ -80,7 +80,7 @@
 
   // A low-level interface to permit arbitrary expectations to be added. The
   // mock sockets will be created in the same order that they were added.
-  void AddRawExpectations(scoped_ptr<DeterministicSocketData> socket_data);
+  void AddRawExpectations(scoped_ptr<SequencedSocketData> socket_data);
 
   // Allow an SSL socket data provider to be added. You must also supply a mock
   // transport socket for it to use. If the mock SSL handshake fails then the
@@ -91,13 +91,13 @@
       scoped_ptr<SSLSocketDataProvider> ssl_socket_data);
 
   // Call to get a pointer to the factory, which remains owned by this object.
-  DeterministicMockClientSocketFactory* factory();
+  MockClientSocketFactory* factory();
 
  private:
   struct Detail;
   scoped_ptr<Detail> detail_;
 
-  DISALLOW_COPY_AND_ASSIGN(WebSocketDeterministicMockClientSocketFactoryMaker);
+  DISALLOW_COPY_AND_ASSIGN(WebSocketMockClientSocketFactoryMaker);
 };
 
 // This class encapsulates the details of creating a
@@ -113,7 +113,7 @@
     maker_.SetExpectations(expect_written, return_to_read);
   }
 
-  void AddRawExpectations(scoped_ptr<DeterministicSocketData> socket_data);
+  void AddRawExpectations(scoped_ptr<SequencedSocketData> socket_data);
 
   // Allow an SSL socket data provider to be added.
   void AddSSLSocketDataProvider(
@@ -130,7 +130,7 @@
   TestURLRequestContext* GetURLRequestContext();
 
  private:
-  WebSocketDeterministicMockClientSocketFactoryMaker maker_;
+  WebSocketMockClientSocketFactoryMaker maker_;
   TestURLRequestContext url_request_context_;
   TestNetworkDelegate network_delegate_;
   scoped_ptr<ProxyService> proxy_service_;
diff --git a/ppapi/proxy/ppapi_proxy_test.cc b/ppapi/proxy/ppapi_proxy_test.cc
index 825cf7c..c7c3a92 100644
--- a/ppapi/proxy/ppapi_proxy_test.cc
+++ b/ppapi/proxy/ppapi_proxy_test.cc
@@ -260,14 +260,8 @@
 base::SharedMemoryHandle
 PluginProxyTestHarness::PluginDelegateMock::ShareSharedMemoryHandleWithRemote(
     const base::SharedMemoryHandle& handle,
-    base::ProcessId remote_pid) {
-#if defined(OS_POSIX)
-  return ShareHandleWithRemote(handle.fd, remote_pid, false);
-#elif defined(OS_WIN)
-  return ShareHandleWithRemote(handle, remote_pid, false);
-#else
-#error Not implemented.
-#endif
+    base::ProcessId /* remote_pid */) {
+  return base::SharedMemory::DuplicateHandle(handle);
 }
 
 std::set<PP_Instance>*
@@ -506,14 +500,8 @@
 base::SharedMemoryHandle
 HostProxyTestHarness::DelegateMock::ShareSharedMemoryHandleWithRemote(
     const base::SharedMemoryHandle& handle,
-    base::ProcessId remote_pid) {
-#if defined(OS_POSIX)
-  return ShareHandleWithRemote(handle.fd, remote_pid, false);
-#elif defined(OS_WIN)
-  return ShareHandleWithRemote(handle, remote_pid, false);
-#else
-#error Not implemented.
-#endif
+    base::ProcessId /*remote_pid*/) {
+  return base::SharedMemory::DuplicateHandle(handle);
 }
 
 // HostProxyTest ---------------------------------------------------------------
diff --git a/ppapi/proxy/proxy_channel.cc b/ppapi/proxy/proxy_channel.cc
index 7e647553..2784e4b9 100644
--- a/ppapi/proxy/proxy_channel.cc
+++ b/ppapi/proxy/proxy_channel.cc
@@ -76,13 +76,11 @@
 
 base::SharedMemoryHandle ProxyChannel::ShareSharedMemoryHandleWithRemote(
     const base::SharedMemoryHandle& handle) {
-#if defined(OS_POSIX)
-  return ShareHandleWithRemote(handle.fd, false);
-#elif defined(OS_WIN)
-  return ShareHandleWithRemote(handle, false);
-#else
-#error Not implemented.
-#endif
+  if (!channel_.get())
+    return base::SharedMemory::NULLHandle();
+
+  DCHECK(peer_pid_ != base::kNullProcessId);
+  return delegate_->ShareSharedMemoryHandleWithRemote(handle, peer_pid_);
 }
 
 bool ProxyChannel::Send(IPC::Message* msg) {
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc
index 3aff7d7..c32d31d 100644
--- a/remoting/client/plugin/chromoting_instance.cc
+++ b/remoting/client/plugin/chromoting_instance.cc
@@ -353,7 +353,7 @@
   } else if (method == "enableDebugRegion") {
     HandleEnableDebugRegion(*data);
   } else if (method == "enableTouchEvents") {
-    HandleEnableTouchEvents();
+    HandleEnableTouchEvents(*data);
   }
 }
 
@@ -985,8 +985,19 @@
   video_renderer_->EnableDebugDirtyRegion(enable);
 }
 
-void ChromotingInstance::HandleEnableTouchEvents() {
-  RequestInputEvents(PP_INPUTEVENT_CLASS_TOUCH);
+void ChromotingInstance::HandleEnableTouchEvents(
+    const base::DictionaryValue& data) {
+  bool enable = false;
+  if (!data.GetBoolean("enable", &enable)) {
+    LOG(ERROR) << "Invalid handleTouchEvents.";
+    return;
+  }
+
+  if (enable) {
+    RequestInputEvents(PP_INPUTEVENT_CLASS_TOUCH);
+  } else {
+    ClearInputEventRequest(PP_INPUTEVENT_CLASS_TOUCH);
+  }
 }
 
 void ChromotingInstance::Disconnect() {
diff --git a/remoting/client/plugin/chromoting_instance.h b/remoting/client/plugin/chromoting_instance.h
index c07a7e1..7f600bb1 100644
--- a/remoting/client/plugin/chromoting_instance.h
+++ b/remoting/client/plugin/chromoting_instance.h
@@ -196,7 +196,7 @@
   void HandleSendMouseInputWhenUnfocused();
   void HandleDelegateLargeCursors();
   void HandleEnableDebugRegion(const base::DictionaryValue& data);
-  void HandleEnableTouchEvents();
+  void HandleEnableTouchEvents(const base::DictionaryValue& data);
 
   void Disconnect();
 
diff --git a/remoting/host/basic_desktop_environment.cc b/remoting/host/basic_desktop_environment.cc
index e7132f6..6d9cc3c 100644
--- a/remoting/host/basic_desktop_environment.cc
+++ b/remoting/host/basic_desktop_environment.cc
@@ -16,6 +16,7 @@
 #include "remoting/host/gnubby_auth_handler.h"
 #include "remoting/host/input_injector.h"
 #include "remoting/host/screen_controls.h"
+#include "remoting/protocol/capability_names.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h"
 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
@@ -55,6 +56,9 @@
 }
 
 std::string BasicDesktopEnvironment::GetCapabilities() const {
+  if (supports_touch_events_)
+    return protocol::kTouchEventsCapability;
+
   return std::string();
 }
 
@@ -83,13 +87,15 @@
 BasicDesktopEnvironment::BasicDesktopEnvironment(
     scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
-    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
+    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+    bool supports_touch_events)
     : caller_task_runner_(caller_task_runner),
       input_task_runner_(input_task_runner),
       ui_task_runner_(ui_task_runner),
       desktop_capture_options_(
           new webrtc::DesktopCaptureOptions(
-              webrtc::DesktopCaptureOptions::CreateDefault())) {
+              webrtc::DesktopCaptureOptions::CreateDefault())),
+      supports_touch_events_(supports_touch_events) {
   DCHECK(caller_task_runner_->BelongsToCurrentThread());
 }
 
@@ -99,7 +105,8 @@
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
     : caller_task_runner_(caller_task_runner),
       input_task_runner_(input_task_runner),
-      ui_task_runner_(ui_task_runner) {
+      ui_task_runner_(ui_task_runner),
+      supports_touch_events_(false) {
 }
 
 BasicDesktopEnvironmentFactory::~BasicDesktopEnvironmentFactory() {
diff --git a/remoting/host/basic_desktop_environment.h b/remoting/host/basic_desktop_environment.h
index 6b6b8e25..a7c5613 100644
--- a/remoting/host/basic_desktop_environment.h
+++ b/remoting/host/basic_desktop_environment.h
@@ -46,7 +46,8 @@
   BasicDesktopEnvironment(
       scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
       scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
-      scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+      bool supports_touch_events);
 
   scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner() const {
     return caller_task_runner_;
@@ -82,6 +83,9 @@
   // find build errors.
   scoped_ptr<webrtc::DesktopCaptureOptions> desktop_capture_options_;
 
+  // True if the touch events capability should be offered.
+  const bool supports_touch_events_;
+
   DISALLOW_COPY_AND_ASSIGN(BasicDesktopEnvironment);
 };
 
@@ -97,6 +101,10 @@
   // DesktopEnvironmentFactory implementation.
   bool SupportsAudioCapture() const override;
 
+  void set_supports_touch_events(bool enable) {
+    supports_touch_events_ = enable;
+  }
+
  protected:
   scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner() const {
     return caller_task_runner_;
@@ -110,6 +118,8 @@
     return ui_task_runner_;
   }
 
+  bool supports_touch_events() const { return supports_touch_events_; }
+
  private:
   // Task runner on which methods of DesktopEnvironmentFactory interface should
   // be called.
@@ -121,6 +131,10 @@
   // Used to run UI code.
   scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
 
+  // True if the touch events capability should be offered by the
+  // DesktopEnvironment instances.
+  bool supports_touch_events_;
+
   DISALLOW_COPY_AND_ASSIGN(BasicDesktopEnvironmentFactory);
 };
 
diff --git a/remoting/host/desktop_session_proxy.cc b/remoting/host/desktop_session_proxy.cc
index f0ff52a..68d9f96 100644
--- a/remoting/host/desktop_session_proxy.cc
+++ b/remoting/host/desktop_session_proxy.cc
@@ -24,6 +24,7 @@
 #include "remoting/proto/audio.pb.h"
 #include "remoting/proto/control.pb.h"
 #include "remoting/proto/event.pb.h"
+#include "remoting/protocol/capability_names.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor.h"
@@ -34,8 +35,6 @@
 #endif  // defined(OS_WIN)
 
 const bool kReadOnly = true;
-const char kSendInitialResolution[] = "sendInitialResolution";
-const char kRateLimitResizeRequests[] = "rateLimitResizeRequests";
 
 namespace remoting {
 
@@ -109,7 +108,8 @@
     scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner,
     base::WeakPtr<ClientSessionControl> client_session_control,
     base::WeakPtr<DesktopSessionConnector> desktop_session_connector,
-    bool virtual_terminal)
+    bool virtual_terminal,
+    bool supports_touch_events)
     : audio_capture_task_runner_(audio_capture_task_runner),
       caller_task_runner_(caller_task_runner),
       io_task_runner_(io_task_runner),
@@ -118,7 +118,8 @@
       desktop_session_connector_(desktop_session_connector),
       pending_capture_frame_requests_(0),
       is_desktop_session_connected_(false),
-      virtual_terminal_(virtual_terminal) {
+      virtual_terminal_(virtual_terminal),
+      supports_touch_events_(supports_touch_events) {
   DCHECK(caller_task_runner_->BelongsToCurrentThread());
 }
 
@@ -152,10 +153,14 @@
 }
 
 std::string DesktopSessionProxy::GetCapabilities() const {
-  std::string result = kRateLimitResizeRequests;
+  std::string result = protocol::kRateLimitResizeRequests;
   // Ask the client to send its resolution unconditionally.
   if (virtual_terminal_)
-    result = result + " " + kSendInitialResolution;
+    result = result + " " + protocol::kSendInitialResolution;
+
+  if (supports_touch_events_)
+    result = result + " "  + protocol::kTouchEventsCapability;
+
   return result;
 }
 
@@ -166,7 +171,7 @@
   // sent its screen resolution (the 'sendInitialResolution' capability is
   // supported).
   if (virtual_terminal_ &&
-      HasCapability(capabilities, kSendInitialResolution)) {
+      HasCapability(capabilities, protocol::kSendInitialResolution)) {
     VLOG(1) << "Waiting for the client screen resolution.";
     return;
   }
diff --git a/remoting/host/desktop_session_proxy.h b/remoting/host/desktop_session_proxy.h
index f18caba3..bae2a80 100644
--- a/remoting/host/desktop_session_proxy.h
+++ b/remoting/host/desktop_session_proxy.h
@@ -75,7 +75,8 @@
       scoped_refptr<base::SingleThreadTaskRunner> video_capture_task_runner,
       base::WeakPtr<ClientSessionControl> client_session_control,
       base::WeakPtr<DesktopSessionConnector> desktop_session_connector,
-      bool virtual_terminal);
+      bool virtual_terminal,
+      bool supports_touch_events);
 
   // Mirrors DesktopEnvironment.
   scoped_ptr<AudioCapturer> CreateAudioCapturer();
@@ -227,6 +228,9 @@
 
   bool virtual_terminal_;
 
+  // True if touch events are supported by the desktop session.
+  bool supports_touch_events_;
+
   DISALLOW_COPY_AND_ASSIGN(DesktopSessionProxy);
 };
 
diff --git a/remoting/host/input_injector.h b/remoting/host/input_injector.h
index ec3078c..99a7ddee 100644
--- a/remoting/host/input_injector.h
+++ b/remoting/host/input_injector.h
@@ -28,6 +28,10 @@
       scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
 
+  // Returns true if the InputInjector returned by Create() supports
+  // InjectTouchEvent() on this platform.
+  static bool SupportsTouchEvents();
+
   // Initialises any objects needed to execute events.
   virtual void Start(
       scoped_ptr<protocol::ClipboardStub> client_clipboard) = 0;
diff --git a/remoting/host/input_injector_chromeos.cc b/remoting/host/input_injector_chromeos.cc
index cdf5b41..58afde0 100644
--- a/remoting/host/input_injector_chromeos.cc
+++ b/remoting/host/input_injector_chromeos.cc
@@ -42,17 +42,6 @@
   }
 }
 
-bool IsModifierKey(ui::DomCode dom_code) {
-  return dom_code == ui::DomCode::CONTROL_RIGHT ||
-         dom_code == ui::DomCode::CONTROL_LEFT ||
-         dom_code == ui::DomCode::SHIFT_RIGHT ||
-         dom_code == ui::DomCode::SHIFT_LEFT ||
-         dom_code == ui::DomCode::ALT_RIGHT ||
-         dom_code == ui::DomCode::ALT_LEFT ||
-         dom_code == ui::DomCode::OS_RIGHT ||
-         dom_code == ui::DomCode::OS_LEFT;
-}
-
 }  // namespace
 
 // This class is run exclusively on the UI thread of the browser process.
@@ -68,24 +57,17 @@
   void Start(scoped_ptr<protocol::ClipboardStub> client_clipboard);
 
  private:
-  void HandleAutoRepeat(ui::DomCode dom_code, bool pressed);
-
   scoped_ptr<ui::SystemInputInjector> delegate_;
-  ui::InputController* input_controller_;
   scoped_ptr<Clipboard> clipboard_;
 
   // Used to rotate the input coordinates appropriately based on the current
   // display rotation settings.
   scoped_ptr<PointTransformer> point_transformer_;
 
-  // Used by HandleAutoRepeat().
-  std::set<ui::DomCode> pressed_keys_;
-  bool saved_auto_repeat_enabled_;
-
   DISALLOW_COPY_AND_ASSIGN(Core);
 };
 
-InputInjectorChromeos::Core::Core() : saved_auto_repeat_enabled_(false) {
+InputInjectorChromeos::Core::Core() {
 }
 
 void InputInjectorChromeos::Core::InjectClipboardEvent(
@@ -102,43 +84,8 @@
 
   // Ignore events which can't be mapped.
   if (dom_code != ui::DomCode::NONE) {
-    HandleAutoRepeat(dom_code, event.pressed());
-    delegate_->InjectKeyPress(dom_code, event.pressed());
-  }
-}
-
-// Disables auto-repeat as long as keys are pressed to avoid duplicated
-// key-presses if network congestion delays the key-up event from the client.
-void InputInjectorChromeos::Core::HandleAutoRepeat(ui::DomCode dom_code,
-                                                   bool pressed) {
-  if (pressed) {
-    // Key is already held down, so lift the key up to ensure this repeated
-    // press takes effect.
-    // TODO(jamiewalch): Fix SystemInputInjector::InjectKeyPress so that this
-    // work-around is not needed (crbug.com/496420).
-    if (pressed_keys_.find(dom_code) != pressed_keys_.end()) {
-      // Ignore repeats for modifier keys.
-      if (IsModifierKey(dom_code))
-        return;
-      delegate_->InjectKeyPress(dom_code, false);
-    }
-
-    if (pressed_keys_.empty()) {
-      // Disable auto-repeat, if necessary, when any key is pressed.
-      saved_auto_repeat_enabled_ = input_controller_->IsAutoRepeatEnabled();
-      if (saved_auto_repeat_enabled_) {
-        input_controller_->SetAutoRepeatEnabled(false);
-      }
-    }
-    pressed_keys_.insert(dom_code);
-  } else {
-    pressed_keys_.erase(dom_code);
-    if (pressed_keys_.empty()) {
-      // Re-enable auto-repeat, if necessary, when all keys are released.
-      if (saved_auto_repeat_enabled_) {
-        input_controller_->SetAutoRepeatEnabled(true);
-      }
-    }
+    delegate_->InjectKeyPress(dom_code, event.pressed(),
+                              false /* enable_repeat */);
   }
 }
 
@@ -166,8 +113,6 @@
   ui::OzonePlatform* ozone_platform = ui::OzonePlatform::GetInstance();
   delegate_ = ozone_platform->CreateSystemInputInjector();
   DCHECK(delegate_);
-  input_controller_ = ozone_platform->GetInputController();
-  DCHECK(input_controller_);
 
   // Implemented by remoting::ClipboardAura.
   clipboard_ = Clipboard::Create();
@@ -229,4 +174,9 @@
   return make_scoped_ptr(new InputInjectorChromeos(ui_task_runner));
 }
 
+// static
+bool InputInjector::SupportsTouchEvents() {
+  return false;
+}
+
 }  // namespace remoting
diff --git a/remoting/host/input_injector_mac.cc b/remoting/host/input_injector_mac.cc
index b4885e3..5043e965 100644
--- a/remoting/host/input_injector_mac.cc
+++ b/remoting/host/input_injector_mac.cc
@@ -340,10 +340,16 @@
 
 }  // namespace
 
+// static
 scoped_ptr<InputInjector> InputInjector::Create(
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
   return make_scoped_ptr(new InputInjectorMac(main_task_runner));
 }
 
+// static
+bool InputInjector::SupportsTouchEvents() {
+  return false;
+}
+
 }  // namespace remoting
diff --git a/remoting/host/input_injector_win.cc b/remoting/host/input_injector_win.cc
index ed328d3..41972582 100644
--- a/remoting/host/input_injector_win.cc
+++ b/remoting/host/input_injector_win.cc
@@ -348,6 +348,7 @@
 
 }  // namespace
 
+// static
 scoped_ptr<InputInjector> InputInjector::Create(
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
@@ -355,4 +356,9 @@
       new InputInjectorWin(main_task_runner, ui_task_runner));
 }
 
+// static
+bool InputInjector::SupportsTouchEvents() {
+  return TouchInjectorWinDelegate::Create();
+}
+
 }  // namespace remoting
diff --git a/remoting/host/input_injector_x11.cc b/remoting/host/input_injector_x11.cc
index 70eeaf72..86a0432f 100644
--- a/remoting/host/input_injector_x11.cc
+++ b/remoting/host/input_injector_x11.cc
@@ -644,6 +644,7 @@
 
 }  // namespace
 
+// static
 scoped_ptr<InputInjector> InputInjector::Create(
     scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
@@ -654,4 +655,9 @@
   return injector.Pass();
 }
 
+// static
+bool InputInjector::SupportsTouchEvents() {
+  return false;
+}
+
 }  // namespace remoting
diff --git a/remoting/host/ipc_desktop_environment.cc b/remoting/host/ipc_desktop_environment.cc
index d7b2cb6..37bd89f 100644
--- a/remoting/host/ipc_desktop_environment.cc
+++ b/remoting/host/ipc_desktop_environment.cc
@@ -31,7 +31,8 @@
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
     base::WeakPtr<ClientSessionControl> client_session_control,
     base::WeakPtr<DesktopSessionConnector> desktop_session_connector,
-    bool virtual_terminal) {
+    bool virtual_terminal,
+    bool supports_touch_events) {
   DCHECK(caller_task_runner->BelongsToCurrentThread());
 
   desktop_session_proxy_ = new DesktopSessionProxy(audio_task_runner,
@@ -40,7 +41,8 @@
                                                    capture_task_runner,
                                                    client_session_control,
                                                    desktop_session_connector,
-                                                   virtual_terminal);
+                                                   virtual_terminal,
+                                                   supports_touch_events);
 }
 
 IpcDesktopEnvironment::~IpcDesktopEnvironment() {
@@ -94,7 +96,8 @@
       curtain_enabled_(false),
       daemon_channel_(daemon_channel),
       next_id_(0),
-      connector_factory_(this) {
+      connector_factory_(this),
+      supports_touch_events_(false) {
 }
 
 IpcDesktopEnvironmentFactory::~IpcDesktopEnvironmentFactory() {
@@ -111,7 +114,8 @@
                                 io_task_runner_,
                                 client_session_control,
                                 connector_factory_.GetWeakPtr(),
-                                curtain_enabled_));
+                                curtain_enabled_,
+                                supports_touch_events_));
 }
 
 void IpcDesktopEnvironmentFactory::SetEnableCurtaining(bool enable) {
diff --git a/remoting/host/ipc_desktop_environment.h b/remoting/host/ipc_desktop_environment.h
index b1dd8611..fd8a6667 100644
--- a/remoting/host/ipc_desktop_environment.h
+++ b/remoting/host/ipc_desktop_environment.h
@@ -45,7 +45,8 @@
       scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
       base::WeakPtr<ClientSessionControl> client_session_control,
       base::WeakPtr<DesktopSessionConnector> desktop_session_connector,
-      bool virtual_terminal);
+      bool virtual_terminal,
+      bool supports_touch_events);
   ~IpcDesktopEnvironment() override;
 
   // DesktopEnvironment implementation.
@@ -100,6 +101,11 @@
       IPC::PlatformFileForTransit desktop_pipe) override;
   void OnTerminalDisconnected(int terminal_id) override;
 
+  // Enables or disables touch events capability.
+  void set_supports_touch_events(bool enable) {
+    supports_touch_events_ = enable;
+  }
+
  private:
   // Used to run the audio capturer.
   scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner_;
@@ -132,6 +138,10 @@
   // Factory for weak pointers to DesktopSessionConnector interface.
   base::WeakPtrFactory<DesktopSessionConnector> connector_factory_;
 
+  // If true then the newly Create()ed desktop environments support touch
+  // events.
+  bool supports_touch_events_;
+
   DISALLOW_COPY_AND_ASSIGN(IpcDesktopEnvironmentFactory);
 };
 
diff --git a/remoting/host/ipc_desktop_environment_unittest.cc b/remoting/host/ipc_desktop_environment_unittest.cc
index 186574b..4c18dac 100644
--- a/remoting/host/ipc_desktop_environment_unittest.cc
+++ b/remoting/host/ipc_desktop_environment_unittest.cc
@@ -129,6 +129,7 @@
   ~IpcDesktopEnvironmentTest() override;
 
   void SetUp() override;
+  void TearDown() override;
 
   void ConnectTerminal(int terminal_id,
                        const ScreenResolution& resolution,
@@ -169,15 +170,14 @@
   // received.
   void OnDesktopAttached(IPC::PlatformFileForTransit desktop_pipe);
 
+  void RunMainLoopUntilDone();
+
   // The main message loop.
   base::MessageLoopForUI message_loop_;
 
   // Runs until |desktop_session_proxy_| is connected to the desktop.
   scoped_ptr<base::RunLoop> setup_run_loop_;
 
-  // Runs until there are references to |task_runner_|.
-  base::RunLoop main_run_loop_;
-
   scoped_refptr<AutoThreadTaskRunner> task_runner_;
   scoped_refptr<AutoThreadTaskRunner> io_task_runner_;
 
@@ -222,6 +222,10 @@
 
   MockClientSessionControl client_session_control_;
   base::WeakPtrFactory<ClientSessionControl> client_session_control_factory_;
+
+ private:
+  // Runs until there are references to |task_runner_|.
+  base::RunLoop main_run_loop_;
 };
 
 IpcDesktopEnvironmentTest::IpcDesktopEnvironmentTest()
@@ -302,6 +306,10 @@
   desktop_environment_->SetCapabilities(std::string());
 }
 
+void IpcDesktopEnvironmentTest::TearDown() {
+  RunMainLoopUntilDone();
+}
+
 void IpcDesktopEnvironmentTest::ConnectTerminal(
     int terminal_id,
     const ScreenResolution& resolution,
@@ -438,6 +446,12 @@
       terminal_id_, process_handle, desktop_pipe);
 }
 
+void IpcDesktopEnvironmentTest::RunMainLoopUntilDone() {
+  task_runner_ = nullptr;
+  io_task_runner_ = nullptr;
+  main_run_loop_.Run();
+}
+
 // Runs until the desktop is attached and exits immediately after that.
 TEST_F(IpcDesktopEnvironmentTest, Basic) {
   scoped_ptr<protocol::MockClipboardStub> clipboard_stub(
@@ -453,10 +467,51 @@
 
   // Stop the test.
   DeleteDesktopEnvironment();
+}
 
-  task_runner_ = nullptr;
-  io_task_runner_ = nullptr;
-  main_run_loop_.Run();
+// Check Capabilities.
+TEST_F(IpcDesktopEnvironmentTest, CapabilitiesNoTouch) {
+  scoped_ptr<protocol::MockClipboardStub> clipboard_stub(
+      new protocol::MockClipboardStub());
+  EXPECT_CALL(*clipboard_stub, InjectClipboardEvent(_))
+      .Times(0);
+
+  EXPECT_EQ("rateLimitResizeRequests", desktop_environment_->GetCapabilities());
+
+  // Start the input injector and screen capturer.
+  input_injector_->Start(clipboard_stub.Pass());
+
+  // Run the message loop until the desktop is attached.
+  setup_run_loop_->Run();
+
+  // Stop the test.
+  DeleteDesktopEnvironment();
+}
+
+// Check touchEvents capability is set when the desktop environment can
+// inject touch events.
+TEST_F(IpcDesktopEnvironmentTest, TouchEventsCapabilities) {
+  // Create an environment with multi touch enabled.
+  desktop_environment_factory_->set_supports_touch_events(true);
+  desktop_environment_ = desktop_environment_factory_->Create(
+      client_session_control_factory_.GetWeakPtr());
+
+  scoped_ptr<protocol::MockClipboardStub> clipboard_stub(
+      new protocol::MockClipboardStub());
+  EXPECT_CALL(*clipboard_stub, InjectClipboardEvent(_))
+      .Times(0);
+
+  EXPECT_EQ("rateLimitResizeRequests touchEvents",
+            desktop_environment_->GetCapabilities());
+
+  // Start the input injector and screen capturer.
+  input_injector_->Start(clipboard_stub.Pass());
+
+  // Run the message loop until the desktop is attached.
+  setup_run_loop_->Run();
+
+  // Stop the test.
+  DeleteDesktopEnvironment();
 }
 
 // Tests that the video capturer receives a frame over IPC.
@@ -482,10 +537,6 @@
 
   // Capture a single frame.
   video_capturer_->Capture(webrtc::DesktopRegion());
-
-  task_runner_ = nullptr;
-  io_task_runner_ = nullptr;
-  main_run_loop_.Run();
 }
 
 // Tests that attaching to a new desktop works.
@@ -510,10 +561,6 @@
 
   // Stop the test.
   DeleteDesktopEnvironment();
-
-  task_runner_ = nullptr;
-  io_task_runner_ = nullptr;
-  main_run_loop_.Run();
 }
 
 // Tests injection of clipboard events.
@@ -546,10 +593,6 @@
   event.set_mime_type(kMimeTypeTextUtf8);
   event.set_data("a");
   input_injector_->InjectClipboardEvent(event);
-
-  task_runner_ = nullptr;
-  io_task_runner_ = nullptr;
-  main_run_loop_.Run();
 }
 
 // Tests injection of key events.
@@ -577,10 +620,6 @@
   event.set_usb_keycode(0x070004);
   event.set_pressed(true);
   input_injector_->InjectKeyEvent(event);
-
-  task_runner_ = nullptr;
-  io_task_runner_ = nullptr;
-  main_run_loop_.Run();
 }
 
 // Tests injection of text events.
@@ -607,10 +646,6 @@
   protocol::TextEvent event;
   event.set_text("hello");
   input_injector_->InjectTextEvent(event);
-
-  task_runner_ = nullptr;
-  io_task_runner_ = nullptr;
-  main_run_loop_.Run();
 }
 
 // Tests injection of mouse events.
@@ -638,10 +673,6 @@
   event.set_x(0);
   event.set_y(0);
   input_injector_->InjectMouseEvent(event);
-
-  task_runner_ = nullptr;
-  io_task_runner_ = nullptr;
-  main_run_loop_.Run();
 }
 
 // Tests injection of touch events.
@@ -684,10 +715,6 @@
 
   // Send the touch event.
   input_injector_->InjectTouchEvent(event);
-
-  task_runner_ = nullptr;
-  io_task_runner_ = nullptr;
-  main_run_loop_.Run();
 }
 
 // Tests that setting the desktop resolution works.
@@ -713,10 +740,6 @@
   screen_controls_->SetScreenResolution(ScreenResolution(
       webrtc::DesktopSize(100, 100),
       webrtc::DesktopVector(96, 96)));
-
-  task_runner_ = nullptr;
-  io_task_runner_ = nullptr;
-  main_run_loop_.Run();
 }
 
 }  // namespace remoting
diff --git a/remoting/host/it2me_desktop_environment.cc b/remoting/host/it2me_desktop_environment.cc
index 7bb5507c..96c11ce 100644
--- a/remoting/host/it2me_desktop_environment.cc
+++ b/remoting/host/it2me_desktop_environment.cc
@@ -26,10 +26,12 @@
     scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
-    base::WeakPtr<ClientSessionControl> client_session_control)
+    base::WeakPtr<ClientSessionControl> client_session_control,
+    bool supports_touch_events)
     : BasicDesktopEnvironment(caller_task_runner,
                               input_task_runner,
-                              ui_task_runner) {
+                              ui_task_runner,
+                              supports_touch_events) {
   DCHECK(caller_task_runner->BelongsToCurrentThread());
 
   // Create the local input monitor.
@@ -88,7 +90,8 @@
   return make_scoped_ptr(new It2MeDesktopEnvironment(caller_task_runner(),
                                                      input_task_runner(),
                                                      ui_task_runner(),
-                                                     client_session_control));
+                                                     client_session_control,
+                                                     supports_touch_events()));
 }
 
 }  // namespace remoting
diff --git a/remoting/host/it2me_desktop_environment.h b/remoting/host/it2me_desktop_environment.h
index c8c3c32..69e136e 100644
--- a/remoting/host/it2me_desktop_environment.h
+++ b/remoting/host/it2me_desktop_environment.h
@@ -26,7 +26,8 @@
       scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
       scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
-      base::WeakPtr<ClientSessionControl> client_session_control);
+      base::WeakPtr<ClientSessionControl> client_session_control,
+      bool supports_touch_events);
 
  private:
   // Presents the continue window to the local user.
diff --git a/remoting/host/me2me_desktop_environment.cc b/remoting/host/me2me_desktop_environment.cc
index d61beb2b..be41bfb 100644
--- a/remoting/host/me2me_desktop_environment.cc
+++ b/remoting/host/me2me_desktop_environment.cc
@@ -17,6 +17,7 @@
 #include "remoting/host/local_input_monitor.h"
 #include "remoting/host/resizing_host_observer.h"
 #include "remoting/host/screen_controls.h"
+#include "remoting/protocol/capability_names.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h"
 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
 
@@ -25,8 +26,6 @@
 #include <unistd.h>
 #endif  // defined(OS_POSIX)
 
-const char kRateLimitResizeRequests[] = "rateLimitResizeRequests";
-
 namespace remoting {
 
 Me2MeDesktopEnvironment::~Me2MeDesktopEnvironment() {
@@ -40,16 +39,23 @@
 }
 
 std::string Me2MeDesktopEnvironment::GetCapabilities() const {
-  return kRateLimitResizeRequests;
+  std::string capabilities = BasicDesktopEnvironment::GetCapabilities();
+  if (!capabilities.empty())
+    capabilities.append(" ");
+  capabilities.append(protocol::kRateLimitResizeRequests);
+
+  return capabilities;
 }
 
 Me2MeDesktopEnvironment::Me2MeDesktopEnvironment(
     scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
-    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
+    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+    bool supports_touch_events)
     : BasicDesktopEnvironment(caller_task_runner,
                               input_task_runner,
-                              ui_task_runner),
+                              ui_task_runner,
+                              supports_touch_events),
       gnubby_auth_enabled_(false) {
   DCHECK(caller_task_runner->BelongsToCurrentThread());
   desktop_capture_options()->set_use_update_notifications(true);
@@ -143,7 +149,8 @@
   scoped_ptr<Me2MeDesktopEnvironment> desktop_environment(
       new Me2MeDesktopEnvironment(caller_task_runner(),
                                   input_task_runner(),
-                                  ui_task_runner()));
+                                  ui_task_runner(),
+                                  supports_touch_events()));
   if (!desktop_environment->InitializeSecurity(client_session_control,
                                                curtain_enabled_)) {
     return nullptr;
diff --git a/remoting/host/me2me_desktop_environment.h b/remoting/host/me2me_desktop_environment.h
index 40ba2821..331096d0 100644
--- a/remoting/host/me2me_desktop_environment.h
+++ b/remoting/host/me2me_desktop_environment.h
@@ -30,7 +30,8 @@
   Me2MeDesktopEnvironment(
       scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
       scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
-      scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+      bool supports_touch_events);
 
   // Initializes security features of the desktop environment (the curtain mode
   // and in-session UI).
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc
index 943d1d8e..3b52799 100644
--- a/remoting/host/remoting_me2me_host.cc
+++ b/remoting/host/remoting_me2me_host.cc
@@ -52,6 +52,7 @@
 #include "remoting/host/host_exit_codes.h"
 #include "remoting/host/host_main.h"
 #include "remoting/host/host_status_logger.h"
+#include "remoting/host/input_injector.h"
 #include "remoting/host/ipc_constants.h"
 #include "remoting/host/ipc_desktop_environment.h"
 #include "remoting/host/ipc_host_event_logger.h"
@@ -804,7 +805,7 @@
           daemon_channel_.get());
   desktop_session_connector_ = desktop_environment_factory;
 #else  // !defined(OS_WIN)
-  DesktopEnvironmentFactory* desktop_environment_factory;
+  BasicDesktopEnvironmentFactory* desktop_environment_factory;
   if (enable_window_capture_) {
     desktop_environment_factory =
       new SingleWindowDesktopEnvironmentFactory(
@@ -820,6 +821,8 @@
           context_->ui_task_runner());
   }
 #endif  // !defined(OS_WIN)
+  desktop_environment_factory->set_supports_touch_events(
+      InputInjector::SupportsTouchEvents());
 
   desktop_environment_factory_.reset(desktop_environment_factory);
   desktop_environment_factory_->SetEnableGnubbyAuth(enable_gnubby_auth_);
diff --git a/remoting/host/single_window_desktop_environment.cc b/remoting/host/single_window_desktop_environment.cc
index 3b721fce..15da395 100644
--- a/remoting/host/single_window_desktop_environment.cc
+++ b/remoting/host/single_window_desktop_environment.cc
@@ -28,7 +28,8 @@
       scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
       scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
-      webrtc::WindowId window_id);
+      webrtc::WindowId window_id,
+      bool supports_touch_events);
 
  private:
   webrtc::WindowId window_id_;
@@ -69,10 +70,12 @@
     scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
-    webrtc::WindowId window_id)
+    webrtc::WindowId window_id,
+    bool supports_touch_events)
     : BasicDesktopEnvironment(caller_task_runner,
                               input_task_runner,
-                              ui_task_runner),
+                              ui_task_runner,
+                              supports_touch_events),
       window_id_(window_id) {
 }
 
@@ -99,7 +102,8 @@
       new SingleWindowDesktopEnvironment(caller_task_runner(),
                                          input_task_runner(),
                                          ui_task_runner(),
-                                         window_id_));
+                                         window_id_,
+                                         supports_touch_events()));
   return desktop_environment.Pass();
 }
 
diff --git a/remoting/host/win/session_desktop_environment.cc b/remoting/host/win/session_desktop_environment.cc
index 3336482f6..b903fa01 100644
--- a/remoting/host/win/session_desktop_environment.cc
+++ b/remoting/host/win/session_desktop_environment.cc
@@ -33,10 +33,12 @@
     scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
-    const base::Closure& inject_sas)
+    const base::Closure& inject_sas,
+    bool supports_touch_events)
     : Me2MeDesktopEnvironment(caller_task_runner,
                               input_task_runner,
-                              ui_task_runner),
+                              ui_task_runner,
+                              supports_touch_events),
       inject_sas_(inject_sas) {
 }
 
@@ -63,7 +65,8 @@
       new SessionDesktopEnvironment(caller_task_runner(),
                                     input_task_runner(),
                                     ui_task_runner(),
-                                    inject_sas_));
+                                    inject_sas_,
+                                    supports_touch_events()));
   if (!desktop_environment->InitializeSecurity(client_session_control,
                                                curtain_enabled())) {
     return nullptr;
diff --git a/remoting/host/win/session_desktop_environment.h b/remoting/host/win/session_desktop_environment.h
index 233938f..6ae54bf 100644
--- a/remoting/host/win/session_desktop_environment.h
+++ b/remoting/host/win/session_desktop_environment.h
@@ -28,7 +28,8 @@
       scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
       scoped_refptr<base::SingleThreadTaskRunner> input_task_runner,
       scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
-      const base::Closure& inject_sas);
+      const base::Closure& inject_sas,
+      bool supports_touch_events);
 
   // Used to ask the daemon to inject Secure Attention Sequence.
   base::Closure inject_sas_;
diff --git a/remoting/protocol/capability_names.h b/remoting/protocol/capability_names.h
new file mode 100644
index 0000000..60da510
--- /dev/null
+++ b/remoting/protocol/capability_names.h
@@ -0,0 +1,20 @@
+// 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 REMOTING_PROTOCOL_CAPABILITY_NAMeS_H_
+#define REMOTING_PROTOCOL_CAPABILITY_NAMeS_H_
+
+namespace remoting {
+namespace protocol {
+
+// Used for negotiating client-host capabilities for touch events.
+const char kTouchEventsCapability[] = "touchEvents";
+
+const char kSendInitialResolution[] = "sendInitialResolution";
+const char kRateLimitResizeRequests[] = "rateLimitResizeRequests";
+
+}  // namespace protocol
+}  // namespace remoting
+
+#endif  // REMOTING_PROTOCOL_CAPABILITY_NAMeS_H_
diff --git a/remoting/remoting_srcs.gypi b/remoting/remoting_srcs.gypi
index 07cd3ae..6b5dc0d 100644
--- a/remoting/remoting_srcs.gypi
+++ b/remoting/remoting_srcs.gypi
@@ -84,6 +84,7 @@
       'protocol/authentication_method.h',
       'protocol/authenticator.cc',
       'protocol/authenticator.h',
+      'protocol/capability_names.h',
       'protocol/channel_authenticator.h',
       'protocol/channel_dispatcher_base.cc',
       'protocol/channel_dispatcher_base.h',
diff --git a/remoting/remoting_webapp_files.gypi b/remoting/remoting_webapp_files.gypi
index ef49890..7474e679 100644
--- a/remoting/remoting_webapp_files.gypi
+++ b/remoting/remoting_webapp_files.gypi
@@ -89,6 +89,7 @@
       'webapp/base/js/identity_unittest.js',
       'webapp/base/js/ipc_unittest.js',
       'webapp/base/js/l10n_unittest.js',
+      'webapp/base/js/platform_unittest.js',
       'webapp/base/js/protocol_extension_manager_unittest.js',
       'webapp/base/js/typecheck_unittest.js',
       'webapp/base/js/viewport_unittest.js',
diff --git a/remoting/resources/remoting_strings.grd b/remoting/resources/remoting_strings.grd
index e357507..7613e06 100644
--- a/remoting/resources/remoting_strings.grd
+++ b/remoting/resources/remoting_strings.grd
@@ -999,6 +999,9 @@
       <message desc="Label for the client-side menu button that sends a PrtScn key press to the host. The 'PrtScn' abbreviation (as typically printed on the keycap on English keyboards) is preferred over 'Print Screen', to make it clearer that this refers to the physical PrtScn key, and not the OS-specific keyboard shortcut for the screen capture functionality." name="IDS_SEND_PRINT_SCREEN">
         Send PrtScn
       </message>
+      <message desc="Label for the client-side menu button that toggles whether or not the right-hand Ctrl key is used to send the Windows/Command key." name="IDS_MAP_RIGHT_CTRL_TO_META">
+        Use right Ctrl for Win key (⌘ on Mac)
+      </message>
       <message desc="Menu option for enabling shrink-to-fit. When clicked, the remote desktop will be scaled down so that it fits in the browser window." name="IDS_SHRINK_TO_FIT">
         Shrink to fit
       </message>
diff --git a/remoting/resources/remoting_strings_ar.xtb b/remoting/resources/remoting_strings_ar.xtb
index 3a5c8b8..471e7da 100644
--- a/remoting/resources/remoting_strings_ar.xtb
+++ b/remoting/resources/remoting_strings_ar.xtb
@@ -256,8 +256,6 @@
 <translation id="6570205395680337606">إعادة ضبط التطبيق. ستفقد أيّ عمل لم يتم حفظه.</translation>
 <translation id="6284412385303060032">‏تم إيقاف المضيف الذي يعمل على شاشة تسجيل لوحة التحكم لدعم الوضع Curtain من خلال التبديل إلى مضيف يعمل في جلسة خاصة بالمستخدم.</translation>
 <translation id="3596628256176442606">‏تمكن هذه الخدمة الاتصالات الواردة من عملاء التوافق مع نظام التشغيل Chrome.</translation>
-<translation id="1978866438647250517">• تحسينات واجهة المستخدم.
-• استخدام منخفض للشبكة عند التشغيل في الخلفية.</translation>
 <translation id="4741792197137897469">‏أخفقت المصادقة،يُرجى تسجيل الدخول إلى Chrome مرة أخرى.</translation>
 <translation id="4277463233460010382">تمت تهيئة هذا الكمبيوتر بحيث يسمح لعميل واحد أو أكثر بالاتصال بدون إدخال رقم تعريف شخصي.</translation>
 <translation id="837021510621780684">من هذا الكمبيوتر</translation>
diff --git a/remoting/resources/remoting_strings_bg.xtb b/remoting/resources/remoting_strings_bg.xtb
index e0650e2..7e68617 100644
--- a/remoting/resources/remoting_strings_bg.xtb
+++ b/remoting/resources/remoting_strings_bg.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Рестартиране на приложението. Незапазената работа ще бъде заличена.</translation>
 <translation id="6284412385303060032">Хостът, изпълняван на екрана за вход в конзолата, е спрян, за да се поддържа режимът на прикриване, като се превключи към хост, работещ в сесия на конкретен потребител.</translation>
 <translation id="3596628256176442606">Тази услуга активира входящите връзки от клиентски програми за Chromoting.</translation>
-<translation id="1978866438647250517">• Подобрения на потребителския интерфейс.
-• Намалено използване на мрежата при работа на заден план.</translation>
 <translation id="4741792197137897469">Удостоверяването не бе успешно. Моля, влезте отново в Chrome.</translation>
 <translation id="4277463233460010382">Този компютър е конфигуриран така, че една или повече клиентски програми да могат да установяват връзка, без да въвеждат ПИН код.</translation>
 <translation id="837021510621780684">От този компютър</translation>
diff --git a/remoting/resources/remoting_strings_ca.xtb b/remoting/resources/remoting_strings_ca.xtb
index f7002b9..d22accd0 100644
--- a/remoting/resources/remoting_strings_ca.xtb
+++ b/remoting/resources/remoting_strings_ca.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Restabliu l'aplicació. Els treballs que no s'hagin desat es perdran.</translation>
 <translation id="6284412385303060032">L'amfitrió que s'executa a la pantalla d'inici de la consola s'ha aturat per admetre el mode Curtain, i fa servir un amfitrió que s'executa en una sessió específica de l'usuari.</translation>
 <translation id="3596628256176442606">Aquest servei permet les connexions entrants dels clients de Chromoting.</translation>
-<translation id="1978866438647250517">• Millores en la interfície d'usuari.
-• Es redueix l'ús de la xarxa quan s'executa en segon pla.</translation>
 <translation id="4741792197137897469">L'autenticació ha fallat. Torneu a iniciar la sessió a Chrome.</translation>
 <translation id="4277463233460010382">La configuració d'aquest ordinador permet que un o més clients es connectin sense introduir cap PIN.</translation>
 <translation id="837021510621780684">Des d'aquest ordinador</translation>
diff --git a/remoting/resources/remoting_strings_cs.xtb b/remoting/resources/remoting_strings_cs.xtb
index 9e0bd5c..18988f6 100644
--- a/remoting/resources/remoting_strings_cs.xtb
+++ b/remoting/resources/remoting_strings_cs.xtb
@@ -255,8 +255,6 @@
 <translation id="6570205395680337606">Resetovat aplikace. Veškerá neuložená práce bude ztracena.</translation>
 <translation id="6284412385303060032">Hostitel spuštěný na obrazovce logiky konzole byl ukončen za účelem zajištění podpory režimu opony prostřednictvím přepnutí na hostitele spuštěného v relaci specifické pro uživatele.</translation>
 <translation id="3596628256176442606">Tato služba umožňuje příchozí připojení od klientů funkce Chromoting.</translation>
-<translation id="1978866438647250517">• Vylepšeno uživatelské rozhraní.
-• Sníženo využití sítě při běhu na pozadí.</translation>
 <translation id="4741792197137897469">Ověření selhalo. Přihlaste se do prohlížeče Chrome znovu.</translation>
 <translation id="4277463233460010382">Tento počítač je nakonfigurován tak, aby jednomu nebo více klientům umožnil připojení bez zadávání kódu PIN.</translation>
 <translation id="837021510621780684">Z tohoto počítače</translation>
diff --git a/remoting/resources/remoting_strings_da.xtb b/remoting/resources/remoting_strings_da.xtb
index d19e4d5..377293b 100644
--- a/remoting/resources/remoting_strings_da.xtb
+++ b/remoting/resources/remoting_strings_da.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Nulstil applikationen. Du vil miste alt arbejde, der ikke er gemt.</translation>
 <translation id="6284412385303060032">Hosten, der kører på loginskærmen for konsollen, er lukket ned for at understøtte curtain mode ved at skifte til en host, der kører i en brugerspecifik session.</translation>
 <translation id="3596628256176442606">Denne tjeneste muliggør indgående forbindelser fra Chromoting-klienter.</translation>
-<translation id="1978866438647250517">• Forbedringer af brugergrænsefladen.
-• Reduceret netværksforbrug, når det kører i baggrunden.</translation>
 <translation id="4741792197137897469">Godkendelsen mislykkedes. Log ind på Chrome igen.</translation>
 <translation id="4277463233460010382">Denne computer er konfigureret til at tillade, at en eller flere klienter opretter forbindelse uden at angive en pinkode.</translation>
 <translation id="837021510621780684">Fra denne computer</translation>
diff --git a/remoting/resources/remoting_strings_de.xtb b/remoting/resources/remoting_strings_de.xtb
index d25325a..61dabab0 100644
--- a/remoting/resources/remoting_strings_de.xtb
+++ b/remoting/resources/remoting_strings_de.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">App zurücksetzen. Alle nicht gespeicherten Daten gehen verloren.</translation>
 <translation id="6284412385303060032">Der Host, der auf dem Anmeldebildschirm für die Konsole ausgeführt wird, wurde heruntergefahren, um den Vorhangmodus zu unterstützen, indem zu einem Host in einer nutzerspezfischen Sitzung gewechselt wurde.</translation>
 <translation id="3596628256176442606">Dieser Dienst ermöglicht eingehende Verbindungen von Chromoting-Clients.</translation>
-<translation id="1978866438647250517">• Verbesserungen an der Benutzeroberfläche
-• Geringere Netzwerkauslastung beim Ausführen im Hintergrund</translation>
 <translation id="4741792197137897469">Fehler bei der Authentifizierung. Melden Sie sich erneut in Chrome an.</translation>
 <translation id="4277463233460010382">Dieser Computer wird konfiguriert, um einem oder mehreren Clients das Herstellen einer Verbindung ohne Eingabe einer PIN zu ermöglichen.</translation>
 <translation id="837021510621780684">Von diesem Computer</translation>
diff --git a/remoting/resources/remoting_strings_el.xtb b/remoting/resources/remoting_strings_el.xtb
index b434247..651e184 100644
--- a/remoting/resources/remoting_strings_el.xtb
+++ b/remoting/resources/remoting_strings_el.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Κάντε επαναφορά της εφαρμογής. Θα χάσετε τυχόν μη αποθηκευμένες εργασίες.</translation>
 <translation id="6284412385303060032">Ο κεντρικός υπολογιστής που εκτελείται στην οθόνη σύνδεσης της κονσόλας τερματίστηκε για να υποστηρίξει τη λειτουργία κουρτίνας, με την εναλλαγή σε έναν υπολογιστή που εκτελείται σε μια περίοδο σύνδεσης συγκεκριμένου χρήστη.</translation>
 <translation id="3596628256176442606">Αυτή η υπηρεσία ενεργοποιεί τις εισερχόμενες συνδέσεις από υπολογιστές-πελάτες Chromoting.</translation>
-<translation id="1978866438647250517">• Βελτιώσεις διεπαφής χρήστη.
-• Μειωμένη χρήση δικτύου κατά τη λειτουργία στο παρασκήνιο.</translation>
 <translation id="4741792197137897469">Αποτυχία ελέγχου ταυτότητας. Συνδεθείτε ξανά στο Chrome.</translation>
 <translation id="4277463233460010382">Αυτός ο υπολογιστής έχει διαμορφωθεί έτσι ώστε να επιτρέπει σε έναν ή περισσότερους υπολογιστές-πελάτες να συνδέονται χωρίς την εισαγωγή PIN.</translation>
 <translation id="837021510621780684">Από αυτόν τον υπολογιστή</translation>
diff --git a/remoting/resources/remoting_strings_en-GB.xtb b/remoting/resources/remoting_strings_en-GB.xtb
index 595613a..3c56b87a 100644
--- a/remoting/resources/remoting_strings_en-GB.xtb
+++ b/remoting/resources/remoting_strings_en-GB.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Reset the application. You will lose any unsaved work.</translation>
 <translation id="6284412385303060032">Host running at the console logic screen has shut down to support curtain mode by switching to a host running in a user-specific session.</translation>
 <translation id="3596628256176442606">This service enables incoming connections from Chromoting clients.</translation>
-<translation id="1978866438647250517">• User interface improvements.
-• Reduced network usage when running in the background.</translation>
 <translation id="4741792197137897469">Authentication failed. Please sign in to Chrome again.</translation>
 <translation id="4277463233460010382">This computer is configured to allow one or more clients to connect without entering a PIN.</translation>
 <translation id="837021510621780684">From this computer</translation>
diff --git a/remoting/resources/remoting_strings_es-419.xtb b/remoting/resources/remoting_strings_es-419.xtb
index d611bc9f..83a0d23 100644
--- a/remoting/resources/remoting_strings_es-419.xtb
+++ b/remoting/resources/remoting_strings_es-419.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Restablece la aplicación. Perderás todo el trabajo que no se haya guardado.</translation>
 <translation id="6284412385303060032">Se cerró el host que se ejecuta en la pantalla de acceso de la consola para poder admitir el modo de cortina. Por lo tanto, se cambió a un host que se ejecuta en una sesión específica de usuario.</translation>
 <translation id="3596628256176442606">Este servicio permite conexiones entrantes de los clientes de Chromoting.</translation>
-<translation id="1978866438647250517">• Se incluyen mejoras en la interfaz de usuario.
-• Se redujo el uso de la red durante la ejecución en segundo plano.</translation>
 <translation id="4741792197137897469">Se produjo un error de autenticación. Vuelve a acceder a Chrome.</translation>
 <translation id="4277463233460010382">Esta computadora está configurada para permitir que uno o más clientes se conecten sin ingresar un PIN.</translation>
 <translation id="837021510621780684">Desde esta computadora</translation>
diff --git a/remoting/resources/remoting_strings_es.xtb b/remoting/resources/remoting_strings_es.xtb
index 43e60e4..a0f17cf8 100644
--- a/remoting/resources/remoting_strings_es.xtb
+++ b/remoting/resources/remoting_strings_es.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Restablecer la aplicación. Se perderá cualquier trabajo que no hayas guardado.</translation>
 <translation id="6284412385303060032">Se ha cerrado el host que se ejecuta en la pantalla de inicio de sesión de la consola para poder admitir el modo de cortina. Para ello, se ha cambiado a un host que se ejecuta en una sesión específica de usuario.</translation>
 <translation id="3596628256176442606">Este servicio permite las conexiones entrantes de los clientes de Chromoting.</translation>
-<translation id="1978866438647250517">• Se ha mejorado la interfaz de usuario.
-• Se ha reducido el uso de red al ejecutar la aplicación en segundo plano.</translation>
 <translation id="4741792197137897469">Error de autenticación. Vuelve a iniciar sesión en Chrome.</translation>
 <translation id="4277463233460010382">Este ordenador está configurado para permitir que uno o más clientes se conecten sin introducir un PIN.</translation>
 <translation id="837021510621780684">Conexiones desde este ordenador</translation>
diff --git a/remoting/resources/remoting_strings_et.xtb b/remoting/resources/remoting_strings_et.xtb
index ca3c9ea0..6e1b9009 100644
--- a/remoting/resources/remoting_strings_et.xtb
+++ b/remoting/resources/remoting_strings_et.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Rakenduse lähtestamine. Kaotate kogu salvestamata töö.</translation>
 <translation id="6284412385303060032">Konsooli loogikakuval käitatav host on varjatud režiimi toetamiseks välja lülitatud, lülitades hostile, mida käitatakse kasutajapõhises seansis.</translation>
 <translation id="3596628256176442606">See teenus lubab sissetulevad ühendused Chromootimise klientidelt.</translation>
-<translation id="1978866438647250517">• Kasutajaliidese täiustused.
-• Kasutab taustal töötades vähem võrguühendust.</translation>
 <translation id="4741792197137897469">Autentimine ebaõnnestus. Logige uuesti Chrome'i sisse.</translation>
 <translation id="4277463233460010382">Arvuti on seadistatud nii, et see lubab ühel või mitmel kliendil luua ühenduse ilma PIN-koodi sisestamata.</translation>
 <translation id="837021510621780684">Sellest arvutist</translation>
diff --git a/remoting/resources/remoting_strings_fi.xtb b/remoting/resources/remoting_strings_fi.xtb
index 8be6946..4f2569b 100644
--- a/remoting/resources/remoting_strings_fi.xtb
+++ b/remoting/resources/remoting_strings_fi.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Nollaa sovellus. Menetät kaikki tallentamattomat työt.</translation>
 <translation id="6284412385303060032">Konsolin logiikkaruudussa käynnissä ollut isäntä sulkeutui tukeakseen verhotilaa. Vaihdetaan käyttäjäkohtaisessa istunnossa käynnissä olevaan isäntään.</translation>
 <translation id="3596628256176442606">Tämä palvelu mahdollistaa Chromoting-asiakkaiden muodostamat yhteydet.</translation>
-<translation id="1978866438647250517">• Käyttöliittymään on tehty parannuksia.
-• Verkon käyttöä on vähennetty käytettäessä taustalla.</translation>
 <translation id="4741792197137897469">Todennus epäonnistui. Kirjaudu uudelleen sisään Chromeen.</translation>
 <translation id="4277463233460010382">Tämä tietokone on määritetty sallimaan vähintään yhden asiakkaan yhteys ilman PIN-koodia.</translation>
 <translation id="837021510621780684">Tältä tietokoneelta</translation>
diff --git a/remoting/resources/remoting_strings_fil.xtb b/remoting/resources/remoting_strings_fil.xtb
index 76b8dae..b71aa018 100644
--- a/remoting/resources/remoting_strings_fil.xtb
+++ b/remoting/resources/remoting_strings_fil.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">I-reset ang application. Mawawala ang anumang hindi na-save na gawa.</translation>
 <translation id="6284412385303060032">Nag-shutdown ang host na tumatakbo sa console logic screen upang masuportahan ang curtain mode sa pamamagitan ng paglipat sa isang host na tumatakbo sa isang user-specific session.</translation>
 <translation id="3596628256176442606">Ini-enable ng serbisyong ito ang mga papasok na koneksyon mula sa mga client ng Chromoting.</translation>
-<translation id="1978866438647250517">• Mga pagpapahusay sa user interface.
-• Nabawasang paggamit ng network kapag tumatakbo sa background.</translation>
 <translation id="4741792197137897469">Hindi naisagawa ang pagpapatotoo. Mangyaring muling mag-sign in sa Chrome.</translation>
 <translation id="4277463233460010382">Naka-configure ang computer na ito na payagan ang isa o higit pang mga client na kumonekta nang hindi naglalagay ng PIN.</translation>
 <translation id="837021510621780684">Mula sa computer na ito</translation>
diff --git a/remoting/resources/remoting_strings_fr.xtb b/remoting/resources/remoting_strings_fr.xtb
index 07f87d873..538549f 100644
--- a/remoting/resources/remoting_strings_fr.xtb
+++ b/remoting/resources/remoting_strings_fr.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Réinitialiser l'application (toutes les données non enregistrées seront perdues)</translation>
 <translation id="6284412385303060032">L'exécution de l'hôte sur l'écran de connexion de la console s'est arrêtée pour accepter le mode Rideau en passant à une exécution d'hôte dans une session propre à l'utilisateur.</translation>
 <translation id="3596628256176442606">Ce service permet la réception de connexions provenant des clients de Chromoting.</translation>
-<translation id="1978866438647250517">• Améliorations apportées à l'interface utilisateur
-• Réduction de l'utilisation du réseau lorsque l'application est exécutée en arrière-plan</translation>
 <translation id="4741792197137897469">Échec de l'authentification. Veuillez vous connecter de nouveau à Chrome.</translation>
 <translation id="4277463233460010382">Cet ordinateur est configuré pour permettre à un ou plusieurs clients de se connecter sans saisir de code d'accès.</translation>
 <translation id="837021510621780684">À partir de cet ordinateur</translation>
diff --git a/remoting/resources/remoting_strings_hi.xtb b/remoting/resources/remoting_strings_hi.xtb
index 632ce6ee..9b3fec9 100644
--- a/remoting/resources/remoting_strings_hi.xtb
+++ b/remoting/resources/remoting_strings_hi.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">ऐप्‍लिकेशन को रीसेट करें. आप किसी भी नहीं सहेजे गए कार्य को खो देंगे.</translation>
 <translation id="6284412385303060032">कर्टन मोड का समर्थन करने के लिए, कंसोल लॉजिक स्‍क्रीन पर चल रहा होस्‍ट किसी उपयोगकर्ता द्वारा निर्दिष्‍ट सत्र में चल रहे होस्‍ट पर स्‍विच होकर बंद हो गया है.</translation>
 <translation id="3596628256176442606">यह सेवा Chromoting क्लाइंट के इनकमिंग कनेक्शन सक्षम करती है.</translation>
-<translation id="1978866438647250517">• उपयोगकर्ता इंटरफ़ेस सुधार.
-• पृष्‍ठभूमि में चलते समय कम नेटवर्क उपयोग.</translation>
 <translation id="4741792197137897469">प्रमाणीकरण विफल रहा. कृपया Chrome में पुन: प्रवेश करें.</translation>
 <translation id="4277463233460010382">इस कंप्यूटर को PIN डाले बिना एक या इससे अधिक क्लाइंट से कनेक्ट करने देने के लिए कॉन्फ़िगर किया गया है.</translation>
 <translation id="837021510621780684">इस कंप्यूटर से</translation>
diff --git a/remoting/resources/remoting_strings_hr.xtb b/remoting/resources/remoting_strings_hr.xtb
index 10a903d..2ace803 100644
--- a/remoting/resources/remoting_strings_hr.xtb
+++ b/remoting/resources/remoting_strings_hr.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Vratite aplikaciju na zadano. Izgubit ćete sav rad koji niste spremili.</translation>
 <translation id="6284412385303060032">Host koji je pokrenut na zaslonu za prijavu na konzolu isključio se radi podrške za način zavjese prelaskom na host koji je pokrenut u sesiji korisnika.</translation>
 <translation id="3596628256176442606">Ta usluga omogućuje dolazne veze s klijenata usluge Chromoting.</translation>
-<translation id="1978866438647250517">• poboljšanja korisničkog sučelja
-• smanjena mrežna potrošnja prilikom izvođenja u pozadini</translation>
 <translation id="4741792197137897469">Autentifikacija nije uspjela. Prijavite se ponovo u Chrome.</translation>
 <translation id="4277463233460010382">To je računalo konfigurirano tako da dozvoljava povezivanje jednog ili više klijenata bez unosa PIN-a.</translation>
 <translation id="837021510621780684">S ovog računala</translation>
diff --git a/remoting/resources/remoting_strings_hu.xtb b/remoting/resources/remoting_strings_hu.xtb
index d515f0c..2c2b06e 100644
--- a/remoting/resources/remoting_strings_hu.xtb
+++ b/remoting/resources/remoting_strings_hu.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Alkalmazás visszaállítása. A nem mentett munkája el fog veszni.</translation>
 <translation id="6284412385303060032">A konzol logikai képernyőjén futó gazdagép leállt, hogy támogassa a rejtett üzemmódot úgy, hogy felhasználóspecifikus munkamenetben futó gazdagépre váltott.</translation>
 <translation id="3596628256176442606">Ez a szolgáltatás engedélyezi a bejövő kapcsolatokat a Chromoting klienseitől.</translation>
-<translation id="1978866438647250517">• Fejlesztések a kezelőfelületen.
-• Csökkentett hálózathasználat, miközben a háttérben fut.</translation>
 <translation id="4741792197137897469">A hitelesítés nem sikerült. Kérjük, jelentkezzen be újra a Chrome-ba.</translation>
 <translation id="4277463233460010382">Ez a számítógép úgy van konfigurálva, hogy egy vagy több kliens PIN megadása nélkül csatlakozhasson.</translation>
 <translation id="837021510621780684">Erről a számítógépről</translation>
diff --git a/remoting/resources/remoting_strings_id.xtb b/remoting/resources/remoting_strings_id.xtb
index e3fca34..3914b7b 100644
--- a/remoting/resources/remoting_strings_id.xtb
+++ b/remoting/resources/remoting_strings_id.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Setel ulang aplikasi. Anda akan kehilangan pekerjaan yang belum disimpan.</translation>
 <translation id="6284412385303060032">Host yang berjalan di layar logika konsol telah dinonaktifkan untuk mendukung mode tirai dengan beralih ke host yang berjalan di sesi khusus pengguna.</translation>
 <translation id="3596628256176442606">Layanan ini mengaktifkan sambungan masuk dari klien Chromoting.</translation>
-<translation id="1978866438647250517">• Penyempurnaan antarmuka pengguna.
-• Penggunaan jaringan yang dikurangi saat berjalan di latar belakang.</translation>
 <translation id="4741792197137897469">Autentikasi gagal. Masuk ke Chrome lagi.</translation>
 <translation id="4277463233460010382">Komputer ini dikonfigurasi untuk mengizinkan satu atau beberapa klien terhubung tanpa memasukkan PIN</translation>
 <translation id="837021510621780684">Dari komputer ini</translation>
diff --git a/remoting/resources/remoting_strings_it.xtb b/remoting/resources/remoting_strings_it.xtb
index 192410f..e02b99d3 100644
--- a/remoting/resources/remoting_strings_it.xtb
+++ b/remoting/resources/remoting_strings_it.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Ripristina l'applicazione. Perderai gli eventuali lavori non salvati.</translation>
 <translation id="6284412385303060032">L'esecuzione dell'host nella schermata di accesso alla console si è interrotta per supportare la modalità Curtain, pertanto l'host viene ora eseguito in una sessione specifica dell'utente.</translation>
 <translation id="3596628256176442606">Questo servizio consente connessioni in entrata da client Chromoting.</translation>
-<translation id="1978866438647250517">• Miglioramenti all'interfaccia utente.
-• Utilizzo ridotto della rete se in esecuzione in background.</translation>
 <translation id="4741792197137897469">Autenticazione non riuscita. Accedi di nuovo a Chrome.</translation>
 <translation id="4277463233460010382">Questo computer è configurato per consentire la connessione di uno o più client senza l'inserimento di un codice PIN.</translation>
 <translation id="837021510621780684">Da questo computer</translation>
diff --git a/remoting/resources/remoting_strings_iw.xtb b/remoting/resources/remoting_strings_iw.xtb
index 33ccf913..89443b7 100644
--- a/remoting/resources/remoting_strings_iw.xtb
+++ b/remoting/resources/remoting_strings_iw.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">אפס את היישום. תאבד עבודות שלא נשמרו.</translation>
 <translation id="6284412385303060032">המארח הפועל במסך הכניסה למסוף כבה כדי לתמוך במצב הסתרה על ידי מעבר אל מארח הרץ בפעילות באתר שהיא ספציפית למשתמש.</translation>
 <translation id="3596628256176442606">‏שירות זה מאפשר חיבורים נכנסים מלקוחות Chromoting.</translation>
-<translation id="1978866438647250517">• שיפורים בממשק המשתמש.
-• שימוש מופחת ברשת בזמן ריצה ברקע.</translation>
 <translation id="4741792197137897469">‏האימות נכשל. היכנס שוב ל-Chrome.</translation>
 <translation id="4277463233460010382">‏מחשב זה מוגדר לאפשר ללקוח אחד או יותר להתחבר מבלי להזין PIN.</translation>
 <translation id="837021510621780684">ממחשב זה</translation>
diff --git a/remoting/resources/remoting_strings_ja.xtb b/remoting/resources/remoting_strings_ja.xtb
index c8bb75c3..f2625c8 100644
--- a/remoting/resources/remoting_strings_ja.xtb
+++ b/remoting/resources/remoting_strings_ja.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">アプリケーションをリセットします。保存されていない作業は失われます。</translation>
 <translation id="6284412385303060032">コンソールのログイン画面で実行されるホストは、カーテンモードをサポートするために終了されました(ユーザー固有のセッションで実行されるホストに切り替えられました)。</translation>
 <translation id="3596628256176442606">このサービスにより、Chromoting クライアントからの着信接続が有効になります。</translation>
-<translation id="1978866438647250517">• ユーザー インターフェースが改善されました。
-• バックグラウンド実行時のネットワーク使用量が削減されました。</translation>
 <translation id="4741792197137897469">認証できませんでした。Chrome にもう一度ログインしてください。</translation>
 <translation id="4277463233460010382">このパソコンは、1 つ以上のクライアントが PIN の入力なしで接続できるように設定されています。</translation>
 <translation id="837021510621780684">このパソコンからの接続</translation>
diff --git a/remoting/resources/remoting_strings_ko.xtb b/remoting/resources/remoting_strings_ko.xtb
index 09525f0..0f5010f7 100644
--- a/remoting/resources/remoting_strings_ko.xtb
+++ b/remoting/resources/remoting_strings_ko.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">애플리케이션을 재설정합니다. 저장하지 않은 작업을 잃게 됩니다.</translation>
 <translation id="6284412385303060032">콘솔 로직 화면에서 실행 중인 호스트가 사용자별 세션에서 실행 중인 호스트로 전환하여 커튼 모드를 지원하기 위해 종료되었습니다.</translation>
 <translation id="3596628256176442606">이 서비스를 이용하면 Chromoting 클라이언트로부터의 연결을 수신할 수 있습니다.</translation>
-<translation id="1978866438647250517">• 사용자 인터페이스 개선
-• 백그라운드에서 실행 중일 때 네트워크 사용량 축소</translation>
 <translation id="4741792197137897469">인증에 실패했습니다. Chrome에 다시 로그인하세요.</translation>
 <translation id="4277463233460010382">이 컴퓨터는 한 개 이상의 클라이언트가 PIN을 입력하지 않고도 연결할 수 있도록 구성되었습니다.</translation>
 <translation id="837021510621780684">이 컴퓨터에서 시작한 연결</translation>
diff --git a/remoting/resources/remoting_strings_lt.xtb b/remoting/resources/remoting_strings_lt.xtb
index 20dedd3..bdb82437 100644
--- a/remoting/resources/remoting_strings_lt.xtb
+++ b/remoting/resources/remoting_strings_lt.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Iš naujo nustatykite programą. Prarasite visus neišsaugotus duomenis.</translation>
 <translation id="6284412385303060032">Priegloba, veikianti pulto logikos ekrane, išjungta, kad būtų galima palaikyti nerodomo vaizdo režimą perjungus į prieglobą, veikiančią konkretaus naudotojo sesijoje.</translation>
 <translation id="3596628256176442606">Naudojant šią paslaugą įgalinami „Chrome“ nuotolinio ryšio klientų prisijungimai.</translation>
-<translation id="1978866438647250517">• Naudotojo sąsajos patobulinimai.
-• Mažesnis tinklo naudojimas, kai vykdoma fone.</translation>
 <translation id="4741792197137897469">Nepavyko autentifikuoti. Dar kartą prisijunkite prie „Chrome“.</translation>
 <translation id="4277463233460010382">Šis kompiuteris sukonfigūruotas leisti vienam ar keliems klientams prisijungti neįvedus PIN kodo.</translation>
 <translation id="837021510621780684">Iš šio kompiuterio</translation>
diff --git a/remoting/resources/remoting_strings_lv.xtb b/remoting/resources/remoting_strings_lv.xtb
index c2c1f692..36f249c0 100644
--- a/remoting/resources/remoting_strings_lv.xtb
+++ b/remoting/resources/remoting_strings_lv.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Atiestatīt lietojumprogrammu. Tiks zaudēts viss nesaglabātais saturs.</translation>
 <translation id="6284412385303060032">Saimniekdators, kas darbojas konsoles pieteikšanās ekrānā, ir izslēgts, lai atbalstītu aizkara režīmu, pārslēdzoties uz saimniekdatoru, kurš darbojas noteikta lietotāja sesijā.</translation>
 <translation id="3596628256176442606">Izmantojot šo pakalpojumu, tiek iespējoti ienākošie savienojumi no Chrome saites klientiem.</translation>
-<translation id="1978866438647250517">• Lietotāja saskarnes uzlabojumi.
-• Samazināts tīkla lietojums, darbojoties fonā.</translation>
 <translation id="4741792197137897469">Autentificēšana neizdevās. Lūdzu, vēlreiz pierakstieties pārlūkā Chrome.</translation>
 <translation id="4277463233460010382">Šajā datorā ir konfigurēta atļauja vienam vai vairākiem klientiem izveidot savienojumu, neievadot PIN kodu.</translation>
 <translation id="837021510621780684">No šī datora</translation>
diff --git a/remoting/resources/remoting_strings_nl.xtb b/remoting/resources/remoting_strings_nl.xtb
index 2bad213..2bed778 100644
--- a/remoting/resources/remoting_strings_nl.xtb
+++ b/remoting/resources/remoting_strings_nl.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">De app opnieuw instellen. Al je niet-opgeslagen werk gaat verloren.</translation>
 <translation id="6284412385303060032">De host die werd uitgevoerd op het console-inlogscherm, is uitgeschakeld om de gordijnmodus te ondersteunen door over te schakelen naar een host die in een gebruikersspecifieke sessie wordt uitgevoerd.</translation>
 <translation id="3596628256176442606">Met deze service worden inkomende verbindingen van Chromoting-clients ingeschakeld.</translation>
-<translation id="1978866438647250517">• Verbeteringen in de gebruikersinterface.
-• Beperkt netwerkgebruik, indien uitgevoerd op de achtergrond.</translation>
 <translation id="4741792197137897469">Verificatie mislukt. Log opnieuw in bij Chrome.</translation>
 <translation id="4277463233460010382">Deze computer is geconfigureerd om een of meer clients toestemming te geven verbinding te maken zonder een pincode op te geven.</translation>
 <translation id="837021510621780684">Vanaf deze computer</translation>
diff --git a/remoting/resources/remoting_strings_no.xtb b/remoting/resources/remoting_strings_no.xtb
index aed6d7b6..e51e43a4f 100644
--- a/remoting/resources/remoting_strings_no.xtb
+++ b/remoting/resources/remoting_strings_no.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Tilbakestill programmet. Du mister alt arbeid som ikke er lagret.</translation>
 <translation id="6284412385303060032">Verten som kjører på skjermen for konsollpålogging, har blitt avsluttet for å støtte gardinmodus ved å bytte til en vert som kjører i en brukerspesifikk økt.</translation>
 <translation id="3596628256176442606">Med denne tjenesten kan du motta innkommende tilkoblinger fra Chromoting-klienter.</translation>
-<translation id="1978866438647250517">• Forbedringer i brukergrensesnittet.
-• Redusert bruk av nettverket ved kjøring i bakgrunnen.</translation>
 <translation id="4741792197137897469">Autentiseringen mislyktes. Logg på Chrome på nytt.</translation>
 <translation id="4277463233460010382">Denne datamaskinen er konfigurer for å la én eller flere klienter koble til uten å skrive inn noen PIN-kode.</translation>
 <translation id="837021510621780684">Fra denne datamaskinen</translation>
diff --git a/remoting/resources/remoting_strings_pl.xtb b/remoting/resources/remoting_strings_pl.xtb
index 9ea85bb..2fe7c54c 100644
--- a/remoting/resources/remoting_strings_pl.xtb
+++ b/remoting/resources/remoting_strings_pl.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Zresetuj aplikację. Niezapisane dane zostaną utracone.</translation>
 <translation id="6284412385303060032">Host uruchomiony na ekranie logowania konsoli został zamknięty, by umożliwić włączenie trybu kurtyny, przełączając się na hosta uruchomionego w sesji danego użytkownika.</translation>
 <translation id="3596628256176442606">Ta usługa umożliwia obsługę połączeń przychodzących z klientów funkcji Chromoting.</translation>
-<translation id="1978866438647250517">• Ulepszenia interfejsu użytkownika.
-• Ograniczenie wykorzystania przepustowości przez zadania uruchamiane w tle.</translation>
 <translation id="4741792197137897469">Uwierzytelnianie nie powiodło się. Zaloguj się ponownie do Chrome.</translation>
 <translation id="4277463233460010382">Ten komputer jest skonfigurowany do zezwalania jednemu lub wielu klientom na łączenie się bez podawania kodu PIN.</translation>
 <translation id="837021510621780684">Z tego komputera</translation>
diff --git a/remoting/resources/remoting_strings_pt-BR.xtb b/remoting/resources/remoting_strings_pt-BR.xtb
index b77e254b..6881813 100644
--- a/remoting/resources/remoting_strings_pt-BR.xtb
+++ b/remoting/resources/remoting_strings_pt-BR.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Reinicie o aplicativo. Você perderá qualquer trabalho que não tenha sido salvo.</translation>
 <translation id="6284412385303060032">O host que está sendo executado na tela de lógica do console foi encerrado para suportar o modo de cortina, alternando para um host executado em uma sessão específica do usuário.</translation>
 <translation id="3596628256176442606">Este serviço permite conexões de entrada a partir de clientes do Chromoting.</translation>
-<translation id="1978866438647250517">• Melhorias na interface de usuário.
-• Uso de rede reduzido quando executado em segundo plano.</translation>
 <translation id="4741792197137897469">Falha na autenticação. Faça login novamente no Chrome.</translation>
 <translation id="4277463233460010382">Este computador está configurado para permitir que um ou mais clientes se conectem sem ter que inserir um PIN.</translation>
 <translation id="837021510621780684">Deste computador</translation>
diff --git a/remoting/resources/remoting_strings_pt-PT.xtb b/remoting/resources/remoting_strings_pt-PT.xtb
index 044bc53..bf2b9dd 100644
--- a/remoting/resources/remoting_strings_pt-PT.xtb
+++ b/remoting/resources/remoting_strings_pt-PT.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Reponha a aplicação. O trabalho não guardado é perdido.</translation>
 <translation id="6284412385303060032">O anfitrião em execução no ecrã de início de sessão da consola foi encerrado para suportar o modo de cortina ao alternar para um anfitrião em execução numa sessão específica de utilizador.</translation>
 <translation id="3596628256176442606">Este serviço permite receber ligações de clientes do Chromoting.</translation>
-<translation id="1978866438647250517">• Melhorias da interface do utilizador.
-• Redução da utilização da rede quando está em execução em segundo plano.</translation>
 <translation id="4741792197137897469">Falha na autenticação. Inicie sessão novamente no Chrome.</translation>
 <translation id="4277463233460010382">Este computador está configurado para permitir que um ou mais clientes se liguem sem introduzir um PIN.</translation>
 <translation id="837021510621780684">A partir deste computador</translation>
diff --git a/remoting/resources/remoting_strings_ro.xtb b/remoting/resources/remoting_strings_ro.xtb
index 8ca2e8f3..abc1d095 100644
--- a/remoting/resources/remoting_strings_ro.xtb
+++ b/remoting/resources/remoting_strings_ro.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Resetează aplicația. Orice conținut nesalvat se va pierde.</translation>
 <translation id="6284412385303060032">Executarea gazdei pe ecranul de conectare al consolei a fost oprită pentru a accepta modul perdea, comutând la o gazdă care rulează într-o sesiune specifică utilizatorului.</translation>
 <translation id="3596628256176442606">Acest serviciu permite conexiuni primite de la clienți Chromoting.</translation>
-<translation id="1978866438647250517">• Îmbunătățiri ale interfeței de utilizare.
-• Utilizare redusă a rețelei când rulează în fundal.</translation>
 <translation id="4741792197137897469">Autentificarea nu a reușit. Conectează-te din nou la Chrome.</translation>
 <translation id="4277463233460010382">Acest computer este configurat să permită conectarea unuia sau a mai multor clienți fără introducerea unui PIN.</translation>
 <translation id="837021510621780684">De la acest computer</translation>
diff --git a/remoting/resources/remoting_strings_ru.xtb b/remoting/resources/remoting_strings_ru.xtb
index 2433ef72..bb5f961 100644
--- a/remoting/resources/remoting_strings_ru.xtb
+++ b/remoting/resources/remoting_strings_ru.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Перезапустить приложение. Все несохраненные данные будут потеряны.</translation>
 <translation id="6284412385303060032">Хост консоли экрана авторизации не поддерживает режим Curtain mode (переключается на пользовательский сеанс).</translation>
 <translation id="3596628256176442606">Данная служба обеспечивает входящие соединения от клиентов Пульта Chrome.</translation>
-<translation id="1978866438647250517">• Улучшен пользовательский интерфейс.
-• Экономное использование сети в фоновом режиме.</translation>
 <translation id="4741792197137897469">Ошибка аутентификации. Войдите в Chrome ещё раз.</translation>
 <translation id="4277463233460010382">Некоторые клиенты могут подключаться к этому компьютеру без PIN-кода.</translation>
 <translation id="837021510621780684">С этого компьютера</translation>
diff --git a/remoting/resources/remoting_strings_sk.xtb b/remoting/resources/remoting_strings_sk.xtb
index 1bb501fbe..ae502a84 100644
--- a/remoting/resources/remoting_strings_sk.xtb
+++ b/remoting/resources/remoting_strings_sk.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Resetovať aplikáciu. Prídete o všetku neuloženú prácu.</translation>
 <translation id="6284412385303060032">Hostiteľ spustený na obrazovke logiky konzoly bol ukončený, aby sa tým zaistil režim opony (curtain mode), a to prepnutím na hostiteľa spúšťaného v relácii konkrétneho používateľa</translation>
 <translation id="3596628256176442606">Táto služba povoľuje prichádzajúce pripojenia od klientov funkcie Chromoting.</translation>
-<translation id="1978866438647250517">• vylepšenia používateľského rozhrania,
-• znížené využitie siete pri spustení na pozadí.</translation>
 <translation id="4741792197137897469">Overenie zlyhalo. Prihláste sa do prehliadača Chrome a skúste to znova.</translation>
 <translation id="4277463233460010382">Tento počítač je nakonfigurovaný tak, aby povolil pripojenie jedného alebo viacerých klientov bez zadania kódu PIN.</translation>
 <translation id="837021510621780684">Z tohto počítača</translation>
diff --git a/remoting/resources/remoting_strings_sl.xtb b/remoting/resources/remoting_strings_sl.xtb
index f7833c0..6930ef9 100644
--- a/remoting/resources/remoting_strings_sl.xtb
+++ b/remoting/resources/remoting_strings_sl.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Ponastavite aplikacijo. Delo, ki ga niste shranili, bo izgubljeno.</translation>
 <translation id="6284412385303060032">Gostitelj, ki se je izvajal na zaslonu za prijavo v konzolo, se je zaustavil zaradi podpore načinu zavese, tako da je preklopil na gostitelja, ki se izvaja v seji uporabnika.</translation>
 <translation id="3596628256176442606">Ta storitev omogoča dohodne povezave iz odjemalcev za Oddaljeno povezovanje s Chromom.</translation>
-<translation id="1978866438647250517">• Izboljšave uporabniškega vmesnika.
-• Zmanjšanje porabe pasovne širine pri izvajanju v ozadju.</translation>
 <translation id="4741792197137897469">Preverjanje pristnosti ni uspelo. Še enkrat se prijavite v Chrome.</translation>
 <translation id="4277463233460010382">Ta računalnik je nastavljen tako, da enemu ali več odjemalcem dovoli povezovanje brez vnosa kode PIN.</translation>
 <translation id="837021510621780684">Iz tega računalnika</translation>
diff --git a/remoting/resources/remoting_strings_sr.xtb b/remoting/resources/remoting_strings_sr.xtb
index 8992f80..4a6eaaef 100644
--- a/remoting/resources/remoting_strings_sr.xtb
+++ b/remoting/resources/remoting_strings_sr.xtb
@@ -252,8 +252,6 @@
 <translation id="6570205395680337606">Ресетујте апликацију. Изгубићете све податке које нисте сачували.</translation>
 <translation id="6284412385303060032">Хост који је покренут на екрану за пријављивање на конзолу је искључен да би подржао режим завесе преласком на хоста који је покренут у сесији одређеног корисника.</translation>
 <translation id="3596628256176442606">Ова услуга омогућава долазне везе клијената Chromoting-а.</translation>
-<translation id="1978866438647250517">• Побољшања корисничког интерфејса.
-• Смањено коришћење мреже при раду у позадини.</translation>
 <translation id="4741792197137897469">Потврда аутентичности није успела. Пријавите се поново у Chrome.</translation>
 <translation id="4277463233460010382">Овај рачунар је конфигурисан тако да омогућава да се један клијент или више њих повезују без уношења PIN-а.</translation>
 <translation id="837021510621780684">Са овог рачунара</translation>
diff --git a/remoting/resources/remoting_strings_sv.xtb b/remoting/resources/remoting_strings_sv.xtb
index 2bd9e8a..5450705 100644
--- a/remoting/resources/remoting_strings_sv.xtb
+++ b/remoting/resources/remoting_strings_sv.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Återställ programmet. Ändringar som inte har sparats går förlorade.</translation>
 <translation id="6284412385303060032">Värden som kördes på konsolens inloggningsskärm har avslutats för att stödja Curtain Mode genom att byta till en värd som körs i en användarspecifik session.</translation>
 <translation id="3596628256176442606">Med den här tjänsten aktiveras inkommande anslutningar från Chromoting-klienter.</translation>
-<translation id="1978866438647250517">• Förbättringar i användargränssnittet.
-• Minskad nätverksanvändning när den körs i bakgrunden.</translation>
 <translation id="4741792197137897469">Autentiseringen misslyckades. Logga in i Chrome igen.</translation>
 <translation id="4277463233460010382">Den här datorn är konfigurerad för att tillåta att en eller flera klienter ansluter utan att en pinkod måste anges.</translation>
 <translation id="837021510621780684">Från den här datorn</translation>
diff --git a/remoting/resources/remoting_strings_th.xtb b/remoting/resources/remoting_strings_th.xtb
index 2ed347e..149f340 100644
--- a/remoting/resources/remoting_strings_th.xtb
+++ b/remoting/resources/remoting_strings_th.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">รีเซ็ตแอปพลิเคชัน คุณจะสูญเสียงานที่ไม่ได้บันทึกไว้ทั้งหมด</translation>
 <translation id="6284412385303060032">โฮสต์ที่ทำงานที่หน้าจอตรรกะของคอนโซลได้ปิดตัวลงเพื่อสนับสนุนโหมด Curtain โดยการเปลี่ยนไปเป็นโฮสต์ที่ทำงานในเซสชันเฉพาะผู้ใช้</translation>
 <translation id="3596628256176442606">บริการนี้จะช่วยให้สามารถใช้การเชื่อมต่อขาเข้าจากไคลเอ็นต์ Chromoting</translation>
-<translation id="1978866438647250517">• ปรับปรุงส่วนติดต่อผู้ใช้
-• ลดการใช้งานเครือข่ายเมื่อทำงานในพื้นหลัง</translation>
 <translation id="4741792197137897469">การตรวจสอบสิทธิ์ล้มเหลว โปรดลงชื่อเข้าใช้ Chrome อีกครั้ง</translation>
 <translation id="4277463233460010382">คอมพิวเตอร์เครื่องนี้ได้รับการกำหนดค่าให้อนุญาตไคลเอ็นต์หนึ่งหรือมากกว่าสามารถเชื่อมต่อโดยไม่ต้องป้อน PIN</translation>
 <translation id="837021510621780684">จากคอมพิวเตอร์เครื่องนี้</translation>
diff --git a/remoting/resources/remoting_strings_tr.xtb b/remoting/resources/remoting_strings_tr.xtb
index 897d320a..dca5da4 100644
--- a/remoting/resources/remoting_strings_tr.xtb
+++ b/remoting/resources/remoting_strings_tr.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Uygulamayı sıfırlayın. Kaydedilmemiş çalışmalarınızın tümünü kaybedeceksiniz.</translation>
 <translation id="6284412385303060032">Konsol mantık ekranında çalışan ana makine, kullanıcı tanımlı oturumda çalışan bir ana makineye geçerek perde modunu desteklemek için kapandı.</translation>
 <translation id="3596628256176442606">Bu hizmet Chromoting istemcilerinden gelen bağlantıları etkinleştirir.</translation>
-<translation id="1978866438647250517">• Kullanıcı arayüzü ile ilgili iyileştirmeler.
-• Arka planda çalışırken daha az ağ kullanımı.</translation>
 <translation id="4741792197137897469">Kimlik doğrulama başarısız oldu. Lütfen Chrome'da tekrar oturum açın.</translation>
 <translation id="4277463233460010382">Bu bilgisayar PIN girmeden bir veya daha fazla istemcinin bağlanmasına izin verecek şekilde yapılandırılmıştır.</translation>
 <translation id="837021510621780684">Bu bilgisayardan</translation>
diff --git a/remoting/resources/remoting_strings_uk.xtb b/remoting/resources/remoting_strings_uk.xtb
index 81482f6..b6e30e8 100644
--- a/remoting/resources/remoting_strings_uk.xtb
+++ b/remoting/resources/remoting_strings_uk.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Скинути дані додатка. Усі незбережені дані буде втрачено.</translation>
 <translation id="6284412385303060032">Хост на логічному екрані консолі вимкнувся. Щоб підтримати режим конфіденційності, зараз працює хост конкретного сеансу користувача.</translation>
 <translation id="3596628256176442606">Ця служба дозволяє встановлювати вхідні з’єднання з клієнтів Віддаленого доступу ОС Chrome.</translation>
-<translation id="1978866438647250517">• Покращено інтерфейс користувача.
-• Зменшено використання мережі під час роботи у фоновому режимі.</translation>
 <translation id="4741792197137897469">Помилка автентифікації. Увійдіть в обліковий запис Chrome знову.</translation>
 <translation id="4277463233460010382">На цьому комп’ютері одному чи кільком клієнтам дозволено під’єднуватися без PIN-коду.</translation>
 <translation id="837021510621780684">З цього комп’ютера</translation>
diff --git a/remoting/resources/remoting_strings_vi.xtb b/remoting/resources/remoting_strings_vi.xtb
index 49a18d0..b5bc8b1 100644
--- a/remoting/resources/remoting_strings_vi.xtb
+++ b/remoting/resources/remoting_strings_vi.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">Đặt lại ứng dụng. Bạn sẽ mất mọi công việc chưa lưu.</translation>
 <translation id="6284412385303060032">Máy chủ chạy trên màn hình logic của bảng điều khiển đã tắt để hỗ trợ chế độ màn bằng cách chuyển sang máy chủ chạy trong phiên dành riêng cho người dùng.</translation>
 <translation id="3596628256176442606">Dịch vụ này kích hoạt các kết nối đến từ ứng dụng khách kết nối từ xa trên Chrome.</translation>
-<translation id="1978866438647250517">• Cải thiện giao diện người dùng.
-• Giảm sử dụng mạng khi chạy trong nền.</translation>
 <translation id="4741792197137897469">Xác thực bị lỗi. Vui lòng đăng nhập lại vào Chrome.</translation>
 <translation id="4277463233460010382">Máy tính này được định cấu hình để cho phép một hoặc nhiều ứng dụng khách kết nối mà không cần nhập mã PIN.</translation>
 <translation id="837021510621780684">Từ máy tính này</translation>
diff --git a/remoting/resources/remoting_strings_zh-CN.xtb b/remoting/resources/remoting_strings_zh-CN.xtb
index c1f65bf6..702c233 100644
--- a/remoting/resources/remoting_strings_zh-CN.xtb
+++ b/remoting/resources/remoting_strings_zh-CN.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">重置该应用。所有未保存的工作都将会丢失。</translation>
 <translation id="6284412385303060032">在控制台逻辑屏幕运行的主机已关闭。这是为了切换到在用户特定会话中运行的主机,以便为 Curtain 模式提供支持。</translation>
 <translation id="3596628256176442606">此服务允许来自 Chrome 远程访问客户端的连接。</translation>
-<translation id="1978866438647250517">• 改进了用户界面。
-• 在后台运行时消耗的数据流量更少。</translation>
 <translation id="4741792197137897469">身份验证失败。请重新登录 Chrome。</translation>
 <translation id="4277463233460010382">此计算机已配置为允许一个或多个客户端无需输入 PIN 即可进行连接。</translation>
 <translation id="837021510621780684">来自此计算机</translation>
diff --git a/remoting/resources/remoting_strings_zh-TW.xtb b/remoting/resources/remoting_strings_zh-TW.xtb
index 2a952b0..7910118 100644
--- a/remoting/resources/remoting_strings_zh-TW.xtb
+++ b/remoting/resources/remoting_strings_zh-TW.xtb
@@ -254,8 +254,6 @@
 <translation id="6570205395680337606">重設應用程式。所有未儲存的變更都會遺失。</translation>
 <translation id="6284412385303060032">在控制台登入畫面執行的主機已關閉。這樣才能切換成在個別使用者工作階段中執行的主機,以支援帷幕模式。</translation>
 <translation id="3596628256176442606">這項服務允許來自 Chromoting 用戶端的連線。</translation>
-<translation id="1978866438647250517">• 改善使用者介面。
-• 在背景執行時減少網路使用量。</translation>
 <translation id="4741792197137897469">驗證失敗,請重新登入 Chrome。</translation>
 <translation id="4277463233460010382">這台電腦已設為允許一或多個用戶端可不輸入 PIN 進行連線。</translation>
 <translation id="837021510621780684">從這台電腦</translation>
diff --git a/remoting/webapp/base/js/client_plugin.js b/remoting/webapp/base/js/client_plugin.js
index 7a897f2..1044280 100644
--- a/remoting/webapp/base/js/client_plugin.js
+++ b/remoting/webapp/base/js/client_plugin.js
@@ -116,6 +116,13 @@
     function(mimeType, item) {};
 
 /**
+ * Notifies the plugin whether to send touch events to the host.
+ *
+ * @param {boolean} enable True if touch events should be sent.
+ */
+remoting.ClientPlugin.prototype.enableTouchEvents = function(enable) {};
+
+/**
  * Request that this client be paired with the current host.
  *
  * @param {string} clientName The human-readable name of the client.
diff --git a/remoting/webapp/base/js/client_plugin_impl.js b/remoting/webapp/base/js/client_plugin_impl.js
index c09db4f..cbe11b67 100644
--- a/remoting/webapp/base/js/client_plugin_impl.js
+++ b/remoting/webapp/base/js/client_plugin_impl.js
@@ -550,7 +550,7 @@
   // Cancel any existing remappings and apply the new ones.
   this.applyRemapKeys_(this.keyRemappings_, false);
   this.applyRemapKeys_(remappings, true);
-  this.keyRemappings_ = remappings;
+  this.keyRemappings_ = /** @type {!Object} */ (base.deepCopy(remappings));
 };
 
 /**
@@ -661,6 +661,16 @@
 };
 
 /**
+ * Notifies the plugin whether to send touch events to the host.
+ *
+ * @param {boolean} enable True if touch events should be sent.
+ */
+remoting.ClientPluginImpl.prototype.enableTouchEvents = function(enable) {
+  this.plugin_.postMessage(
+      JSON.stringify({method: 'enableTouchEvents', data: {'enable': enable}}));
+};
+
+/**
  * Notifies the host that the client has the specified size and pixel density.
  *
  * @param {number} width The available client width in DIPs.
diff --git a/remoting/webapp/base/js/client_session.js b/remoting/webapp/base/js/client_session.js
index 79056ab..294fe53 100644
--- a/remoting/webapp/base/js/client_session.js
+++ b/remoting/webapp/base/js/client_session.js
@@ -226,6 +226,11 @@
   // <1000 users on M-29 or below. Remove this and the capability on the host.
   RATE_LIMIT_RESIZE_REQUESTS: 'rateLimitResizeRequests',
 
+  // Indicates native touch input support. If the host does not support
+  // touch then the client will let Chrome synthesize mouse events from touch
+  // input, for compatibility with non-touch-aware systems.
+  TOUCH_EVENTS: 'touchEvents',
+
   // Indicates that host/client supports Google Drive integration, and that the
   // client should send to the host the OAuth tokens to be used by Google Drive
   // on the host.
@@ -529,6 +534,10 @@
 
   this.notifyStateChanges_(oldState, this.state_);
   this.logToServer_.logClientSessionStateChange(this.state_, this.error_);
+  if (this.plugin_.hasCapability(
+          remoting.ClientSession.Capability.TOUCH_EVENTS)) {
+    this.plugin_.enableTouchEvents(true);
+  }
 };
 
 /**
diff --git a/remoting/webapp/base/js/client_session_factory.js b/remoting/webapp/base/js/client_session_factory.js
index 24cfa2a..276f42610 100644
--- a/remoting/webapp/base/js/client_session_factory.js
+++ b/remoting/webapp/base/js/client_session_factory.js
@@ -23,7 +23,8 @@
   this.requiredCapabilities_ = [
     remoting.ClientSession.Capability.SEND_INITIAL_RESOLUTION,
     remoting.ClientSession.Capability.RATE_LIMIT_RESIZE_REQUESTS,
-    remoting.ClientSession.Capability.VIDEO_RECORDER
+    remoting.ClientSession.Capability.VIDEO_RECORDER,
+    remoting.ClientSession.Capability.TOUCH_EVENTS
   ];
 
   // Append the app-specific capabilities.
diff --git a/remoting/webapp/base/js/host.js b/remoting/webapp/base/js/host.js
index 48b6240..a7c7e8dc 100644
--- a/remoting/webapp/base/js/host.js
+++ b/remoting/webapp/base/js/host.js
@@ -99,7 +99,7 @@
       } else if (typeof(remappings) !== 'object') {
         remappings = {};
       }
-      that.remapKeys = remappings;
+      that.remapKeys = /** @type {!Object} */ (base.deepCopy(remappings));
     });
 };
 
diff --git a/remoting/webapp/base/js/platform.js b/remoting/webapp/base/js/platform.js
index 627edcc..8865c099 100644
--- a/remoting/webapp/base/js/platform.js
+++ b/remoting/webapp/base/js/platform.js
@@ -7,28 +7,33 @@
 /** @suppress {duplicate} */
 var remoting = remoting || {};
 
+/** @enum {string} */
+remoting.Os = {
+  WINDOWS: 'Windows',
+  LINUX: 'Linux',
+  MAC: 'Mac',
+  CHROMEOS: 'ChromeOS',
+  UNKNOWN: 'Unknown'
+};
+
+/**
+ * @typedef {{
+ *  osName: remoting.Os,
+ *  osVersion: string,
+ *  cpu: string,
+ *  chromeVersion: string
+ * }}
+ */
+remoting.SystemInfo;
+
+(function() {
+
 /**
  * Returns full Chrome version.
  * @return {string?}
  */
 remoting.getChromeVersion = function() {
-  var match = new RegExp('Chrome/([0-9.]*)').exec(navigator.userAgent);
-  if (match && (match.length >= 2)) {
-    return match[1];
-  }
-  return null;
-};
-
-/**
- * Returns Chrome major version.
- * @return {number}
- */
-remoting.getChromeMajorVersion = function() {
-  var match = new RegExp('Chrome/([0-9]+)\.').exec(navigator.userAgent);
-  if (match && (match.length >= 2)) {
-    return parseInt(match[1], 10);
-  }
-  return 0;
+  return remoting.getSystemInfo().chromeVersion;
 };
 
 /**
@@ -37,8 +42,8 @@
  * @return {boolean} True if the platform is Mac.
  */
 remoting.platformIsMac = function() {
-  return navigator.platform.indexOf('Mac') != -1;
-}
+  return remoting.getSystemInfo().osName === remoting.Os.MAC;
+};
 
 /**
  * Tests whether we are running on Windows.
@@ -46,9 +51,8 @@
  * @return {boolean} True if the platform is Windows.
  */
 remoting.platformIsWindows = function() {
-  return (navigator.platform.indexOf('Win32') != -1) ||
-         (navigator.platform.indexOf('Win64') != -1);
-}
+  return remoting.getSystemInfo().osName === remoting.Os.WINDOWS;
+};
 
 /**
  * Tests whether we are running on Linux.
@@ -56,9 +60,8 @@
  * @return {boolean} True if the platform is Linux.
  */
 remoting.platformIsLinux = function() {
-  return (navigator.platform.indexOf('Linux') != -1) &&
-         !remoting.platformIsChromeOS();
-}
+  return remoting.getSystemInfo().osName === remoting.Os.LINUX;
+};
 
 /**
  * Tests whether we are running on ChromeOS.
@@ -66,5 +69,70 @@
  * @return {boolean} True if the platform is ChromeOS.
  */
 remoting.platformIsChromeOS = function() {
-  return navigator.userAgent.match(/\bCrOS\b/) != null;
-}
+  return remoting.getSystemInfo().osName === remoting.Os.CHROMEOS;
+};
+
+/**
+ * @return {?remoting.SystemInfo}
+ */
+remoting.getSystemInfo = function() {
+  var userAgent = remoting.getUserAgent();
+
+  /** @type {remoting.SystemInfo} */
+  var result = {
+    chromeVersion: '',
+    osName: remoting.Os.UNKNOWN,
+    osVersion: '',
+    cpu: ''
+  };
+
+  // See platform_unittest.js for sample user agent strings.
+  var chromeVersion = new RegExp('Chrome/([0-9.]*)').exec(userAgent);
+  if (chromeVersion && chromeVersion.length >= 2) {
+    result.chromeVersion = chromeVersion[1];
+  }
+
+  var match = new RegExp('Windows NT ([0-9\\.]*)').exec(userAgent);
+  if (match && (match.length >= 2)) {
+    result.osName = remoting.Os.WINDOWS;
+    result.osVersion = match[1];
+    return result;
+  }
+
+  match = new RegExp('Linux ([a-zA-Z0-9_]*)').exec(userAgent);
+  if (match && (match.length >= 2)) {
+    result.osName = remoting.Os.LINUX;
+    result.osVersion = '';
+    result.cpu = match[1];
+    return result;
+  }
+
+  match = new RegExp('([a-zA-Z]*) Mac OS X ([0-9_]*)').exec(userAgent);
+  if (match && (match.length >= 3)) {
+    result.osName = remoting.Os.MAC;
+    result.osVersion = match[2].replace(/_/g, '.');
+    result.cpu = match[1];
+    return result;
+  }
+
+  match = new RegExp('CrOS ([a-zA-Z0-9_]*) ([0-9.]*)').exec(userAgent);
+  if (match && (match.length >= 3)) {
+    result.osName = remoting.Os.CHROMEOS;
+    result.osVersion = match[2];
+    result.cpu = match[1];
+    return result;
+  }
+  return null;
+};
+
+/**
+ * To be overwritten by unit test.
+ *
+ * @return {!string}
+ */
+remoting.getUserAgent = function() {
+  return navigator.userAgent;
+};
+
+})();
+
diff --git a/remoting/webapp/base/js/platform_unittest.js b/remoting/webapp/base/js/platform_unittest.js
new file mode 100644
index 0000000..74e9763e
--- /dev/null
+++ b/remoting/webapp/base/js/platform_unittest.js
@@ -0,0 +1,153 @@
+// 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.
+
+(function() {
+
+'use strict';
+
+var testData = [{
+    userAgent: 'Mozilla/5.0 (X11; CrOS x86_64 6457.107.0) AppleWebKit/537.36 ' +
+      '(KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36,gzip(gfe)',
+    osName: 'ChromeOS',
+    osVersion: '6457.107.0',
+    cpu: 'x86_64',
+    chromeVersion: '40.0.2214.115'
+  }, {
+    userAgent: 'Mozilla/5.0 (X11; CrOS i686 6812.88.0) AppleWebKit/537.36 ' +
+      '(KHTML, like Gecko) Chrome/42.0.2311.153 Safari/537.36,gzip(gfe)',
+    osName: 'ChromeOS',
+    osVersion: '6812.88.0',
+    cpu: 'i686',
+    chromeVersion: '42.0.2311.153'
+  }, {
+    userAgent: 'Mozilla/5.0 (X11; CrOS armv7l 6946.52.0) AppleWebKit/537.36 ' +
+      '(KHTML, like Gecko) Chrome/43.0.2357.73 Safari/537.36,gzip(gfe)',
+    osName: 'ChromeOS',
+    osVersion: '6946.52.0',
+    cpu: 'armv7l',
+    chromeVersion: '43.0.2357.73'
+  }, {
+    userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 ' +
+        '(KHTML, like Gecko) Chrome/45.0.2414.0 Safari/537.36,gzip(gfe)',
+    osName: 'Linux',
+    osVersion: '',
+    cpu: 'x86_64',
+    chromeVersion: '45.0.2414.0'
+  },{
+    userAgent: 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 ' +
+        '(KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36,gzip(gfe)',
+    osName: 'Windows',
+    osVersion: '6.1',
+    cpu: '',
+    chromeVersion: '43.0.2357.81'
+  },{
+    userAgent: 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 ' +
+      '(KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36,gzip(gfe)',
+    osName: 'Windows',
+    osVersion: '6.3',
+    cpu: '',
+    chromeVersion: '42.0.2311.152'
+  },{
+    userAgent: 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 ' +
+        '(KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36,gzip(gfe)',
+    osName: 'Windows',
+    osVersion: '6.3',
+    cpu: '',
+    chromeVersion: '43.0.2357.81'
+  }, {
+    userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '+
+      '(KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36,gzip(gfe)',
+    osName: 'Windows',
+    osVersion: '10.0',
+    cpu: '',
+    chromeVersion: '43.0.2357.81'
+  },{
+    userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit' +
+      '/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36,gzip(gfe)',
+    osName: 'Mac',
+    osVersion: '10.9.5',
+    cpu: 'Intel',
+    chromeVersion: '43.0.2357.81'
+  },{
+    userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit' +
+      '/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36,gzip(gfe)',
+    osName: 'Mac',
+    osVersion: '10.10.1',
+    cpu: 'Intel',
+    chromeVersion: '43.0.2357.81'
+  },{
+    userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit' +
+      '/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36,gzip(gfe)',
+    osName: 'Mac',
+    osVersion: '10.10.2',
+    cpu: 'Intel',
+    chromeVersion: '43.0.2357.81'
+  },{
+    userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit' +
+      '/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36,gzip(gfe)',
+    osName: 'Mac',
+    osVersion: '10.10.3',
+    cpu: 'Intel',
+    chromeVersion: '43.0.2357.81'
+  }
+];
+
+QUnit.module('platform');
+
+function forEachUserAgent(/** function(Object<string>, string) */ callback) {
+  testData.forEach(function(/** Object<string>*/ testCase) {
+    var message = 'userAgent: ' + testCase['userAgent']
+    var userAgentStub = sinon.stub(remoting, 'getUserAgent');
+    userAgentStub.returns(testCase['userAgent']);
+    var result = remoting.getSystemInfo();
+    callback(testCase, message);
+    userAgentStub.restore();
+  });
+}
+
+QUnit.test('OS name, OS version, chrome version and cpu detection',
+           function(assert) {
+  forEachUserAgent(
+      function(/** Object<string> */ testCase, /** string */ message) {
+        var result = remoting.getSystemInfo();
+        assert.equal(result.osName, testCase['osName'], message);
+        assert.equal(result.osVersion, testCase['osVersion'], message);
+        assert.equal(result.cpu, testCase['cpu'], message);
+        assert.equal(result.chromeVersion, testCase['chromeVersion'], message);
+  });
+});
+
+QUnit.test('platform is Mac', function(assert) {
+  forEachUserAgent(
+      function(/** Object<string> */ testCase, /** string */ message) {
+        assert.equal(remoting.platformIsMac(),
+                     testCase['osName'] === 'Mac', message);
+  });
+});
+
+QUnit.test('platform is Windows', function(assert) {
+  forEachUserAgent(
+      function(/** Object<string> */ testCase, /** string */ message) {
+        assert.equal(remoting.platformIsWindows(),
+                     testCase['osName'] === 'Windows', message);
+  });
+});
+
+QUnit.test('platform is Linux', function(assert) {
+  forEachUserAgent(
+      function(/** Object<string> */ testCase, /** string */ message) {
+        assert.equal(remoting.platformIsLinux(),
+                     testCase['osName'] === 'Linux', message);
+  });
+});
+
+QUnit.test('platform is ChromeOS', function(assert) {
+  forEachUserAgent(
+    function(/** Object<string> */ testCase, /** string */ message) {
+      assert.equal(remoting.platformIsChromeOS(),
+                   testCase['osName'] === 'ChromeOS', message);
+  });
+});
+
+})();
diff --git a/remoting/webapp/base/js/server_log_entry.js b/remoting/webapp/base/js/server_log_entry.js
index 3575129..0af065f 100644
--- a/remoting/webapp/base/js/server_log_entry.js
+++ b/remoting/webapp/base/js/server_log_entry.js
@@ -139,14 +139,6 @@
 
 /** @private */
 remoting.ServerLogEntry.KEY_OS_NAME_ = 'os-name';
-/** @private */
-remoting.ServerLogEntry.VALUE_OS_NAME_WINDOWS_ = 'Windows';
-/** @private */
-remoting.ServerLogEntry.VALUE_OS_NAME_LINUX_ = 'Linux';
-/** @private */
-remoting.ServerLogEntry.VALUE_OS_NAME_MAC_ = 'Mac';
-/** @private */
-remoting.ServerLogEntry.VALUE_OS_NAME_CHROMEOS_ = 'ChromeOS';
 
 /** @private */
 remoting.ServerLogEntry.KEY_OS_VERSION_ = 'os-version';
@@ -377,83 +369,21 @@
  * Adds fields describing the host to this log entry.
  */
 remoting.ServerLogEntry.prototype.addClientOSFields = function() {
-  var host = remoting.ServerLogEntry.getHostData_();
-  if (host) {
-    if (host.os_name.length > 0) {
-      this.set_(remoting.ServerLogEntry.KEY_OS_NAME_, host.os_name);
+  var systemInfo = remoting.getSystemInfo();
+  if (systemInfo) {
+    if (systemInfo.osName.length > 0) {
+      this.set_(remoting.ServerLogEntry.KEY_OS_NAME_, systemInfo.osName);
     }
-    if (host.os_version.length > 0) {
-      this.set_(remoting.ServerLogEntry.KEY_OS_VERSION_, host.os_version);
+    if (systemInfo.osVersion.length > 0) {
+      this.set_(remoting.ServerLogEntry.KEY_OS_VERSION_, systemInfo.osVersion);
     }
-    if (host.cpu.length > 0) {
-      this.set_(remoting.ServerLogEntry.KEY_CPU_, host.cpu);
+    if (systemInfo.cpu.length > 0) {
+      this.set_(remoting.ServerLogEntry.KEY_CPU_, systemInfo.cpu);
     }
   }
 };
 
 /**
- * Extracts host data from the userAgent string.
- *
- * @private
- * @return {{os_name:string, os_version:string, cpu:string} | null}
- */
-remoting.ServerLogEntry.getHostData_ = function() {
-  return remoting.ServerLogEntry.extractHostDataFrom_(navigator.userAgent);
-};
-
-/**
- * Extracts host data from the given userAgent string.
- *
- * @private
- * @param {string} s
- * @return {{os_name:string, os_version:string, cpu:string} | null}
- */
-remoting.ServerLogEntry.extractHostDataFrom_ = function(s) {
-  // Sample userAgent strings:
-  // 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 ' +
-  //   '(KHTML, like Gecko) Chrome/15.0.874.106 Safari/535.2'
-  // 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.8 ' +
-  //   '(KHTML, like Gecko) Chrome/17.0.933.0 Safari/535.8'
-  // 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 ' +
-  //   '(KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1'
-  // 'Mozilla/5.0 (X11; CrOS i686 14.811.154) AppleWebKit/535.1 ' +
-  //   '(KHTML, like Gecko) Chrome/14.0.835.204 Safari/535.1'
-  var match = new RegExp('Windows NT ([0-9\\.]*)').exec(s);
-  if (match && (match.length >= 2)) {
-    return {
-        'os_name': remoting.ServerLogEntry.VALUE_OS_NAME_WINDOWS_,
-        'os_version': match[1],
-        'cpu': ''
-    };
-  }
-  match = new RegExp('Linux ([a-zA-Z0-9_]*)').exec(s);
-  if (match && (match.length >= 2)) {
-    return {
-        'os_name': remoting.ServerLogEntry.VALUE_OS_NAME_LINUX_,
-        'os_version' : '',
-        'cpu': match[1]
-    };
-  }
-  match = new RegExp('([a-zA-Z]*) Mac OS X ([0-9_]*)').exec(s);
-  if (match && (match.length >= 3)) {
-    return {
-        'os_name': remoting.ServerLogEntry.VALUE_OS_NAME_MAC_,
-        'os_version': match[2].replace(/_/g, '.'),
-        'cpu': match[1]
-    };
-  }
-  match = new RegExp('CrOS ([a-zA-Z0-9]*) ([0-9.]*)').exec(s);
-  if (match && (match.length >= 3)) {
-    return {
-        'os_name': remoting.ServerLogEntry.VALUE_OS_NAME_CHROMEOS_,
-        'os_version': match[2],
-        'cpu': match[1]
-    };
-  }
-  return null;
-};
-
-/**
  * Adds a field to this log entry specifying the time in seconds since the start
  * of the session to the current event.
  * @param {number} sessionDurationInSeconds
diff --git a/remoting/webapp/build_template.gni b/remoting/webapp/build_template.gni
index c47eae7..9e8ab18 100644
--- a/remoting/webapp/build_template.gni
+++ b/remoting/webapp/build_template.gni
@@ -47,25 +47,30 @@
 }
 
 template("build_webapp_html") {
-  target_jscompile = "${target_name}_jscompile"
-  target_jscompile_stamp = "$target_gen_dir/${target_jscompile}.stamp"
-  action(target_jscompile) {
-    js_files = remoting_webapp_js_proto_files + invoker.js_files
+  target_jscompile = ""
 
-    script = "../../third_party/closure_compiler/compile.py"
-    inputs = js_files
-    outputs = [
-      target_jscompile_stamp,
-    ]
+  if (run_jscompile) {
+    target_jscompile = "${target_name}_jscompile"
+    target_jscompile_stamp = "$target_gen_dir/${target_jscompile}.stamp"
+    action(target_jscompile) {
+      js_files = remoting_webapp_js_proto_files + invoker.js_files
 
-    args = [
-             "--strict",
-             "--no-single-file",
-             "--externs",
-             "../../third_party/closure_compiler/externs/chrome_extensions.js",
-             "--success-stamp",
-             rebase_path(target_jscompile_stamp, root_build_dir),
-           ] + rebase_path(js_files, root_build_dir)
+      script = "../../third_party/closure_compiler/compile.py"
+      inputs = js_files
+      outputs = [
+        target_jscompile_stamp,
+      ]
+
+      args = [
+        "--strict",
+        "--no-single-file",
+        "--externs",
+        "../../third_party/closure_compiler/externs/chrome_extensions.js",
+        "--success-stamp",
+        rebase_path(target_jscompile_stamp, root_build_dir),
+      ]
+      args += rebase_path(js_files, root_build_dir)
+    }
   }
 
   action(target_name) {
@@ -82,7 +87,7 @@
       html_output,
     ]
 
-    if (run_jscompile) {
+    if (target_jscompile != "") {
       deps = [
         ":$target_jscompile",
       ]
diff --git a/remoting/webapp/crd/html/toolbar.html b/remoting/webapp/crd/html/toolbar.html
index 04b9cfe..ed2a1fa3 100644
--- a/remoting/webapp/crd/html/toolbar.html
+++ b/remoting/webapp/crd/html/toolbar.html
@@ -36,6 +36,8 @@
       <ul>
         <li id="send-ctrl-alt-del" i18n-content="SEND_CTRL_ALT_DEL"></li>
         <li id="send-print-screen" i18n-content="SEND_PRINT_SCREEN"></li>
+        <li id="map-right-ctrl-to-meta" i18n-content="MAP_RIGHT_CTRL_TO_META">
+        </li>
       </ul>
     </span>
 
diff --git a/remoting/webapp/crd/html/window_frame.html b/remoting/webapp/crd/html/window_frame.html
index f945483..4cddc950 100644
--- a/remoting/webapp/crd/html/window_frame.html
+++ b/remoting/webapp/crd/html/window_frame.html
@@ -18,6 +18,8 @@
             i18n-content="SEND_CTRL_ALT_DEL"></li>
         <li class="menu-send-print-screen"
             i18n-content="SEND_PRINT_SCREEN"></li>
+        <li class="menu-map-right-ctrl-to-meta"
+            i18n-content="MAP_RIGHT_CTRL_TO_META"></li>
         <li class="menu-separator"></li>
         <li class="menu-resize-to-client"
             i18n-content="RESIZE_TO_CLIENT"></li>
diff --git a/remoting/webapp/crd/js/desktop_connected_view.js b/remoting/webapp/crd/js/desktop_connected_view.js
index eced1b2..6e9df11f 100644
--- a/remoting/webapp/crd/js/desktop_connected_view.js
+++ b/remoting/webapp/crd/js/desktop_connected_view.js
@@ -106,6 +106,14 @@
   return false;
 };
 
+/**
+ * @return {boolean} True if the right-hand Ctrl key is mapped to the Meta
+ *     (Windows, Command) key.
+ */
+remoting.DesktopConnectedView.prototype.getMapRightCtrl = function() {
+  return this.host_.options.remapKeys[0x0700e4] === 0x0700e7;
+};
+
 remoting.DesktopConnectedView.prototype.toggleStats = function() {
   this.stats_.toggle();
 };
@@ -235,6 +243,25 @@
 };
 
 /**
+ * Set whether or not the right-hand Ctrl key should send the Meta (Windows,
+ * Command) key-code.
+ *
+ * @param {boolean} enable True to enable the mapping; false to disable.
+ */
+remoting.DesktopConnectedView.prototype.setMapRightCtrl = function(enable) {
+  if (enable === this.getMapRightCtrl()) {
+    return;  // In case right Ctrl is mapped, but not to right Meta.
+  }
+
+  if (enable) {
+    this.host_.options.remapKeys[0x0700e4] = 0x0700e7;
+  } else {
+    delete this.host_.options.remapKeys[0x0700e4]
+  }
+  this.setRemapKeys(this.host_.options.remapKeys);
+};
+
+/**
  * Sends a Ctrl-Alt-Del sequence to the remoting client.
  *
  * @return {void} Nothing.
@@ -263,7 +290,8 @@
 remoting.DesktopConnectedView.prototype.setRemapKeys = function(remappings) {
   this.plugin_.setRemapKeys(remappings);
   // Save the new remapping setting.
-  this.host_.options.remapKeys = remappings;
+  this.host_.options.remapKeys =
+      /** @type {!Object} */ (base.deepCopy(remappings));
   this.host_.options.save();
 };
 
diff --git a/remoting/webapp/crd/js/fullscreen_v2.js b/remoting/webapp/crd/js/fullscreen_v2.js
index d2fb26a45..616c77d 100644
--- a/remoting/webapp/crd/js/fullscreen_v2.js
+++ b/remoting/webapp/crd/js/fullscreen_v2.js
@@ -117,6 +117,11 @@
  */
 remoting.FullscreenAppsV2.prototype.onRestored_ = function() {
   if (!this.isMinimized_) {
+    // ChromeOS fires a spurious onRestored event going maximized->fullscreen.
+    // TODO(jamiewalch): Remove this work-around when crbug.com/394819 is fixed.
+    if (remoting.platformIsChromeOS() && this.isActive()) {
+      return;
+    }
     document.body.classList.remove('fullscreen');
     this.raiseEvent_(false);
   }
diff --git a/remoting/webapp/crd/js/mock_client_plugin.js b/remoting/webapp/crd/js/mock_client_plugin.js
index 68be5e1..29a9a90 100644
--- a/remoting/webapp/crd/js/mock_client_plugin.js
+++ b/remoting/webapp/crd/js/mock_client_plugin.js
@@ -109,6 +109,9 @@
 remoting.MockClientPlugin.prototype.sendClipboardItem =
     function(mimeType, item) {};
 
+remoting.MockClientPlugin.prototype.enableTouchEvents =
+    function(enable) {};
+
 remoting.MockClientPlugin.prototype.requestPairing =
     function(clientName, onDone) {};
 
@@ -292,4 +295,4 @@
   PIN: 'pin',
   THIRD_PARTY: 'thirdParty',
   PAIRING: 'pairing'
-};
\ No newline at end of file
+};
diff --git a/remoting/webapp/crd/js/options_menu.js b/remoting/webapp/crd/js/options_menu.js
index 6c855a8..705af5a2 100644
--- a/remoting/webapp/crd/js/options_menu.js
+++ b/remoting/webapp/crd/js/options_menu.js
@@ -15,6 +15,7 @@
 /**
  * @param {Element} sendCtrlAltDel
  * @param {Element} sendPrtScrn
+ * @param {Element} mapRightCtrl
  * @param {Element} resizeToClient
  * @param {Element} shrinkToFit
  * @param {Element} newConnection
@@ -23,12 +24,13 @@
  * @param {Element?} startStopRecording
  * @constructor
  */
-remoting.OptionsMenu = function(sendCtrlAltDel, sendPrtScrn,
+remoting.OptionsMenu = function(sendCtrlAltDel, sendPrtScrn, mapRightCtrl,
                                 resizeToClient, shrinkToFit,
                                 newConnection, fullscreen, toggleStats,
                                 startStopRecording) {
   this.sendCtrlAltDel_ = sendCtrlAltDel;
   this.sendPrtScrn_ = sendPrtScrn;
+  this.mapRightCtrl_ = mapRightCtrl;
   this.resizeToClient_ = resizeToClient;
   this.shrinkToFit_ = shrinkToFit;
   this.newConnection_ = newConnection;
@@ -43,6 +45,8 @@
       'click', this.onSendCtrlAltDel_.bind(this), false);
   this.sendPrtScrn_.addEventListener(
       'click', this.onSendPrtScrn_.bind(this), false);
+  this.mapRightCtrl_.addEventListener(
+      'click', this.onMapRightCtrl_.bind(this), false);
   this.resizeToClient_.addEventListener(
       'click', this.onResizeToClient_.bind(this), false);
   this.shrinkToFit_.addEventListener(
@@ -78,6 +82,10 @@
     var drApp = /** @type {remoting.DesktopRemoting} */ (remoting.app);
     var mode = drApp.getConnectionMode();
 
+    this.mapRightCtrl_.hidden = !remoting.platformIsChromeOS();
+    remoting.MenuButton.select(
+        this.mapRightCtrl_, this.desktopConnectedView_.getMapRightCtrl());
+
     this.resizeToClient_.hidden = mode === remoting.DesktopRemoting.Mode.IT2ME;
     remoting.MenuButton.select(
         this.resizeToClient_, this.desktopConnectedView_.getResizeToClient());
@@ -118,6 +126,13 @@
   }
 };
 
+remoting.OptionsMenu.prototype.onMapRightCtrl_ = function() {
+  if (this.desktopConnectedView_) {
+    this.desktopConnectedView_.setMapRightCtrl(
+        !this.desktopConnectedView_.getMapRightCtrl());
+  }
+};
+
 remoting.OptionsMenu.prototype.onResizeToClient_ = function() {
   if (this.desktopConnectedView_) {
     this.desktopConnectedView_.setScreenMode(
diff --git a/remoting/webapp/crd/js/toolbar.js b/remoting/webapp/crd/js/toolbar.js
index 73d26e8..f2338ff3 100644
--- a/remoting/webapp/crd/js/toolbar.js
+++ b/remoting/webapp/crd/js/toolbar.js
@@ -68,6 +68,7 @@
   return new remoting.OptionsMenu(
       document.getElementById('send-ctrl-alt-del'),
       document.getElementById('send-print-screen'),
+      document.getElementById('map-right-ctrl-to-meta'),
       document.getElementById('screen-resize-to-client'),
       document.getElementById('screen-shrink-to-fit'),
       document.getElementById('new-connection'),
diff --git a/remoting/webapp/crd/js/window_frame.js b/remoting/webapp/crd/js/window_frame.js
index fb4abb1..147d1ac 100644
--- a/remoting/webapp/crd/js/window_frame.js
+++ b/remoting/webapp/crd/js/window_frame.js
@@ -83,6 +83,7 @@
   return new remoting.OptionsMenu(
       this.titleBar_.querySelector('.menu-send-ctrl-alt-del'),
       this.titleBar_.querySelector('.menu-send-print-screen'),
+      this.titleBar_.querySelector('.menu-map-right-ctrl-to-meta'),
       this.titleBar_.querySelector('.menu-resize-to-client'),
       this.titleBar_.querySelector('.menu-shrink-to-fit'),
       this.titleBar_.querySelector('.menu-new-connection'),
diff --git a/remoting/webapp/files.gni b/remoting/webapp/files.gni
index 7b3a716..fbd68c77 100644
--- a/remoting/webapp/files.gni
+++ b/remoting/webapp/files.gni
@@ -85,6 +85,7 @@
   "base/js/identity_unittest.js",
   "base/js/ipc_unittest.js",
   "base/js/l10n_unittest.js",
+  "base/js/platform_unittest.js",
   "base/js/protocol_extension_manager_unittest.js",
   "base/js/typecheck_unittest.js",
   "base/js/viewport_unittest.js",
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 29ad879..45916bf 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -318,6 +318,18 @@
     "ext/skia_utils_win.h",
   ]
 
+  if (current_cpu == "x86" || current_cpu == "x64") {
+    sources += [
+      "ext/convolver_SSE2.cc",
+      "ext/convolver_SSE2.h",
+    ]
+  } else if (current_cpu == "mipsel" && mips_dsp_rev >= 2) {
+    sources += [
+      "ext/convolver_mips_dspr2.cc",
+      "ext/convolver_mips_dspr2.h",
+    ]
+  }
+
   # The skia gypi values are relative to the skia_dir, so we need to rebase.
   sources += gypi_skia_core.sources
   sources += gypi_skia_effects.sources
@@ -545,24 +557,54 @@
 }
 
 # Separated out so it can be compiled with different flags for SSE.
+if (current_cpu == "x86" || current_cpu == "x64") {
+  source_set("skia_opts_sse3") {
+    sources = gypi_skia_opts.ssse3_sources
+    if (!is_win || is_clang) {
+      cflags = [ "-mssse3" ]
+    }
+    if (is_win) {
+      defines = [ "SK_CPU_SSE_LEVEL=31" ]
+    }
+    visibility = [ ":skia_opts" ]
+    configs -= [ "//build/config/compiler:chromium_code" ]
+    configs += [
+      ":skia_config",
+      ":skia_library_config",
+      "//build/config/compiler:no_chromium_code",
+    ]
+  }
+  source_set("skia_opts_sse4") {
+    sources = gypi_skia_opts.sse41_sources
+    if (!is_win || is_clang) {
+      cflags = [ "-msse4.1" ]
+    }
+    if (is_win) {
+      defines = [ "SK_CPU_SSE_LEVEL=41" ]
+    }
+    visibility = [ ":skia_opts" ]
+    configs -= [ "//build/config/compiler:chromium_code" ]
+    configs += [
+      ":skia_config",
+      ":skia_library_config",
+      "//build/config/compiler:no_chromium_code",
+    ]
+  }
+}
 source_set("skia_opts") {
   cflags = []
   defines = []
 
-  if (current_cpu == "x86" || current_cpu == "x64") {
-    sources = gypi_skia_opts.sse2_sources + gypi_skia_opts.ssse3_sources +
-              gypi_skia_opts.sse41_sources +
-              [
-                # Chrome-specific.
-                "ext/convolver_SSE2.cc",
-                "ext/convolver_SSE2.h",
-              ]
+  deps = [
+    "//base",
+  ]
 
-    if (is_linux || is_mac) {
-      cflags += [ "-msse4.1" ]
-    } else if (is_win) {
-      defines += [ "SK_CPU_SSE_LEVEL=41" ]
-    }
+  if (current_cpu == "x86" || current_cpu == "x64") {
+    sources = gypi_skia_opts.sse2_sources
+    deps += [
+      ":skia_opts_sse3",
+      ":skia_opts_sse4",
+    ]
   } else if (current_cpu == "arm") {
     # The assembly uses the frame pointer register (r7 in Thumb/r11 in
     # ARM), the compiler doesn't like that.
@@ -588,13 +630,6 @@
 
     if (mips_dsp_rev >= 1) {
       sources = gypi_skia_opts.mips_dsp_sources
-      if (mips_dsp_rev >= 2) {
-        sources += [
-          # Chrome-specific.
-          "ext/convolver_mips_dspr2.cc",
-          "ext/convolver_mips_dspr2.h",
-        ]
-      }
     } else {
       sources = gypi_skia_opts.none_sources
     }
@@ -614,10 +649,6 @@
     "//build/config/compiler:no_chromium_code",
   ]
 
-  deps = [
-    "//base",
-  ]
-
   visibility = [ ":skia" ]
 }
 
diff --git a/skia/skia.gyp b/skia/skia.gyp
index 756baf7..8c0536b 100644
--- a/skia/skia.gyp
+++ b/skia/skia.gyp
@@ -88,37 +88,6 @@
   # targets that are not dependent upon the component type
   'targets': [
     {
-      'target_name': 'skia_chrome_opts',
-      'type': 'static_library',
-      'include_dirs': [
-        '..',
-        'config',
-        '../third_party/skia/include/core',
-      ],
-      'conditions': [
-        [ 'os_posix == 1 and OS != "mac" and OS != "android" and \
-            target_arch != "arm" and target_arch != "mipsel" and \
-            target_arch != "arm64" and target_arch != "mips64el"', {
-          'cflags': [
-            '-msse2',
-          ],
-        }],
-        [ 'target_arch != "arm" and target_arch != "mipsel" and \
-           target_arch != "arm64" and target_arch != "mips64el"', {
-          'sources': [
-            'ext/convolver_SSE2.cc',
-            'ext/convolver_SSE2.h',
-          ],
-        }],
-        [ 'target_arch == "mipsel" and mips_dsp_rev >= 2',{
-          'sources': [
-            'ext/convolver_mips_dspr2.cc',
-            'ext/convolver_mips_dspr2.h',
-          ],
-        }],
-      ],
-    },
-    {
       'target_name': 'image_operations_bench',
       'type': 'executable',
       'dependencies': [
diff --git a/skia/skia_chrome.gypi b/skia/skia_chrome.gypi
index d689a92..eb3f7e2 100644
--- a/skia/skia_chrome.gypi
+++ b/skia/skia_chrome.gypi
@@ -9,7 +9,6 @@
 {
   'dependencies': [
     'skia_library',
-    'skia_chrome_opts',
     '../base/base.gyp:base',
     '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
   ],
@@ -85,16 +84,24 @@
         'ext/skia_utils_base.cc',
       ],
     }],
-    ['OS == "ios"', {
-      'dependencies!': [
-        'skia_chrome_opts',
-      ],
-    }],
     [ 'OS != "android" and (OS != "linux" or use_cairo==1)', {
       'sources!': [
         'ext/bitmap_platform_device_skia.cc',
       ],
     }],
+    [ 'OS != "ios" and target_arch != "arm" and target_arch != "mipsel" and \
+       target_arch != "arm64" and target_arch != "mips64el"', {
+      'sources': [
+        'ext/convolver_SSE2.cc',
+        'ext/convolver_SSE2.h',
+      ],
+    }],
+    [ 'target_arch == "mipsel" and mips_dsp_rev >= 2',{
+      'sources': [
+        'ext/convolver_mips_dspr2.cc',
+        'ext/convolver_mips_dspr2.h',
+      ],
+    }],
   ],
 
   'target_conditions': [
diff --git a/skia/skia_library_opts.gyp b/skia/skia_library_opts.gyp
index 58f036f01..545ef17e 100644
--- a/skia/skia_library_opts.gyp
+++ b/skia/skia_library_opts.gyp
@@ -18,22 +18,10 @@
    },
 
   'targets': [
-    # Due to an unfortunate intersection of lameness between gcc and gyp,
-    # we have to build the *_SSE2.cpp files in a separate target.  The
-    # gcc lameness is that, in order to compile SSE2 intrinsics code, it
-    # must be passed the -msse2 flag.  However, with this flag, it may
-    # emit SSE2 instructions even for scalar code, such as the CPUID
-    # test used to test for the presence of SSE2.  So that, and all other
-    # code must be compiled *without* -msse2.  The gyp lameness is that it
-    # does not allow file-specific CFLAGS, so we must create this extra
-    # target for those files to be compiled with -msse2.
-    #
-    # This is actually only a problem on 32-bit Linux (all Intel Macs have
-    # SSE2, Linux x86_64 has SSE2 by definition, and MSC will happily emit
-    # SSE2 from instrinsics, which generating plain ol' 386 for everything
-    # else).  However, to keep the .gyp file simple and avoid platform-specific
-    # build breakage, we do this on all platforms.
-
+    # SSE files have to be built in a separate target, because gcc needs
+    # different -msse flags for different SSE levels which enable use of SSE
+    # intrinsics but also allow emission of SSE2 instructions for scalar code.
+    # gyp does not allow per-file compiler flags.
     # For about the same reason, we need to compile the ARM opts files
     # separately as well.
     {
@@ -49,13 +37,12 @@
       ],
       'include_dirs': [ '<@(include_dirs)' ],
       'conditions': [
-        [ 'os_posix == 1 and OS != "mac" and OS != "android" and \
-           target_arch != "arm" and target_arch != "arm64" and \
-           target_arch != "mipsel" and target_arch != "mips64el"', {
-          'cflags': [ '-msse2' ],
-        }],
         [ 'target_arch != "arm" and target_arch != "mipsel" and \
            target_arch != "arm64" and target_arch != "mips64el"', {
+          # Chrome builds with -msse2 locally, so sse2_sources could in theory
+          # be in the regular skia target. But we need skia_opts for arm
+          # anyway, so putting sse2_sources here is simpler than making this
+          # conditionally a type none target on x86.
           'sources': [ '<@(sse2_sources)' ],
           'dependencies': [
             'skia_opts_ssse3',
diff --git a/sync/api/sync_data.h b/sync/api/sync_data.h
index 6815896..e3885291 100644
--- a/sync/api/sync_data.h
+++ b/sync/api/sync_data.h
@@ -193,7 +193,7 @@
 };
 
 // gmock printer helper.
-void PrintTo(const SyncData& sync_data, std::ostream* os);
+void SYNC_EXPORT PrintTo(const SyncData& sync_data, std::ostream* os);
 
 typedef std::vector<SyncData> SyncDataList;
 
diff --git a/testing/buildbot/OWNERS b/testing/buildbot/OWNERS
index c3c145a1..c768380 100644
--- a/testing/buildbot/OWNERS
+++ b/testing/buildbot/OWNERS
@@ -3,12 +3,11 @@
 # and understand the implications of changing these files.
 set noparent
 
-cmp@chromium.org
-darin@chromium.org
 dpranke@chromium.org
 jam@chromium.org
 jochen@chromium.org
 machenbach@chromium.org
+maruel@chromium.org
 phajdan.jr@chromium.org
 sky@chromium.org
 thakis@chromium.org
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index b7067882..8509c57f 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -3471,7 +3471,7 @@
       {
         "args": [
           "--site-per-process",
-          "--gtest_filter=-*.DontPreemptNavigationWithFrameTreeUpdate:*.ProcessExitWithSwappedOutViews:*.SupportCrossProcessPostMessageWithMessagePort"
+          "--gtest_filter=-*.AllowTargetedNavigationsAfterSwap:*.DisownOpener:*.SupportCrossProcessPostMessageWithMessagePort"
         ],
         "test": "content_browsertests"
       },
@@ -3501,7 +3501,7 @@
       {
         "args": [
           "--site-per-process",
-          "--gtest_filter=-*.DontPreemptNavigationWithFrameTreeUpdate:*.ProcessExitWithSwappedOutViews:*.SupportCrossProcessPostMessageWithMessagePort"
+          "--gtest_filter=-*.AllowTargetedNavigationsAfterSwap:*.DisownOpener:*.SupportCrossProcessPostMessageWithMessagePort"
         ],
         "test": "content_browsertests"
       },
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 6a81d7e..a0d832f 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -3,12 +3,6 @@
     "additional_compile_targets": [
       "chrome_shell_apk",
       "mandoline:all"
-    ],
-    "scripts": [
-      {
-        "name": "gn_check",
-        "script": "gn_check.py"
-      }
     ]
   },
   "Android GN (dbg)": {
@@ -437,11 +431,6 @@
       "url_unittests",
       "views_unittests",
       "wm_unittests"
-    ],
-    "gtest_tests": [
-      {
-        "test": "base_unittests"
-      }
     ]
   },
   "Linux GN Clobber": {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index f3dcaed..55a95d0 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -533,11 +533,6 @@
       "url_unittests",
       "views_unittests",
       "wm_unittests"
-    ],
-    "gtest_tests": [
-      {
-        "test": "base_unittests"
-      }
     ]
   },
   "Win x64 GN (dbg)": {
@@ -591,11 +586,6 @@
       "url_unittests",
       "views_unittests",
       "wm_unittests"
-    ],
-    "gtest_tests": [
-      {
-        "test": "base_unittests"
-      }
     ]
   },
   "Win7 Tests (1)": {
@@ -1168,11 +1158,6 @@
       "url_unittests",
       "views_unittests",
       "wm_unittests"
-    ],
-    "gtest_tests": [
-      {
-        "test": "base_unittests"
-      }
     ]
   },
   "Win8 GN (dbg)": {
@@ -1226,11 +1211,6 @@
       "url_unittests",
       "views_unittests",
       "wm_unittests"
-    ],
-    "gtest_tests": [
-      {
-        "test": "base_unittests"
-      }
     ]
   },
   "XP Tests (1)": {
diff --git a/testing/buildbot/manage.py b/testing/buildbot/manage.py
index 0a4dee88..98de7ef4 100755
--- a/testing/buildbot/manage.py
+++ b/testing/buildbot/manage.py
@@ -36,6 +36,14 @@
   # http://crbug.com/441429
   'Linux Trusty (32)', 'Linux Trusty (dbg)(32)',
 
+  # http://crbug.com/480053
+  'Linux GN',
+  'linux_chromium_gn_rel',
+
+  # Unmaintained builders on chromium.fyi
+  'ClangToTMac',
+  'ClangToTMacASan',
+
   # One off builders. Note that Swarming does support ARM.
   'Linux ARM Cross-Compile',
   'Site Isolation Linux',
@@ -43,12 +51,8 @@
 }
 
 
-def upgrade_test(test):
-  """Converts from old style string to new style dict."""
-  if isinstance(test, basestring):
-    return {'test': test}
-  assert isinstance(test, dict)
-  return test
+class Error(Exception):
+  """Processing error."""
 
 
 def get_isolates():
@@ -57,33 +61,159 @@
   return [os.path.basename(f) for f in files if f.endswith('.isolate')]
 
 
+def process_builder_convert(data, filename, builder, test_name):
+  """Converts 'test_name' to run on Swarming in 'data'.
+
+  Returns True if 'test_name' was found.
+  """
+  result = False
+  for test in data['gtest_tests']:
+    if test['test'] != test_name:
+      continue
+    test.setdefault('swarming', {})
+    if not test['swarming'].get('can_use_on_swarming_builders'):
+      print('- %s: %s' % (filename, builder))
+      test['swarming']['can_use_on_swarming_builders'] = True
+    result = True
+  return result
+
+
+def process_builder_remaining(data, filename, builder, tests_location):
+  """Calculates tests_location when mode is --remaining."""
+  for test in data['gtest_tests']:
+    name = test['test']
+    if test.get('swarming', {}).get('can_use_on_swarming_builders'):
+      tests_location[name]['count_run_on_swarming'] += 1
+    else:
+      tests_location[name]['count_run_local'] += 1
+      tests_location[name]['local_configs'].setdefault(
+          filename, []).append(builder)
+
+
+def process_file(mode, test_name, tests_location, filepath):
+  """Processes a file.
+
+  The action depends on mode. Updates tests_location.
+
+  Return False if the process exit code should be 1.
+  """
+  filename = os.path.basename(filepath)
+  with open(filepath) as f:
+    content = f.read()
+  try:
+    config = json.loads(content)
+  except ValueError as e:
+    raise Error('Exception raised while checking %s: %s' % (filepath, e))
+
+  for builder, data in sorted(config.iteritems()):
+    if builder in SKIP:
+      # Oddities.
+      continue
+    if not isinstance(data, dict):
+      raise Error('%s: %s is broken: %s' % (filename, builder, data))
+    if 'gtest_tests' not in data:
+      continue
+    if not isinstance(data['gtest_tests'], list):
+      raise Error(
+          '%s: %s is broken: %s' % (filename, builder, data['gtest_tests']))
+    if not all(isinstance(g, dict) for g in data['gtest_tests']):
+      raise Error(
+          '%s: %s is broken: %s' % (filename, builder, data['gtest_tests']))
+
+    config[builder]['gtest_tests'] = sorted(
+        data['gtest_tests'], key=lambda x: x['test'])
+    if mode == 'remaining':
+      process_builder_remaining(data, filename, builder, tests_location)
+    elif mode == 'convert':
+      process_builder_convert(data, filename, builder, test_name)
+
+  expected = json.dumps(
+      config, sort_keys=True, indent=2, separators=(',', ': ')) + '\n'
+  if content != expected:
+    if mode in ('convert', 'write'):
+      with open(filepath, 'wb') as f:
+        f.write(expected)
+      if mode == 'write':
+        print('Updated %s' % filename)
+    else:
+      print('%s is not in canonical format' % filename)
+      print('run `testing/buildbot/manage.py -w` to fix')
+    return mode != 'check'
+  return True
+
+
+def print_remaining(test_name,tests_location):
+  """Prints a visual summary of what tests are yet to be converted to run on
+  Swarming.
+  """
+  if test_name:
+    if test_name not in tests_location:
+      raise Error('Unknown test %s' % test_name)
+    for config, builders in sorted(
+        tests_location[test_name]['local_configs'].iteritems()):
+      print('%s:' % config)
+      for builder in sorted(builders):
+        print('  %s' % builder)
+    return
+
+  isolates = get_isolates()
+  l = max(map(len, tests_location))
+  print('%-*s%sLocal       %sSwarming  %sMissing isolate' %
+      (l, 'Test', colorama.Fore.RED, colorama.Fore.GREEN,
+        colorama.Fore.MAGENTA))
+  total_local = 0
+  total_swarming = 0
+  for name, location in sorted(tests_location.iteritems()):
+    if not location['count_run_on_swarming']:
+      c = colorama.Fore.RED
+    elif location['count_run_local']:
+      c = colorama.Fore.YELLOW
+    else:
+      c = colorama.Fore.GREEN
+    total_local += location['count_run_local']
+    total_swarming += location['count_run_on_swarming']
+    missing_isolate = ''
+    if name + '.isolate' not in isolates:
+      missing_isolate = colorama.Fore.MAGENTA + '*'
+    print('%s%-*s %4d           %4d    %s' %
+        (c, l, name, location['count_run_local'],
+          location['count_run_on_swarming'], missing_isolate))
+
+  total = total_local + total_swarming
+  p_local = 100. * total_local / total
+  p_swarming = 100. * total_swarming / total
+  print('%s%-*s %4d (%4.1f%%)   %4d (%4.1f%%)' %
+      (colorama.Fore.WHITE, l, 'Total:', total_local, p_local,
+        total_swarming, p_swarming))
+  print('%-*s                %4d' % (l, 'Total executions:', total))
+
+
 def main():
   colorama.init()
   parser = argparse.ArgumentParser(description=sys.modules[__name__].__doc__)
   group = parser.add_mutually_exclusive_group(required=True)
   group.add_argument(
-      '-c', '--check', action='store_true', help='Only check the files')
+      '-c', '--check', dest='mode', action='store_const', const='check',
+      default='check', help='Only check the files')
   group.add_argument(
-      '--convert', action='store_true',
+      '--convert', dest='mode', action='store_const', const='convert',
       help='Convert a test to run on Swarming everywhere')
   group.add_argument(
-      '--remaining', action='store_true',
+      '--remaining', dest='mode', action='store_const', const='remaining',
       help='Count the number of tests not yet running on Swarming')
   group.add_argument(
-      '-w', '--write', action='store_true', help='Rewrite the files')
+      '-w', '--write', dest='mode', action='store_const', const='write',
+      help='Rewrite the files')
   parser.add_argument(
       'test_name', nargs='?',
       help='The test name to print which configs to update; only to be used '
            'with --remaining')
   args = parser.parse_args()
 
-  if args.convert or args.remaining:
-    isolates = get_isolates()
-
-  if args.convert:
+  if args.mode == 'convert':
     if not args.test_name:
       parser.error('A test name is required with --convert')
-    if args.test_name + '.isolate' not in isolates:
+    if args.test_name + '.isolate' not in get_isolates():
       parser.error('Create %s.isolate first' % args.test_name)
 
   # Stats when running in --remaining mode;
@@ -92,102 +222,18 @@
         'count_run_local': 0, 'count_run_on_swarming': 0, 'local_configs': {}
       })
 
-  result = 0
-  for filepath in glob.glob(os.path.join(THIS_DIR, '*.json')):
-    filename = os.path.basename(filepath)
-    with open(filepath) as f:
-      content = f.read()
-    try:
-      config = json.loads(content)
-    except ValueError as e:
-      print "Exception raised while checking %s: %s" % (filepath, e)
-      raise
-    for builder, data in sorted(config.iteritems()):
-      if builder in SKIP:
-        # Oddities.
-        continue
+  try:
+    result = 0
+    for filepath in glob.glob(os.path.join(THIS_DIR, '*.json')):
+      if not process_file(args.mode, args.test_name, tests_location, filepath):
+        result = 1
 
-      if not isinstance(data, dict):
-        print('%s: %s is broken: %s' % (filename, builder, data))
-        continue
-
-      if 'gtest_tests' in data:
-        config[builder]['gtest_tests'] = sorted(
-          (upgrade_test(l) for l in data['gtest_tests']),
-          key=lambda x: x['test'])
-
-        if args.remaining:
-          for test in data['gtest_tests']:
-            name = test['test']
-            if test.get('swarming', {}).get('can_use_on_swarming_builders'):
-              tests_location[name]['count_run_on_swarming'] += 1
-            else:
-              tests_location[name]['count_run_local'] += 1
-              tests_location[name]['local_configs'].setdefault(
-                  filename, []).append(builder)
-        elif args.convert:
-          for test in data['gtest_tests']:
-            if test['test'] != args.test_name:
-              continue
-            test.setdefault('swarming', {})
-            if not test['swarming'].get('can_use_on_swarming_builders'):
-              print('- %s: %s' % (filename, builder))
-              test['swarming']['can_use_on_swarming_builders'] = True
-
-    expected = json.dumps(
-        config, sort_keys=True, indent=2, separators=(',', ': ')) + '\n'
-    if content != expected:
-      result = 1
-      if args.write or args.convert:
-        with open(filepath, 'wb') as f:
-          f.write(expected)
-        if args.write:
-          print('Updated %s' % filename)
-      else:
-        print('%s is not in canonical format' % filename)
-        print('run `testing/buildbot/manage.py -w` to fix')
-
-  if args.remaining:
-    if args.test_name:
-      if args.test_name not in tests_location:
-        print('Unknown test %s' % args.test_name)
-        return 1
-      for config, builders in sorted(
-          tests_location[args.test_name]['local_configs'].iteritems()):
-        print('%s:' % config)
-        for builder in sorted(builders):
-          print('  %s' % builder)
-    else:
-      l = max(map(len, tests_location))
-      print('%-*s%sLocal       %sSwarming  %sMissing isolate' %
-          (l, 'Test', colorama.Fore.RED, colorama.Fore.GREEN,
-            colorama.Fore.MAGENTA))
-      total_local = 0
-      total_swarming = 0
-      for name, location in sorted(tests_location.iteritems()):
-        if not location['count_run_on_swarming']:
-          c = colorama.Fore.RED
-        elif location['count_run_local']:
-          c = colorama.Fore.YELLOW
-        else:
-          c = colorama.Fore.GREEN
-        total_local += location['count_run_local']
-        total_swarming += location['count_run_on_swarming']
-        missing_isolate = ''
-        if name + '.isolate' not in isolates:
-          missing_isolate = colorama.Fore.MAGENTA + '*'
-        print('%s%-*s %4d           %4d    %s' %
-            (c, l, name, location['count_run_local'],
-              location['count_run_on_swarming'], missing_isolate))
-
-      total = total_local + total_swarming
-      p_local = 100. * total_local / total
-      p_swarming = 100. * total_swarming / total
-      print('%s%-*s %4d (%4.1f%%)   %4d (%4.1f%%)' %
-          (colorama.Fore.WHITE, l, 'Total:', total_local, p_local,
-            total_swarming, p_swarming))
-      print('%-*s                %4d' % (l, 'Total executions:', total))
-  return result
+    if args.mode == 'remaining':
+      print_remaining(args.test_name, tests_location)
+    return result
+  except Error as e:
+    sys.stderr.write('%s\n' % e)
+    return 1
 
 
 if __name__ == "__main__":
diff --git a/testing/buildbot/tryserver.chromium.linux.json b/testing/buildbot/tryserver.chromium.linux.json
index a63bca9..876d8a5 100644
--- a/testing/buildbot/tryserver.chromium.linux.json
+++ b/testing/buildbot/tryserver.chromium.linux.json
@@ -3,20 +3,12 @@
     "additional_compile_targets": [
       "chrome_shell_apk",
       "mandoline:all"
-    ],
-    "gtest_tests": []
+    ]
   },
   "android_chromium_gn_compile_rel": {
     "additional_compile_targets": [
       "chrome_shell_apk",
       "mandoline:all"
-    ],
-    "gtest_tests": [],
-    "scripts": [
-      {
-        "name": "gn_check",
-        "script": "gn_check.py"
-      }
     ]
   },
   "linux_chromium_gn_chromeos_dbg": {
@@ -61,11 +53,6 @@
       "url_unittests",
       "views_unittests",
       "wm_unittests"
-    ],
-    "gtest_tests": [
-      {
-        "test": "base_unittests"
-      }
     ]
   },
   "linux_chromium_gn_chromeos_rel": {
@@ -113,11 +100,6 @@
       "url_unittests",
       "views_unittests",
       "wm_unittests"
-    ],
-    "gtest_tests": [
-      {
-        "test": "base_unittests"
-      }
     ]
   },
   "linux_chromium_gn_dbg": {
@@ -168,11 +150,6 @@
       "url_unittests",
       "views_unittests",
       "wm_unittests"
-    ],
-    "gtest_tests": [
-      {
-        "test": "base_unittests"
-      }
     ]
   },
   "linux_chromium_gn_rel": {
diff --git a/testing/buildbot/tryserver.chromium.win.json b/testing/buildbot/tryserver.chromium.win.json
index 14d7964..4142387 100644
--- a/testing/buildbot/tryserver.chromium.win.json
+++ b/testing/buildbot/tryserver.chromium.win.json
@@ -50,11 +50,6 @@
       "url_unittests",
       "views_unittests",
       "wm_unittests"
-    ],
-    "gtest_tests": [
-      {
-        "test": "base_unittests"
-      }
     ]
   },
   "win8_chromium_gn_rel": {
@@ -108,11 +103,6 @@
       "url_unittests",
       "views_unittests",
       "wm_unittests"
-    ],
-    "gtest_tests": [
-      {
-        "test": "base_unittests"
-      }
     ]
   },
   "win_chromium_gn_x64_dbg": {
@@ -166,11 +156,6 @@
       "url_unittests",
       "views_unittests",
       "wm_unittests"
-    ],
-    "gtest_tests": [
-      {
-        "test": "base_unittests"
-      }
     ]
   },
   "win_chromium_gn_x64_rel": {
@@ -224,11 +209,6 @@
       "url_unittests",
       "views_unittests",
       "wm_unittests"
-    ],
-    "gtest_tests": [
-      {
-        "test": "base_unittests"
-      }
     ]
   }
 }
diff --git a/testing/gtest_ios/unittest-Info.plist b/testing/gtest_ios/unittest-Info.plist
index f443580..6b3c094 100644
--- a/testing/gtest_ios/unittest-Info.plist
+++ b/testing/gtest_ios/unittest-Info.plist
@@ -22,6 +22,8 @@
 	<string>1.0</string>
 	<key>LSRequiresIPhoneOS</key>
 	<true/>
+	<key>NSMainNibFile</key>
+	<string>${MAIN_NIB_FILE}</string>
 	<key>UILaunchImages</key>
 	<array>
 		<dict>
@@ -104,6 +106,42 @@
 		<string>UIInterfaceOrientationLandscapeLeft</string>
 		<string>UIInterfaceOrientationLandscapeRight</string>
 	</array>
+	<key>CFBundleURLTypes</key>
+	<array>
+		<dict>
+			<key>CFBundleURLSchemes</key>
+			<array>
+				<string>com.google.sso.chrome</string>
+				<string>${BUNDLE_ID_TEST_NAME}.http</string>
+				<string>${BUNDLE_ID_TEST_NAME}.https</string>
+				<string>${BUNDLE_ID_TEST_NAME}-x-callback</string>
+			</array>
+		</dict>
+	</array>
+	<key>UTImportedTypeDeclarations</key>
+	<array>
+		<dict>
+			<key>UTTypeConformsTo</key>
+			<array>
+				<string>public.url</string>
+				<string>org.appextension.find-login-action</string>
+			</array>
+			<key>UTTypeDescription</key>
+			<string>Chrome Password Fill by App Extension Action</string>
+			<key>UTTypeIdentifier</key>
+			<string>org.appextension.chrome-password-action</string>
+		</dict>
+		<dict>
+			<key>UTTypeConformsTo</key>
+			<array>
+				<string>public.url</string>
+			</array>
+			<key>UTTypeDescription</key>
+			<string>1Password Find Login Action</string>
+			<key>UTTypeIdentifier</key>
+			<string>org.appextension.find-login-action</string>
+		</dict>
+	</array>
 	<key>UIBackgroundModes</key>
 	<array>
 		<string>fetch</string>
diff --git a/third_party/android_crazy_linker/README.chromium b/third_party/android_crazy_linker/README.chromium
index fa9158e..97147d2 100644
--- a/third_party/android_crazy_linker/README.chromium
+++ b/third_party/android_crazy_linker/README.chromium
@@ -76,3 +76,7 @@
 
 - Correct fix for crbug/479220 (replace IsSystemLibrary() with caller flags).
 
+- Fix link_map_.l_addr (was load address, should be load bias).
+
+- Convert packed relocation code to handle Android packed relocations.
+
diff --git a/third_party/android_crazy_linker/src/src/crazy_linker_elf_loader.cpp b/third_party/android_crazy_linker/src/src/crazy_linker_elf_loader.cpp
index a2e5fab2..e265ac3 100644
--- a/third_party/android_crazy_linker/src/src/crazy_linker_elf_loader.cpp
+++ b/third_party/android_crazy_linker/src/src/crazy_linker_elf_loader.cpp
@@ -193,7 +193,7 @@
     return false;
   }
 
-  uint8_t* addr = reinterpret_cast<uint8_t*>(min_vaddr);
+  uint8_t* addr = NULL;
   int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
 
   // Support loading at a fixed address.
diff --git a/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.cpp b/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.cpp
index 559c09e..5691ed3 100644
--- a/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.cpp
+++ b/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.cpp
@@ -4,6 +4,7 @@
 
 #include "crazy_linker_elf_relocations.h"
 
+#include <assert.h>
 #include <errno.h>
 
 #include "crazy_linker_debug.h"
@@ -32,6 +33,23 @@
 #define DT_FLAGS 30
 #endif
 
+// Extension dynamic tags for Android packed relocations.
+#ifndef DT_LOOS
+#define DT_LOOS 0x6000000d
+#endif
+#ifndef DT_ANDROID_REL
+#define DT_ANDROID_REL (DT_LOOS + 2)
+#endif
+#ifndef DT_ANDROID_RELSZ
+#define DT_ANDROID_RELSZ (DT_LOOS + 3)
+#endif
+#ifndef DT_ANDROID_RELA
+#define DT_ANDROID_RELA (DT_LOOS + 4)
+#endif
+#ifndef DT_ANDROID_RELASZ
+#define DT_ANDROID_RELASZ (DT_LOOS + 5)
+#endif
+
 // Processor-specific relocation types supported by the linker.
 #ifdef __arm__
 
@@ -168,9 +186,6 @@
   phdr_ = view->phdr();
   phdr_count_ = view->phdr_count();
   load_bias_ = view->load_bias();
-#if defined(__arm__) || defined(__aarch64__)
-  packed_relocations_ = view->packed_relocations();
-#endif
 
   // We handle only Rel or Rela, but not both. If DT_RELA or DT_RELASZ
   // then we require DT_PLTREL to agree.
@@ -231,6 +246,38 @@
         else
           has_rel_relocations = true;
         break;
+      case DT_ANDROID_RELA:
+      case DT_ANDROID_REL:
+        RLOG("  %s addr=%p\n",
+             (tag == DT_ANDROID_RELA) ? "DT_ANDROID_RELA" : "DT_ANDROID_REL",
+             dyn_addr);
+        if (android_relocations_) {
+          *error = "Unsupported DT_ANDROID_RELA/DT_ANDROID_REL "
+                   "combination in dynamic section";
+          return false;
+        }
+        android_relocations_ = reinterpret_cast<uint8_t*>(dyn_addr);
+        if (tag == DT_ANDROID_RELA)
+          has_rela_relocations = true;
+        else
+          has_rel_relocations = true;
+        break;
+      case DT_ANDROID_RELASZ:
+      case DT_ANDROID_RELSZ:
+        RLOG("  %s size=%d\n",
+             (tag == DT_ANDROID_RELASZ)
+                 ? "DT_ANDROID_RELASZ" : "DT_ANDROID_RELSZ", dyn_addr);
+        if (android_relocations_size_) {
+          *error = "Unsupported DT_ANDROID_RELASZ/DT_ANDROID_RELSZ "
+                   "combination in dyn section";
+          return false;
+        }
+        android_relocations_size_ = dyn_value;
+        if (tag == DT_ANDROID_RELASZ)
+          has_rela_relocations = true;
+        else
+          has_rel_relocations = true;
+        break;
       case DT_PLTGOT:
         // Only used on MIPS currently. Could also be used on other platforms
         // when lazy binding (i.e. RTLD_LAZY) is implemented.
@@ -250,7 +297,7 @@
           has_text_relocations_ = true;
         if (dyn_value & DF_SYMBOLIC)
           has_symbolic_ = true;
-        RLOG(" DT_FLAGS has_text_relocations=%s has_symbolic=%s\n",
+        RLOG("  DT_FLAGS has_text_relocations=%s has_symbolic=%s\n",
              has_text_relocations_ ? "true" : "false",
              has_symbolic_ ? "true" : "false");
         break;
@@ -276,7 +323,8 @@
   }
 
   if (has_rel_relocations && has_rela_relocations) {
-    *error = "Combining DT_REL and DT_RELA is not currently supported";
+    *error = "Combining relocations with and without addends is not "
+             "currently supported";
     return false;
   }
 
@@ -290,11 +338,13 @@
   }
 
   if (relocations_type_ == DT_REL && has_rela_relocations) {
-    *error = "Found DT_RELA in dyn section, but DT_PLTREL is DT_REL";
+    *error = "Found relocations with addends in dyn section, "
+             "but DT_PLTREL is DT_REL";
     return false;
   }
   if (relocations_type_ == DT_RELA && has_rel_relocations) {
-    *error = "Found DT_REL in dyn section, but DT_PLTREL is DT_RELA";
+    *error = "Found relocations without addends in dyn section, "
+             "but DT_PLTREL is DT_RELA";
     return false;
   }
 
@@ -313,10 +363,8 @@
     }
   }
 
-#if defined(__arm__) || defined(__aarch64__)
-  if (!ApplyPackedRelocations(error))
+  if (!ApplyAndroidRelocations(symbols, resolver, error))
     return false;
-#endif
 
   if (relocations_type_ == DT_REL) {
     if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(relocations_),
@@ -364,142 +412,189 @@
   return true;
 }
 
-#if defined(__arm__) || defined(__aarch64__)
+// Helper class for Android packed relocations.  Encapsulates the packing
+// flags used by Android for packed relocation groups.
+class AndroidPackedRelocationGroupFlags {
+ public:
+  explicit AndroidPackedRelocationGroupFlags(size_t flags) : flags_(flags) { }
 
-bool ElfRelocations::ForEachPackedRel(const uint8_t* packed_relocations,
-                                      RelRelocationHandler handler,
-                                      void* opaque) {
-  Leb128Decoder decoder(packed_relocations);
+  bool is_relocation_grouped_by_info() const {
+    return hasFlag(RELOCATION_GROUPED_BY_INFO_FLAG);
+  }
+  bool is_relocation_grouped_by_offset_delta() const {
+    return hasFlag(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG);
+  }
+  bool is_relocation_grouped_by_addend() const {
+    return hasFlag(RELOCATION_GROUPED_BY_ADDEND_FLAG);
+  }
+  bool is_relocation_group_has_addend() const {
+    return hasFlag(RELOCATION_GROUP_HAS_ADDEND_FLAG);
+  }
 
-  // Find the count of pairs and the start address.
-  size_t pairs = decoder.Dequeue();
-  const ELF::Addr start_address = decoder.Dequeue();
+ private:
+  bool hasFlag(size_t flag) const { return (flags_ & flag) != 0; }
 
-  // Emit initial relative relocation.
-  ELF::Rel relocation;
-  relocation.r_offset = start_address;
-  relocation.r_info = ELF_R_INFO(0, RELATIVE_RELOCATION_CODE);
-  const ELF::Addr sym_addr = 0;
-  const bool resolved = false;
-  if (!handler(this, &relocation, opaque))
+  static const size_t RELOCATION_GROUPED_BY_INFO_FLAG = 1 << 0;
+  static const size_t RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 1 << 1;
+  static const size_t RELOCATION_GROUPED_BY_ADDEND_FLAG = 1 << 2;
+  static const size_t RELOCATION_GROUP_HAS_ADDEND_FLAG = 1 << 3;
+
+  const size_t flags_;
+};
+
+bool ElfRelocations::ForEachAndroidRelocation(RelocationHandler handler,
+                                              void* opaque) {
+  // Skip over the "APS2" signature.
+  Sleb128Decoder decoder(android_relocations_ + 4,
+                         android_relocations_size_ - 4);
+
+  // Unpacking into a relocation with addend, both for REL and RELA, is
+  // convenient at this point. If REL, the handler needs to take care of
+  // any conversion before use.
+  ELF::Rela relocation;
+  memset(&relocation, 0, sizeof(relocation));
+
+  // Read the relocation count and initial offset.
+  const size_t relocation_count = decoder.pop_front();
+  relocation.r_offset = decoder.pop_front();
+
+  LOG("%s: relocation_count=%d, initial r_offset=%p\n",
+      __FUNCTION__,
+      relocation_count,
+      relocation.r_offset);
+
+  size_t relocations_handled = 0;
+  while (relocations_handled < relocation_count) {
+    // Read the start of the group header to obtain its size and flags.
+    const size_t group_size = decoder.pop_front();
+    AndroidPackedRelocationGroupFlags group_flags(decoder.pop_front());
+
+    // Read other group header fields, depending on the flags read above.
+    size_t group_r_offset_delta = 0;
+    if (group_flags.is_relocation_grouped_by_offset_delta())
+      group_r_offset_delta = decoder.pop_front();
+
+    if (group_flags.is_relocation_grouped_by_info())
+      relocation.r_info = decoder.pop_front();
+
+    if (group_flags.is_relocation_group_has_addend() &&
+        group_flags.is_relocation_grouped_by_addend())
+      relocation.r_addend += decoder.pop_front();
+    else if (!group_flags.is_relocation_group_has_addend())
+      relocation.r_addend = 0;
+
+    // Expand the group into individual relocations.
+    for (size_t group_index = 0; group_index < group_size; group_index++) {
+      if (group_flags.is_relocation_grouped_by_offset_delta())
+        relocation.r_offset += group_r_offset_delta;
+      else
+        relocation.r_offset += decoder.pop_front();
+
+      if (!group_flags.is_relocation_grouped_by_info())
+        relocation.r_info = decoder.pop_front();
+
+      if (group_flags.is_relocation_group_has_addend() &&
+          !group_flags.is_relocation_grouped_by_addend())
+        relocation.r_addend += decoder.pop_front();
+
+      // Pass the relocation to the supplied handler function. If the handler
+      // returns false we view this as failure and return false to our caller.
+      if (!handler(this, &relocation, opaque)) {
+        LOG("%s: failed handling relocation %d\n",
+            __FUNCTION__,
+            relocations_handled);
+        return false;
+      }
+
+      relocations_handled++;
+    }
+  }
+
+  LOG("%s: relocations_handled=%d\n", __FUNCTION__, relocations_handled);
+  return true;
+}
+
+namespace {
+
+// Validate the Android packed relocations signature.
+bool IsValidAndroidPackedRelocations(const uint8_t* android_relocations,
+                                     size_t android_relocations_size) {
+  if (android_relocations_size < 4)
     return false;
 
-  size_t unpacked_count = 1;
+  // Check for an initial APS2 Android packed relocations header.
+  return (android_relocations[0] == 'A' &&
+          android_relocations[1] == 'P' &&
+          android_relocations[2] == 'S' &&
+          android_relocations[3] == '2');
+}
 
-  // Emit relocations for each count-delta pair.
-  while (pairs) {
-    size_t count = decoder.Dequeue();
-    const size_t delta = decoder.Dequeue();
+// Narrow a Rela to its equivalent Rel. The r_addend field in the input
+// Rela must be zero.
+void ConvertRelaToRel(const ELF::Rela* rela, ELF::Rel* rel) {
+  assert(rela->r_addend == 0);
+  rel->r_offset = rela->r_offset;
+  rel->r_info = rela->r_info;
+}
 
-    // Emit count relative relocations with delta offset.
-    while (count) {
-      relocation.r_offset += delta;
-      if (!handler(this, &relocation, opaque))
-        return false;
-      unpacked_count++;
-      count--;
-    }
-    pairs--;
+}  // namespace
+
+// Args for ApplyAndroidRelocation handler function.
+struct ApplyAndroidRelocationArgs {
+  ELF::Addr relocations_type;
+  const ElfSymbols* symbols;
+  ElfRelocations::SymbolResolver* resolver;
+  Error* error;
+};
+
+// Static ForEachAndroidRelocation() handler.
+bool ElfRelocations::ApplyAndroidRelocation(ElfRelocations* relocations,
+                                            const ELF::Rela* relocation,
+                                            void* opaque) {
+  // Unpack args from opaque.
+  ApplyAndroidRelocationArgs* args =
+      reinterpret_cast<ApplyAndroidRelocationArgs*>(opaque);
+  const ELF::Addr relocations_type = args->relocations_type;
+  const ElfSymbols* symbols = args->symbols;
+  ElfRelocations::SymbolResolver* resolver = args->resolver;
+  Error* error = args->error;
+
+  // For REL relocations, convert from RELA to REL and apply the conversion.
+  // For RELA relocations, apply RELA directly.
+  if (relocations_type == DT_REL) {
+    ELF::Rel converted;
+    ConvertRelaToRel(relocation, &converted);
+    return relocations->ApplyRelReloc(&converted, symbols, resolver, error);
   }
 
-  RLOG("%s: unpacked_count=%d\n", __FUNCTION__, unpacked_count);
+  if (relocations_type == DT_RELA)
+    return relocations->ApplyRelaReloc(relocation, symbols, resolver, error);
+
   return true;
 }
 
-bool ElfRelocations::ForEachPackedRela(const uint8_t* packed_relocations,
-                                       RelaRelocationHandler handler,
-                                       void* opaque) {
-  Sleb128Decoder decoder(packed_relocations);
-
-  // Find the count of pairs.
-  size_t pairs = decoder.Dequeue();
-
-  ELF::Addr offset = 0;
-  ELF::Sxword addend = 0;
-
-  const ELF::Addr sym_addr = 0;
-  const bool resolved = false;
-
-  size_t unpacked_count = 0;
-
-  // Emit relocations for each deltas pair.
-  while (pairs) {
-    offset += decoder.Dequeue();
-    addend += decoder.Dequeue();
-
-    ELF::Rela relocation;
-    relocation.r_offset = offset;
-    relocation.r_info = ELF_R_INFO(0, RELATIVE_RELOCATION_CODE);
-    relocation.r_addend = addend;
-    if (!handler(this, &relocation, opaque))
-      return false;
-    unpacked_count++;
-    pairs--;
-  }
-
-  RLOG("%s: unpacked_count=%d\n", __FUNCTION__, unpacked_count);
-  return true;
-}
-
-bool ElfRelocations::ApplyPackedRel(ElfRelocations* relocations,
-                                    const ELF::Rel* relocation,
-                                    void* opaque) {
-  Error* error = reinterpret_cast<Error*>(opaque);
-  const ELF::Addr sym_addr = 0;
-  const bool resolved = false;
-  return relocations->ApplyRelReloc(relocation, sym_addr, resolved, error);
-}
-
-bool ElfRelocations::ApplyPackedRels(const uint8_t* packed_relocations,
-                                     Error* error) {
-  void* opaque = error;
-  return ForEachPackedRel(packed_relocations, &ApplyPackedRel, opaque);
-}
-
-bool ElfRelocations::ApplyPackedRela(ElfRelocations* relocations,
-                                     const ELF::Rela* relocation,
-                                     void* opaque) {
-  Error* error = reinterpret_cast<Error*>(opaque);
-  const ELF::Addr sym_addr = 0;
-  const bool resolved = false;
-  return relocations->ApplyRelaReloc(relocation, sym_addr, resolved, error);
-}
-
-bool ElfRelocations::ApplyPackedRelas(const uint8_t* packed_relocations,
-                                      Error* error) {
-  void* opaque = error;
-  return ForEachPackedRela(packed_relocations, &ApplyPackedRela, opaque);
-}
-
-bool ElfRelocations::ApplyPackedRelocations(Error* error) {
-  if (!packed_relocations_)
+bool ElfRelocations::ApplyAndroidRelocations(const ElfSymbols* symbols,
+                                             SymbolResolver* resolver,
+                                             Error* error) {
+  if (!android_relocations_)
     return true;
 
-  // Check for an initial APR1 header, packed relocations.
-  if (packed_relocations_[0] == 'A' &&
-      packed_relocations_[1] == 'P' &&
-      packed_relocations_[2] == 'R' &&
-      packed_relocations_[3] == '1') {
-    return ApplyPackedRels(packed_relocations_ + 4, error);
-  }
+  if (!IsValidAndroidPackedRelocations(android_relocations_,
+                                       android_relocations_size_))
+    return false;
 
-  // Check for an initial APA1 header, packed relocations with addend.
-  if (packed_relocations_[0] == 'A' &&
-      packed_relocations_[1] == 'P' &&
-      packed_relocations_[2] == 'A' &&
-      packed_relocations_[3] == '1') {
-    return ApplyPackedRelas(packed_relocations_ + 4, error);
-  }
-
-  error->Format("Bad packed relocations ident, expected APR1 or APA1");
-  return false;
+  ApplyAndroidRelocationArgs args;
+  args.relocations_type = relocations_type_;
+  args.symbols = symbols;
+  args.resolver = resolver;
+  args.error = error;
+  return ForEachAndroidRelocation(&ApplyAndroidRelocation, &args);
 }
-#endif  // __arm__ || __aarch64__
 
-bool ElfRelocations::ApplyRelaReloc(const ELF::Rela* rela,
-                                    ELF::Addr sym_addr,
-                                    bool resolved CRAZY_UNUSED,
-                                    Error* error) {
+bool ElfRelocations::ApplyResolvedRelaReloc(const ELF::Rela* rela,
+                                            ELF::Addr sym_addr,
+                                            bool resolved CRAZY_UNUSED,
+                                            Error* error) {
   const ELF::Word rela_type = ELF_R_TYPE(rela->r_info);
   const ELF::Word CRAZY_UNUSED rela_symbol = ELF_R_SYM(rela->r_info);
   const ELF::Sword CRAZY_UNUSED addend = rela->r_addend;
@@ -591,10 +686,10 @@
   return true;
 }
 
-bool ElfRelocations::ApplyRelReloc(const ELF::Rel* rel,
-                                   ELF::Addr sym_addr,
-                                   bool resolved CRAZY_UNUSED,
-                                   Error* error) {
+bool ElfRelocations::ApplyResolvedRelReloc(const ELF::Rel* rel,
+                                           ELF::Addr sym_addr,
+                                           bool resolved CRAZY_UNUSED,
+                                           Error* error) {
   const ELF::Word rel_type = ELF_R_TYPE(rel->r_info);
   const ELF::Word CRAZY_UNUSED rel_symbol = ELF_R_SYM(rel->r_info);
 
@@ -752,6 +847,43 @@
   return false;
 }
 
+bool ElfRelocations::ApplyRelReloc(const ELF::Rel* rel,
+                                   const ElfSymbols* symbols,
+                                   SymbolResolver* resolver,
+                                   Error* error) {
+  const ELF::Word rel_type = ELF_R_TYPE(rel->r_info);
+  const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info);
+
+  ELF::Addr sym_addr = 0;
+  ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_);
+  RLOG("  reloc=%p offset=%p type=%d symbol=%d\n",
+       reloc,
+       rel->r_offset,
+       rel_type,
+       rel_symbol);
+
+  if (rel_type == 0)
+    return true;
+
+  bool resolved = false;
+
+  // If this is a symbolic relocation, compute the symbol's address.
+  if (__builtin_expect(rel_symbol != 0, 0)) {
+    if (!ResolveSymbol(rel_type,
+                       rel_symbol,
+                       symbols,
+                       resolver,
+                       reloc,
+                       &sym_addr,
+                       error)) {
+      return false;
+    }
+    resolved = true;
+  }
+
+  return ApplyResolvedRelReloc(rel, sym_addr, resolved, error);
+}
+
 bool ElfRelocations::ApplyRelRelocs(const ELF::Rel* rel,
                                     size_t rel_count,
                                     const ElfSymbols* symbols,
@@ -763,45 +895,52 @@
     return true;
 
   for (size_t rel_n = 0; rel_n < rel_count; rel++, rel_n++) {
-    const ELF::Word rel_type = ELF_R_TYPE(rel->r_info);
-    const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info);
+    RLOG("  Relocation %d of %d:\n", rel_n + 1, rel_count);
 
-    ELF::Addr sym_addr = 0;
-    ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_);
-    RLOG("  %d/%d reloc=%p offset=%p type=%d symbol=%d\n",
-         rel_n + 1,
-         rel_count,
-         reloc,
-         rel->r_offset,
-         rel_type,
-         rel_symbol);
-
-    if (rel_type == 0)
-      continue;
-
-    bool resolved = false;
-
-    // If this is a symbolic relocation, compute the symbol's address.
-    if (__builtin_expect(rel_symbol != 0, 0)) {
-      if (!ResolveSymbol(rel_type,
-                         rel_symbol,
-                         symbols,
-                         resolver,
-                         reloc,
-                         &sym_addr,
-                         error)) {
-        return false;
-      }
-      resolved = true;
-    }
-
-    if (!ApplyRelReloc(rel, sym_addr, resolved, error))
+    if (!ApplyRelReloc(rel, symbols, resolver, error))
       return false;
   }
 
   return true;
 }
 
+bool ElfRelocations::ApplyRelaReloc(const ELF::Rela* rela,
+                                    const ElfSymbols* symbols,
+                                    SymbolResolver* resolver,
+                                    Error* error) {
+  const ELF::Word rel_type = ELF_R_TYPE(rela->r_info);
+  const ELF::Word rel_symbol = ELF_R_SYM(rela->r_info);
+
+  ELF::Addr sym_addr = 0;
+  ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_);
+  RLOG("  reloc=%p offset=%p type=%d symbol=%d\n",
+       reloc,
+       rela->r_offset,
+       rel_type,
+       rel_symbol);
+
+  if (rel_type == 0)
+    return true;
+
+  bool resolved = false;
+
+  // If this is a symbolic relocation, compute the symbol's address.
+  if (__builtin_expect(rel_symbol != 0, 0)) {
+    if (!ResolveSymbol(rel_type,
+                       rel_symbol,
+                       symbols,
+                       resolver,
+                       reloc,
+                       &sym_addr,
+                       error)) {
+      return false;
+    }
+    resolved = true;
+  }
+
+  return ApplyResolvedRelaReloc(rela, sym_addr, resolved, error);
+}
+
 bool ElfRelocations::ApplyRelaRelocs(const ELF::Rela* rela,
                                      size_t rela_count,
                                      const ElfSymbols* symbols,
@@ -813,39 +952,9 @@
     return true;
 
   for (size_t rel_n = 0; rel_n < rela_count; rela++, rel_n++) {
-    const ELF::Word rel_type = ELF_R_TYPE(rela->r_info);
-    const ELF::Word rel_symbol = ELF_R_SYM(rela->r_info);
+    RLOG("  Relocation %d of %d:\n", rel_n + 1, rela_count);
 
-    ELF::Addr sym_addr = 0;
-    ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_);
-    RLOG("  %d/%d reloc=%p offset=%p type=%d symbol=%d\n",
-         rel_n + 1,
-         rela_count,
-         reloc,
-         rela->r_offset,
-         rel_type,
-         rel_symbol);
-
-    if (rel_type == 0)
-      continue;
-
-    bool resolved = false;
-
-    // If this is a symbolic relocation, compute the symbol's address.
-    if (__builtin_expect(rel_symbol != 0, 0)) {
-      if (!ResolveSymbol(rel_type,
-                         rel_symbol,
-                         symbols,
-                         resolver,
-                         reloc,
-                         &sym_addr,
-                         error)) {
-        return false;
-      }
-      resolved = true;
-    }
-
-    if (!ApplyRelaReloc(rela, sym_addr, resolved, error))
+    if (!ApplyRelaReloc(rela, symbols, resolver, error))
       return false;
   }
 
@@ -941,115 +1050,90 @@
   }
 }
 
-#if defined(__arm__) || defined(__aarch64__)
+void ElfRelocations::AdjustAndroidRelocation(const ELF::Rela* relocation,
+                                             size_t src_addr,
+                                             size_t dst_addr,
+                                             size_t map_addr,
+                                             size_t size) {
+  // Add this value to each source address to get the corresponding
+  // destination address.
+  const size_t dst_delta = dst_addr - src_addr;
+  const size_t map_delta = map_addr - src_addr;
 
-struct AdjustRelocationArgs {
+  const ELF::Word rel_type = ELF_R_TYPE(relocation->r_info);
+  const ELF::Word rel_symbol = ELF_R_SYM(relocation->r_info);
+  ELF::Addr src_reloc =
+      static_cast<ELF::Addr>(relocation->r_offset + load_bias_);
+
+  if (rel_type == 0 || rel_symbol != 0) {
+    // Ignore empty and symbolic relocations
+    return;
+  }
+
+  if (src_reloc < src_addr || src_reloc >= src_addr + size) {
+    // Ignore entries that don't relocate addresses inside the source section.
+    return;
+  }
+
+  AdjustRelocation(rel_type, src_reloc, dst_delta, map_delta);
+}
+
+// Args for ApplyAndroidRelocation handler function.
+struct RelocateAndroidRelocationArgs {
   size_t src_addr;
   size_t dst_addr;
   size_t map_addr;
   size_t size;
 };
 
-template<typename Rel>
-bool ElfRelocations::RelocatePackedRelocation(ElfRelocations* relocations,
-                                              const Rel* rel,
-                                              void* opaque) {
-  AdjustRelocationArgs* args = reinterpret_cast<AdjustRelocationArgs*>(opaque);
+// Static ForEachAndroidRelocation() handler.
+bool ElfRelocations::RelocateAndroidRelocation(ElfRelocations* relocations,
+                                               const ELF::Rela* relocation,
+                                               void* opaque) {
+  // Unpack args from opaque, to obtain addrs and size;
+  RelocateAndroidRelocationArgs* args =
+      reinterpret_cast<RelocateAndroidRelocationArgs*>(opaque);
   const size_t src_addr = args->src_addr;
   const size_t dst_addr = args->dst_addr;
   const size_t map_addr = args->map_addr;
   const size_t size = args->size;
 
-  const size_t load_bias = relocations->load_bias_;
-
-  const size_t dst_delta = dst_addr - src_addr;
-  const size_t map_delta = map_addr - src_addr;
-
-  const ELF::Word rel_type = ELF_R_TYPE(rel->r_info);
-  const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info);
-  ELF::Addr src_reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias);
-
-  if (rel_type == 0 || rel_symbol != 0) {
-    // Ignore empty and symbolic relocations
-    return true;
-  }
-
-  if (src_reloc < src_addr || src_reloc >= src_addr + size) {
-    // Ignore entries that don't relocate addresses inside the source section.
-    return true;
-  }
-
-  relocations->AdjustRelocation(rel_type, src_reloc, dst_delta, map_delta);
+  // Relocate the given relocation.  Because the r_addend field is ignored
+  // in relocating RELA relocations we do not need to convert from REL to
+  // RELA and supply alternative relocator functions; instead we can work
+  // here directly on the RELA supplied by ForEachAndroidRelocation(), even
+  // on REL architectures.
+  relocations->AdjustAndroidRelocation(relocation,
+                                       src_addr,
+                                       dst_addr,
+                                       map_addr,
+                                       size);
   return true;
 }
 
-template bool ElfRelocations::RelocatePackedRelocation<ELF::Rel>(
-    ElfRelocations* relocations, const ELF::Rel* rel, void* opaque);
+void ElfRelocations::RelocateAndroidRelocations(size_t src_addr,
+                                                size_t dst_addr,
+                                                size_t map_addr,
+                                                size_t size) {
+  if (!android_relocations_)
+    return;
 
-template bool ElfRelocations::RelocatePackedRelocation<ELF::Rela>(
-    ElfRelocations* relocations, const ELF::Rela* rel, void* opaque);
+  assert(IsValidAndroidPackedRelocations(android_relocations_,
+                                         android_relocations_size_));
 
-void ElfRelocations::RelocatePackedRels(const uint8_t* packed_relocations,
-                                        size_t src_addr,
-                                        size_t dst_addr,
-                                        size_t map_addr,
-                                        size_t size) {
-  AdjustRelocationArgs args;
+  RelocateAndroidRelocationArgs args;
   args.src_addr = src_addr;
   args.dst_addr = dst_addr;
   args.map_addr = map_addr;
   args.size = size;
-  ForEachPackedRel(packed_relocations,
-                   &RelocatePackedRelocation<ELF::Rel>, &args);
+  ForEachAndroidRelocation(&RelocateAndroidRelocation, &args);
 }
 
-void ElfRelocations::RelocatePackedRelas(const uint8_t* packed_relocations,
-                                         size_t src_addr,
+template<typename Rel>
+void ElfRelocations::RelocateRelocations(size_t src_addr,
                                          size_t dst_addr,
                                          size_t map_addr,
                                          size_t size) {
-  AdjustRelocationArgs args;
-  args.src_addr = src_addr;
-  args.dst_addr = dst_addr;
-  args.map_addr = map_addr;
-  args.size = size;
-  ForEachPackedRela(packed_relocations,
-                    &RelocatePackedRelocation<ELF::Rela>, &args);
-}
-
-void ElfRelocations::RelocatePackedRelocations(size_t src_addr,
-                                               size_t dst_addr,
-                                               size_t map_addr,
-                                               size_t size) {
-  if (!packed_relocations_)
-    return;
-
-  // Check for an initial APR1 header, packed relocations.
-  if (packed_relocations_[0] == 'A' &&
-      packed_relocations_[1] == 'P' &&
-      packed_relocations_[2] == 'R' &&
-      packed_relocations_[3] == '1') {
-    RelocatePackedRels(packed_relocations_ + 4,
-                       src_addr, dst_addr, map_addr, size);
-  }
-
-  // Check for an initial APA1 header, packed relocations with addend.
-  if (packed_relocations_[0] == 'A' &&
-      packed_relocations_[1] == 'P' &&
-      packed_relocations_[2] == 'A' &&
-      packed_relocations_[3] == '1') {
-    RelocatePackedRelas(packed_relocations_ + 4,
-                        src_addr, dst_addr, map_addr, size);
-  }
-}
-
-#endif  // __arm__ || __aarch64__
-
-template<typename Rel>
-void ElfRelocations::RelocateRelocation(size_t src_addr,
-                                        size_t dst_addr,
-                                        size_t map_addr,
-                                        size_t size) {
   // Add this value to each source address to get the corresponding
   // destination address.
   const size_t dst_delta = dst_addr - src_addr;
@@ -1079,10 +1163,10 @@
   }
 }
 
-template void ElfRelocations::RelocateRelocation<ELF::Rel>(
+template void ElfRelocations::RelocateRelocations<ELF::Rel>(
     size_t src_addr, size_t dst_addr, size_t map_addr, size_t size);
 
-template void ElfRelocations::RelocateRelocation<ELF::Rela>(
+template void ElfRelocations::RelocateRelocations<ELF::Rela>(
     size_t src_addr, size_t dst_addr, size_t map_addr, size_t size);
 
 void ElfRelocations::CopyAndRelocate(size_t src_addr,
@@ -1094,17 +1178,15 @@
            reinterpret_cast<void*>(src_addr),
            size);
 
-#if defined(__arm__) || defined(__aarch64__)
-  // Relocate packed relative relocations.
-  RelocatePackedRelocations(src_addr, dst_addr, map_addr, size);
-#endif
+  // Relocate android relocations.
+  RelocateAndroidRelocations(src_addr, dst_addr, map_addr, size);
 
   // Relocate relocations.
   if (relocations_type_ == DT_REL)
-    RelocateRelocation<ELF::Rel>(src_addr, dst_addr, map_addr, size);
+    RelocateRelocations<ELF::Rel>(src_addr, dst_addr, map_addr, size);
 
   if (relocations_type_ == DT_RELA)
-    RelocateRelocation<ELF::Rela>(src_addr, dst_addr, map_addr, size);
+    RelocateRelocations<ELF::Rela>(src_addr, dst_addr, map_addr, size);
 
 #ifdef __mips__
   // Add this value to each source address to get the corresponding
diff --git a/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.h b/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.h
index d57c90f..1c7c15b 100644
--- a/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.h
+++ b/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.h
@@ -64,13 +64,21 @@
                      ELF::Addr reloc,
                      ELF::Addr* sym_addr,
                      Error* error);
+  bool ApplyResolvedRelaReloc(const ELF::Rela* rela,
+                              ELF::Addr sym_addr,
+                              bool resolved,
+                              Error* error);
+  bool ApplyResolvedRelReloc(const ELF::Rel* rel,
+                             ELF::Addr sym_addr,
+                             bool resolved,
+                             Error* error);
   bool ApplyRelaReloc(const ELF::Rela* rela,
-                      ELF::Addr sym_addr,
-                      bool resolved,
+                      const ElfSymbols* symbols,
+                      SymbolResolver* resolver,
                       Error* error);
   bool ApplyRelReloc(const ELF::Rel* rel,
-                     ELF::Addr sym_addr,
-                     bool resolved,
+                     const ElfSymbols* symbols,
+                     SymbolResolver* resolver,
                      Error* error);
   bool ApplyRelaRelocs(const ELF::Rela* relocs,
                        size_t relocs_count,
@@ -87,68 +95,43 @@
                         size_t dst_delta,
                         size_t map_delta);
   template<typename Rel>
-  void RelocateRelocation(size_t src_addr,
+  void RelocateRelocations(size_t src_addr,
                           size_t dst_addr,
                           size_t map_addr,
                           size_t size);
+  void AdjustAndroidRelocation(const ELF::Rela* relocation,
+                               size_t src_addr,
+                               size_t dst_addr,
+                               size_t map_addr,
+                               size_t size);
 
-#if defined(__arm__) || defined(__aarch64__)
-  // Packed relocations unpackers. Call the given handler for each
-  // relocation in the unpacking stream. There are two versions, one
-  // for REL, the other for RELA.
-  typedef bool (*RelRelocationHandler)(ElfRelocations* relocations,
-                                       const ELF::Rel* relocation,
-                                       void* opaque);
-  bool ForEachPackedRel(const uint8_t* packed_relocations,
-                        RelRelocationHandler handler,
-                        void* opaque);
+  // Android packed relocations unpacker. Calls the given handler for
+  // each relocation in the unpacking stream.
+  typedef bool (*RelocationHandler)(ElfRelocations* relocations,
+                                    const ELF::Rela* relocation,
+                                    void* opaque);
+  bool ForEachAndroidRelocation(RelocationHandler handler,
+                                void* opaque);
 
-  typedef bool (*RelaRelocationHandler)(ElfRelocations* relocations,
+  // Apply Android packed relocations.
+  // On error, return false and set |error| message.
+  // The static function is the ForEachAndroidRelocation() handler.
+  bool ApplyAndroidRelocations(const ElfSymbols* symbols,
+                               SymbolResolver* resolver,
+                               Error* error);
+  static bool ApplyAndroidRelocation(ElfRelocations* relocations,
+                                     const ELF::Rela* relocation,
+                                     void* opaque);
+
+  // Relocate Android packed relocations.
+  // The static function is the ForEachAndroidRelocation() handler.
+  void RelocateAndroidRelocations(size_t src_addr,
+                                  size_t dst_addr,
+                                  size_t map_addr,
+                                  size_t size);
+  static bool RelocateAndroidRelocation(ElfRelocations* relocations,
                                         const ELF::Rela* relocation,
                                         void* opaque);
-  bool ForEachPackedRela(const uint8_t* packed_relocations,
-                         RelaRelocationHandler handler,
-                         void* opaque);
-
-  // Apply packed REL and RELA relocations.  On error, return false.
-  bool ApplyPackedRels(const uint8_t* packed_relocations, Error* error);
-  static bool ApplyPackedRel(ElfRelocations* relocations,
-                             const ELF::Rel* relocation,
-                             void* opaque);
-  bool ApplyPackedRelas(const uint8_t* packed_relocations, Error* error);
-  static bool ApplyPackedRela(ElfRelocations* relocations,
-                              const ELF::Rela* relocation,
-                              void* opaque);
-
-  // Apply all packed relocations.
-  // On error, return false and set |error| message.  No-op if no packed
-  // relocations are present.
-  bool ApplyPackedRelocations(Error* error);
-
-  // Relocate packed REL and RELA relocations.
-  template<typename Rel>
-  static bool RelocatePackedRelocation(ElfRelocations* relocations,
-                                       const Rel* rel,
-                                       void* opaque);
-
-  void RelocatePackedRels(const uint8_t* packed_relocations,
-                          size_t src_addr,
-                          size_t dst_addr,
-                          size_t map_addr,
-                          size_t size);
-  void RelocatePackedRelas(const uint8_t* packed_relocations,
-                           size_t src_addr,
-                           size_t dst_addr,
-                           size_t map_addr,
-                           size_t size);
-
-  // Relocate all packed relocations. No-op if no packed relocations
-  // are present.
-  void RelocatePackedRelocations(size_t src_addr,
-                                 size_t dst_addr,
-                                 size_t map_addr,
-                                 size_t size);
-#endif
 
 #if defined(__mips__)
   bool RelocateMipsGot(const ElfSymbols* symbols,
@@ -175,9 +158,8 @@
   ELF::Word mips_gotsym_;
 #endif
 
-#if defined(__arm__) || defined(__aarch64__)
-  uint8_t* packed_relocations_;
-#endif
+  uint8_t* android_relocations_;
+  size_t android_relocations_size_;
 
   bool has_text_relocations_;
   bool has_symbolic_;
diff --git a/third_party/android_crazy_linker/src/src/crazy_linker_leb128.h b/third_party/android_crazy_linker/src/src/crazy_linker_leb128.h
index 0888d77c..787566e 100644
--- a/third_party/android_crazy_linker/src/src/crazy_linker_leb128.h
+++ b/third_party/android_crazy_linker/src/src/crazy_linker_leb128.h
@@ -5,6 +5,7 @@
 #ifndef CRAZY_LINKER_LEB128_H
 #define CRAZY_LINKER_LEB128_H
 
+#include <assert.h>
 #include <stdint.h>
 
 // Helper classes for decoding LEB128, used in packed relocation data.
@@ -12,58 +13,36 @@
 
 namespace crazy {
 
-class Leb128Decoder {
- public:
-  explicit Leb128Decoder(const uint8_t* encoding)
-      : encoding_(encoding), cursor_(0) { }
-
-  size_t Dequeue() {
-    size_t value = 0;
-
-    size_t shift = 0;
-    uint8_t byte;
-
-    do {
-      byte = encoding_[cursor_++];
-      value |= static_cast<size_t>(byte & 127) << shift;
-      shift += 7;
-    } while (byte & 128);
-
-    return value;
-  }
-
- private:
-  const uint8_t* encoding_;
-  size_t cursor_;
-};
-
 class Sleb128Decoder {
  public:
-  explicit Sleb128Decoder(const uint8_t* encoding)
-      : encoding_(encoding), cursor_(0) { }
+  Sleb128Decoder(const uint8_t* buffer, size_t count)
+      : current_(buffer), end_(buffer + count) { }
 
-  ssize_t Dequeue() {
-    ssize_t value = 0;
+  size_t pop_front() {
+    size_t value = 0;
     static const size_t size = CHAR_BIT * sizeof(value);
 
     size_t shift = 0;
     uint8_t byte;
 
     do {
-      byte = encoding_[cursor_++];
-      value |= (static_cast<ssize_t>(byte & 127) << shift);
+      assert(current_ < end_);
+
+      byte = *current_++;
+      value |= (static_cast<size_t>(byte & 127) << shift);
       shift += 7;
     } while (byte & 128);
 
-    if (shift < size && (byte & 64))
-      value |= -(static_cast<ssize_t>(1) << shift);
+    if (shift < size && (byte & 64)) {
+      value |= -(static_cast<size_t>(1) << shift);
+    }
 
     return value;
   }
 
  private:
-  const uint8_t* encoding_;
-  size_t cursor_;
+  const uint8_t* current_;
+  const uint8_t* const end_;
 };
 
 }  // namespace crazy
diff --git a/third_party/android_crazy_linker/src/src/crazy_linker_library_list.cpp b/third_party/android_crazy_linker/src/src/crazy_linker_library_list.cpp
index f4acadb..0bc3689 100644
--- a/third_party/android_crazy_linker/src/src/crazy_linker_library_list.cpp
+++ b/third_party/android_crazy_linker/src/src/crazy_linker_library_list.cpp
@@ -431,7 +431,7 @@
     return NULL;
 
   // Notify GDB of load.
-  lib->link_map_.l_addr = lib->load_address();
+  lib->link_map_.l_addr = lib->load_bias();
   lib->link_map_.l_name = const_cast<char*>(lib->base_name_);
   lib->link_map_.l_ld = reinterpret_cast<uintptr_t>(lib->view_.dynamic());
   Globals::GetRDebug()->AddEntry(&lib->link_map_);
diff --git a/third_party/android_crazy_linker/src/src/crazy_linker_shared_library.cpp b/third_party/android_crazy_linker/src/src/crazy_linker_shared_library.cpp
index f45824c..b982a7d 100644
--- a/third_party/android_crazy_linker/src/src/crazy_linker_shared_library.cpp
+++ b/third_party/android_crazy_linker/src/src/crazy_linker_shared_library.cpp
@@ -58,18 +58,6 @@
 #define DT_PREINIT_ARRAYSZ 33
 #endif
 
-#ifndef DT_LOOS
-#define DT_LOOS 0x6000000d
-#endif
-
-// Extension dynamic tags for packed relocations.
-#if defined(__arm__) || defined(__aarch64__)
-
-#define DT_ANDROID_REL_OFFSET (DT_LOOS)
-#define DT_ANDROID_REL_SIZE (DT_LOOS + 1)
-
-#endif  // __arm__ || __aarch64__
-
 namespace crazy {
 
 namespace {
@@ -194,57 +182,6 @@
   Vector<LibraryView*>* dependencies_;
 };
 
-#if defined(__arm__) || defined(__aarch64__)
-
-// Helper class to provide a simple scoped buffer.  ScopedPtr is not
-// usable here because it calls delete, not delete [].
-class ScopedBuffer {
- public:
-  explicit ScopedBuffer(size_t bytes) : buffer_(new uint8_t[bytes]) { }
-  ~ScopedBuffer() { delete [] buffer_; }
-
-  uint8_t* Get() { return buffer_; }
-
-  uint8_t* Release() {
-    uint8_t* ptr = buffer_;
-    buffer_ = NULL;
-    return ptr;
-  }
-
- private:
-  uint8_t* buffer_;
-};
-
-// Read an .android.rel.dyn packed relocations section.
-// Returns an allocated buffer holding the data, or NULL on error.
-uint8_t* ReadPackedRelocations(const char* full_path,
-                               off_t offset,
-                               size_t bytes,
-                               Error* error) {
-  FileDescriptor fd;
-  if (!fd.OpenReadOnly(full_path)) {
-    error->Format("Error opening file '%s'", full_path);
-    return NULL;
-  }
-  if (fd.SeekTo(offset) == -1) {
-    error->Format("Error seeking to %d in file '%s'", offset, full_path);
-    return NULL;
-  }
-
-  ScopedBuffer buffer(bytes);
-  const ssize_t bytes_read = fd.Read(buffer.Get(), bytes);
-  if (static_cast<size_t>(bytes_read) != bytes) {
-    error->Format("Error reading %d bytes from file '%s'", bytes, full_path);
-    return NULL;
-  }
-  fd.Close();
-
-  uint8_t* packed_data = buffer.Release();
-  return packed_data;
-}
-
-#endif  // __arm__ || __aarch64__
-
 }  // namespace
 
 SharedLibrary::SharedLibrary() { ::memset(this, 0, sizeof(*this)); }
@@ -253,10 +190,6 @@
   // Ensure the library is unmapped on destruction.
   if (view_.load_address())
     munmap(reinterpret_cast<void*>(view_.load_address()), view_.load_size());
-
-#if defined(__arm__) || defined(__aarch64__)
-  delete [] packed_relocations_;
-#endif
 }
 
 bool SharedLibrary::Load(const char* full_path,
@@ -312,11 +245,6 @@
       phdr(), phdr_count(), load_bias(), &arm_exidx_, &arm_exidx_count_);
 #endif
 
-#if defined(__arm__) || defined(__aarch64__)
-  off_t packed_relocations_offset = 0;
-  size_t packed_relocations_size = 0;
-#endif
-
   LOG("%s: Parsing dynamic table for %s\n", __FUNCTION__, base_name_);
   ElfView::DynamicIterator dyn(&view_);
   for (; dyn.HasNext(); dyn.GetNext()) {
@@ -375,16 +303,6 @@
         if (dyn_value & DF_SYMBOLIC)
           has_DT_SYMBOLIC_ = true;
         break;
-#if defined(__arm__) || defined(__aarch64__)
-      case DT_ANDROID_REL_OFFSET:
-        packed_relocations_offset = dyn.GetOffset();
-        LOG("  DT_ANDROID_REL_OFFSET addr=%p\n", packed_relocations_offset);
-        break;
-      case DT_ANDROID_REL_SIZE:
-        packed_relocations_size = dyn.GetValue();
-        LOG("  DT_ANDROID_REL_SIZE=%d\n", packed_relocations_size);
-        break;
-#endif
 #if defined(__mips__)
       case DT_MIPS_RLD_MAP:
         *dyn.GetValuePointer() =
@@ -396,32 +314,6 @@
     }
   }
 
-#if defined(__arm__) || defined(__aarch64__)
-  // If packed relocations are present in the target library, read the
-  // section data and save it in packed_relocations_.
-  if (packed_relocations_offset && packed_relocations_size) {
-    LOG("%s: Packed relocations found at offset %d, %d bytes\n",
-        __FUNCTION__,
-        packed_relocations_offset,
-        packed_relocations_size);
-
-    packed_relocations_ =
-        ReadPackedRelocations(full_path,
-                              packed_relocations_offset + file_offset,
-                              packed_relocations_size,
-                              error);
-    if (!packed_relocations_)
-      return false;
-
-    LOG("%s: Packed relocations stored at %p\n",
-        __FUNCTION__,
-        packed_relocations_);
-
-    // Add packed relocations to the view.
-    view_.RegisterPackedRelocations(packed_relocations_);
-  }
-#endif
-
   LOG("%s: Load complete for %s\n", __FUNCTION__, base_name_);
   return true;
 }
diff --git a/third_party/android_crazy_linker/src/src/crazy_linker_shared_library.h b/third_party/android_crazy_linker/src/src/crazy_linker_shared_library.h
index 410c914..ef8f469 100644
--- a/third_party/android_crazy_linker/src/src/crazy_linker_shared_library.h
+++ b/third_party/android_crazy_linker/src/src/crazy_linker_shared_library.h
@@ -194,11 +194,6 @@
   size_t arm_exidx_count_;
 #endif
 
-#if defined(__arm__) || defined(__aarch64__)
-  // Packed relocations data, NULL if absent.
-  uint8_t* packed_relocations_;
-#endif
-
   link_map_t link_map_;
 
   bool has_DT_SYMBOLIC_;
diff --git a/third_party/boringssl/err_data.c b/third_party/boringssl/err_data.c
index 913a5d0..5a791377 100644
--- a/third_party/boringssl/err_data.c
+++ b/third_party/boringssl/err_data.c
@@ -218,65 +218,65 @@
     0x28330ac8,
     0x28338acd,
     0x28340ad8,
-    0x2c322b06,
-    0x2c32ab12,
-    0x2c332b25,
-    0x2c33ab36,
-    0x2c342b4f,
-    0x2c34ab77,
-    0x2c352b8e,
-    0x2c35abab,
-    0x2c362bc8,
-    0x2c36abe5,
-    0x2c372bfe,
-    0x2c37ac17,
-    0x2c382c2d,
-    0x2c38ac3b,
-    0x2c392c4d,
-    0x2c39ac6a,
-    0x2c3a2c87,
-    0x2c3aac95,
-    0x2c3b2cb3,
-    0x2c3bacd1,
-    0x2c3c2cec,
-    0x2c3cad00,
-    0x2c3d2d12,
-    0x2c3dad22,
-    0x2c3e2d30,
-    0x2c3ead40,
-    0x2c3f2d50,
-    0x2c3fad6b,
-    0x2c402d7c,
-    0x2c40ad97,
-    0x2c412dab,
-    0x2c41adbe,
-    0x2c422ddd,
-    0x2c42adf1,
-    0x2c432e04,
-    0x2c43ae13,
-    0x2c442e22,
-    0x2c44ae39,
-    0x2c452e54,
-    0x2c45ae6c,
-    0x2c462e80,
-    0x2c46ae93,
-    0x2c472ea4,
-    0x2c47aeb5,
-    0x2c482ec6,
-    0x2c48aed7,
-    0x2c492ee6,
-    0x2c49aef3,
-    0x2c4a2f00,
-    0x2c4aaf0d,
-    0x2c4b2f16,
-    0x2c4baf2a,
-    0x2c4c2f39,
-    0x2c4caf47,
-    0x2c4d2f69,
-    0x2c4daf7a,
-    0x2c4e2f8b,
-    0x2c4eaf56,
-    0x2c4f2b68,
+    0x2c322b00,
+    0x2c32ab0c,
+    0x2c332b1f,
+    0x2c33ab30,
+    0x2c342b49,
+    0x2c34ab71,
+    0x2c352b88,
+    0x2c35aba5,
+    0x2c362bc2,
+    0x2c36abdf,
+    0x2c372bf8,
+    0x2c37ac11,
+    0x2c382c27,
+    0x2c38ac35,
+    0x2c392c47,
+    0x2c39ac64,
+    0x2c3a2c81,
+    0x2c3aac8f,
+    0x2c3b2cad,
+    0x2c3baccb,
+    0x2c3c2ce6,
+    0x2c3cacfa,
+    0x2c3d2d0c,
+    0x2c3dad1c,
+    0x2c3e2d2a,
+    0x2c3ead3a,
+    0x2c3f2d4a,
+    0x2c3fad65,
+    0x2c402d76,
+    0x2c40ad91,
+    0x2c412da5,
+    0x2c41adb8,
+    0x2c422dd7,
+    0x2c42adeb,
+    0x2c432dfe,
+    0x2c43ae0d,
+    0x2c442e1c,
+    0x2c44ae33,
+    0x2c452e4e,
+    0x2c45ae66,
+    0x2c462e7a,
+    0x2c46ae8d,
+    0x2c472e9e,
+    0x2c47aeaf,
+    0x2c482ec0,
+    0x2c48aed1,
+    0x2c492ee0,
+    0x2c49aeed,
+    0x2c4a2efa,
+    0x2c4aaf07,
+    0x2c4b2f10,
+    0x2c4baf24,
+    0x2c4c2f33,
+    0x2c4caf41,
+    0x2c4d2f63,
+    0x2c4daf74,
+    0x2c4e2f85,
+    0x2c4eaf50,
+    0x2c4f2b62,
     0x30320000,
     0x30328018,
     0x3033002c,
@@ -482,104 +482,104 @@
     0x4051a1de,
     0x40522201,
     0x4052a221,
-    0x4053223c,
-    0x4053a24c,
-    0x4054a258,
-    0x4055226e,
-    0x4055a28c,
-    0x40562299,
-    0x4056a2a3,
-    0x405722b1,
-    0x4057a2cc,
-    0x405822e7,
-    0x4058a306,
-    0x4059231b,
-    0x4059a330,
-    0x405a234d,
-    0x405aa361,
-    0x405b237d,
-    0x405ba393,
-    0x405c23b0,
-    0x405ca3c2,
-    0x405d23d9,
-    0x405da3ea,
-    0x405e2406,
-    0x405ea41a,
-    0x405f242a,
-    0x405fa446,
-    0x4060245b,
-    0x4060a471,
-    0x4061248e,
-    0x4061a4a7,
-    0x406224d1,
-    0x4062a4da,
-    0x406324ea,
-    0x4063a523,
-    0x40642539,
-    0x4064a557,
-    0x4065256c,
-    0x4065a589,
-    0x406625a0,
-    0x4066a5be,
-    0x406725db,
-    0x4067a5f2,
-    0x40682610,
-    0x4068a627,
-    0x4069263f,
-    0x4069a650,
-    0x406a2663,
-    0x406aa676,
-    0x406b268a,
-    0x406ba6ae,
-    0x406c26c9,
-    0x406ca6ea,
-    0x406d270e,
-    0x406da729,
-    0x406e274a,
-    0x406ea75f,
-    0x406f2778,
-    0x406fa785,
-    0x40702793,
-    0x4070a7a0,
-    0x407127bd,
-    0x4071a7dd,
-    0x407227f8,
-    0x4072a811,
-    0x40732828,
-    0x4073a842,
-    0x40742866,
-    0x4074a87c,
-    0x40752890,
-    0x4075a8a5,
-    0x407628bf,
-    0x4076a8d1,
-    0x407728e6,
-    0x4077a90c,
-    0x40782929,
-    0x4078a94c,
-    0x40792972,
-    0x4079a98f,
-    0x407a29b2,
-    0x407aa9ce,
-    0x407b29ea,
-    0x407ba9fc,
-    0x407c2a09,
-    0x407e2a16,
-    0x407eaa2c,
-    0x407f2a44,
-    0x407faa57,
-    0x40802a6c,
-    0x4080aa85,
-    0x40812aa3,
-    0x4081aac3,
-    0x40822acc,
-    0x4082aae8,
-    0x40832af1,
+    0x40532236,
+    0x4053a246,
+    0x4054a252,
+    0x40552268,
+    0x4055a286,
+    0x40562293,
+    0x4056a29d,
+    0x405722ab,
+    0x4057a2c6,
+    0x405822e1,
+    0x4058a300,
+    0x40592315,
+    0x4059a32a,
+    0x405a2347,
+    0x405aa35b,
+    0x405b2377,
+    0x405ba38d,
+    0x405c23aa,
+    0x405ca3bc,
+    0x405d23d3,
+    0x405da3e4,
+    0x405e2400,
+    0x405ea414,
+    0x405f2424,
+    0x405fa440,
+    0x40602455,
+    0x4060a46b,
+    0x40612488,
+    0x4061a4a1,
+    0x406224cb,
+    0x4062a4d4,
+    0x406324e4,
+    0x4063a51d,
+    0x40642533,
+    0x4064a551,
+    0x40652566,
+    0x4065a583,
+    0x4066259a,
+    0x4066a5b8,
+    0x406725d5,
+    0x4067a5ec,
+    0x4068260a,
+    0x4068a621,
+    0x40692639,
+    0x4069a64a,
+    0x406a265d,
+    0x406aa670,
+    0x406b2684,
+    0x406ba6a8,
+    0x406c26c3,
+    0x406ca6e4,
+    0x406d2708,
+    0x406da723,
+    0x406e2744,
+    0x406ea759,
+    0x406f2772,
+    0x406fa77f,
+    0x4070278d,
+    0x4070a79a,
+    0x407127b7,
+    0x4071a7d7,
+    0x407227f2,
+    0x4072a80b,
+    0x40732822,
+    0x4073a83c,
+    0x40742860,
+    0x4074a876,
+    0x4075288a,
+    0x4075a89f,
+    0x407628b9,
+    0x4076a8cb,
+    0x407728e0,
+    0x4077a906,
+    0x40782923,
+    0x4078a946,
+    0x4079296c,
+    0x4079a989,
+    0x407a29ac,
+    0x407aa9c8,
+    0x407b29e4,
+    0x407ba9f6,
+    0x407c2a03,
+    0x407e2a10,
+    0x407eaa26,
+    0x407f2a3e,
+    0x407faa51,
+    0x40802a66,
+    0x4080aa7f,
+    0x40812a9d,
+    0x4081aabd,
+    0x40822ac6,
+    0x4082aae2,
+    0x40832aeb,
     0x4083a123,
     0x408421b2,
     0x4084a182,
-    0x40852512,
-    0x4085a4f6,
+    0x4085250c,
+    0x4085a4f0,
     0x40861c3c,
     0x40869c4f,
     0x40871f41,
@@ -587,7 +587,7 @@
     0x40881bcb,
     0x40889eca,
     0x40891f28,
-    0x4089a4ba,
+    0x4089a4b4,
     0x408a1b70,
     0x408a9b81,
     0x408b1b93,
@@ -629,63 +629,63 @@
     0x4c3998fe,
     0x4c3a1916,
     0x4c3a9929,
-    0x50322f9c,
-    0x5032afb1,
-    0x50332fc2,
-    0x5033afd5,
-    0x50342fe6,
-    0x5034aff9,
-    0x50353008,
-    0x5035b01d,
-    0x5036302d,
-    0x5036b03c,
-    0x5037304d,
-    0x5037b05d,
-    0x5038306e,
-    0x5038b081,
-    0x50393093,
-    0x5039b0a9,
-    0x503a30bb,
-    0x503ab0cc,
-    0x503b30dd,
-    0x503bb0ee,
-    0x503c30f9,
-    0x503cb105,
-    0x503d3110,
-    0x503db11b,
-    0x503e3128,
-    0x503eb13d,
-    0x503f314b,
-    0x503fb15f,
-    0x50403172,
-    0x5040b183,
-    0x5041319d,
-    0x5041b1ac,
-    0x504231b5,
-    0x5042b1c4,
-    0x504331d6,
-    0x5043b1e2,
-    0x504431ea,
-    0x5044b1fd,
-    0x5045320e,
-    0x5045b224,
-    0x50463230,
-    0x5046b244,
-    0x50473252,
-    0x5047b266,
-    0x50483280,
-    0x5048b294,
-    0x504932aa,
-    0x5049b2c1,
-    0x504a32d3,
-    0x504ab2e7,
-    0x504b32fc,
-    0x504bb313,
-    0x504c3327,
-    0x504cb330,
-    0x504d3338,
-    0x504db347,
-    0x504e3357,
+    0x50322f96,
+    0x5032afab,
+    0x50332fbc,
+    0x5033afcf,
+    0x50342fe0,
+    0x5034aff3,
+    0x50353002,
+    0x5035b017,
+    0x50363027,
+    0x5036b036,
+    0x50373047,
+    0x5037b057,
+    0x50383068,
+    0x5038b07b,
+    0x5039308d,
+    0x5039b0a3,
+    0x503a30b5,
+    0x503ab0c6,
+    0x503b30d7,
+    0x503bb0e8,
+    0x503c30f3,
+    0x503cb0ff,
+    0x503d310a,
+    0x503db115,
+    0x503e3122,
+    0x503eb137,
+    0x503f3145,
+    0x503fb159,
+    0x5040316c,
+    0x5040b17d,
+    0x50413197,
+    0x5041b1a6,
+    0x504231af,
+    0x5042b1be,
+    0x504331d0,
+    0x5043b1dc,
+    0x504431e4,
+    0x5044b1f7,
+    0x50453208,
+    0x5045b21e,
+    0x5046322a,
+    0x5046b23e,
+    0x5047324c,
+    0x5047b260,
+    0x5048327a,
+    0x5048b28e,
+    0x504932a4,
+    0x5049b2bb,
+    0x504a32cd,
+    0x504ab2e1,
+    0x504b32f6,
+    0x504bb30d,
+    0x504c3321,
+    0x504cb32a,
+    0x504d3332,
+    0x504db341,
+    0x504e3351,
     0x68321109,
     0x6832911a,
     0x6833112a,
@@ -1198,7 +1198,7 @@
     "dtls1_read_bytes\0"
     "dtls1_seal_record\0"
     "dtls1_send_hello_verify_request\0"
-    "dtls1_write_app_data_bytes\0"
+    "dtls1_write_app_data\0"
     "i2d_SSL_SESSION\0"
     "ssl3_accept\0"
     "ssl3_cert_verify_hash\0"
@@ -1542,43 +1542,43 @@
     0x28328b8e,
     0x28330b5f,
     0x28338ba1,
-    0x2c322a47,
-    0x2c32aa55,
-    0x2c332a67,
-    0x2c33aa79,
-    0x2c342a8d,
-    0x2c34aa9f,
-    0x2c352aba,
-    0x2c35aacc,
-    0x2c362adf,
+    0x2c322ab3,
+    0x2c32aac1,
+    0x2c332ad3,
+    0x2c33aae5,
+    0x2c342af9,
+    0x2c34ab0b,
+    0x2c352b26,
+    0x2c35ab38,
+    0x2c362b4b,
     0x2c3682f3,
-    0x2c372aec,
-    0x2c37aafe,
-    0x2c382b11,
-    0x2c38ab1f,
-    0x2c392b2f,
-    0x2c39ab41,
-    0x2c3a2b55,
-    0x2c3aab66,
+    0x2c372b58,
+    0x2c37ab6a,
+    0x2c382b7d,
+    0x2c38ab8b,
+    0x2c392b9b,
+    0x2c39abad,
+    0x2c3a2bc1,
+    0x2c3aabd2,
     0x2c3b134c,
-    0x2c3bab77,
-    0x2c3c2b8b,
-    0x2c3caba1,
-    0x2c3d2bba,
-    0x2c3dabe8,
-    0x2c3e2bf6,
-    0x2c3eac0e,
-    0x2c3f2c26,
-    0x2c3fac33,
-    0x2c402c56,
-    0x2c40ac75,
+    0x2c3babe3,
+    0x2c3c2bf7,
+    0x2c3cac0d,
+    0x2c3d2c26,
+    0x2c3dac54,
+    0x2c3e2c62,
+    0x2c3eac7a,
+    0x2c3f2c92,
+    0x2c3fac9f,
+    0x2c402cc2,
+    0x2c40ace1,
     0x2c4111b6,
-    0x2c41ac86,
-    0x2c422c99,
+    0x2c41acf2,
+    0x2c422d05,
     0x2c429128,
-    0x2c432caa,
+    0x2c432d16,
     0x2c4386a2,
-    0x2c442bd7,
+    0x2c442c43,
     0x30320000,
     0x30328015,
     0x3033001f,
@@ -1750,162 +1750,165 @@
     0x40491b0e,
     0x40499b23,
     0x404a1b3c,
-    0x404a9b5f,
-    0x404b1b79,
-    0x404b9b97,
-    0x404c1bb2,
-    0x404c9bcc,
-    0x404d1be3,
-    0x404d9c0b,
-    0x404e1c22,
-    0x404e9c3e,
-    0x404f1c5a,
-    0x404f9c7b,
-    0x40501c9d,
-    0x40509cb9,
-    0x40511ccd,
-    0x40519cda,
-    0x40521cf1,
-    0x40529d01,
-    0x40531d11,
-    0x40539d25,
-    0x40541d40,
-    0x40549d50,
-    0x40551d67,
-    0x40559d76,
-    0x40561d91,
-    0x40569da9,
-    0x40571dc5,
-    0x40579dde,
-    0x40581df1,
-    0x40589e06,
-    0x40591e29,
-    0x40599e37,
-    0x405a1e44,
-    0x405a9e5d,
-    0x405b1e75,
-    0x405b9e88,
-    0x405c1e9d,
-    0x405c9eaf,
-    0x405d1ec4,
-    0x405d9ed4,
-    0x405e1eed,
-    0x405e9f01,
-    0x405f1f11,
-    0x405f9f29,
-    0x40601f3a,
-    0x40609f4d,
-    0x40611f5e,
-    0x40619f7c,
-    0x40621f8d,
-    0x40629f9a,
-    0x40631fb1,
-    0x40639ff2,
-    0x40642009,
-    0x4064a016,
-    0x40652024,
-    0x4065a046,
-    0x4066206e,
-    0x4066a083,
-    0x4067209a,
-    0x4067a0ab,
-    0x406820bc,
-    0x4068a0cd,
-    0x406920e2,
-    0x4069a0f9,
-    0x406a210a,
-    0x406aa123,
-    0x406b213e,
-    0x406ba155,
-    0x406c216d,
-    0x406ca18e,
-    0x406d21a1,
-    0x406da1c2,
-    0x406e21dd,
-    0x406ea1f8,
-    0x406f2219,
-    0x406fa23f,
-    0x4070225f,
-    0x4070a27b,
-    0x40712408,
-    0x4071a42b,
-    0x40722441,
-    0x4072a460,
-    0x40732478,
-    0x4073a498,
-    0x407426c2,
-    0x4074a6e7,
-    0x40752702,
-    0x4075a721,
-    0x40762750,
-    0x4076a778,
-    0x40772791,
-    0x4077a7b0,
-    0x407827d5,
-    0x4078a7ec,
-    0x407927ff,
-    0x4079a81c,
+    0x404a9b76,
+    0x404b1b90,
+    0x404b9bae,
+    0x404c1bc9,
+    0x404c9be3,
+    0x404d1bfa,
+    0x404d9c22,
+    0x404e1c39,
+    0x404e9c55,
+    0x404f1c71,
+    0x404f9c92,
+    0x40501cb4,
+    0x40509cd0,
+    0x40511ce4,
+    0x40519cf1,
+    0x40521d08,
+    0x40529d18,
+    0x40531d28,
+    0x40539d3c,
+    0x40541d57,
+    0x40549d67,
+    0x40551d7e,
+    0x40559d8d,
+    0x40561da8,
+    0x40569dc0,
+    0x40571ddc,
+    0x40579df5,
+    0x40581e08,
+    0x40589e1d,
+    0x40591e40,
+    0x40599e4e,
+    0x405a1e5b,
+    0x405a9e74,
+    0x405b1e8c,
+    0x405b9e9f,
+    0x405c1eb4,
+    0x405c9ec6,
+    0x405d1edb,
+    0x405d9eeb,
+    0x405e1f04,
+    0x405e9f18,
+    0x405f1f28,
+    0x405f9f40,
+    0x40601f51,
+    0x40609f64,
+    0x40611f75,
+    0x40619f93,
+    0x40621fa4,
+    0x40629fb1,
+    0x40631fc8,
+    0x4063a009,
+    0x40642020,
+    0x4064a02d,
+    0x4065203b,
+    0x4065a05d,
+    0x40662085,
+    0x4066a09a,
+    0x406720b1,
+    0x4067a0c2,
+    0x406820d3,
+    0x4068a0e4,
+    0x406920f9,
+    0x4069a110,
+    0x406a2121,
+    0x406aa13a,
+    0x406b2155,
+    0x406ba16c,
+    0x406c21d9,
+    0x406ca1fa,
+    0x406d220d,
+    0x406da22e,
+    0x406e2249,
+    0x406ea264,
+    0x406f2285,
+    0x406fa2ab,
+    0x407022cb,
+    0x4070a2e7,
+    0x40712474,
+    0x4071a497,
+    0x407224ad,
+    0x4072a4cc,
+    0x407324e4,
+    0x4073a504,
+    0x4074272e,
+    0x4074a753,
+    0x4075276e,
+    0x4075a78d,
+    0x407627bc,
+    0x4076a7e4,
+    0x407727fd,
+    0x4077a81c,
+    0x40782841,
+    0x4078a858,
+    0x4079286b,
+    0x4079a888,
     0x407a0782,
-    0x407aa82e,
-    0x407b2841,
-    0x407ba85a,
-    0x407c2872,
+    0x407aa89a,
+    0x407b28ad,
+    0x407ba8c6,
+    0x407c28de,
     0x407c90b0,
-    0x407d2886,
-    0x407da8a0,
-    0x407e28b1,
-    0x407ea8c5,
-    0x407f28d3,
-    0x407fa8ee,
+    0x407d28f2,
+    0x407da90c,
+    0x407e291d,
+    0x407ea931,
+    0x407f293f,
+    0x407fa95a,
     0x40801279,
-    0x4080a913,
-    0x40812935,
-    0x4081a950,
-    0x40822965,
-    0x4082a97d,
-    0x40832995,
-    0x4083a9ac,
-    0x408429c2,
-    0x4084a9ce,
-    0x408529e1,
-    0x4085a9f6,
-    0x40862a08,
-    0x4086aa1d,
-    0x40872a26,
-    0x40879bf9,
+    0x4080a97f,
+    0x408129a1,
+    0x4081a9bc,
+    0x408229d1,
+    0x4082a9e9,
+    0x40832a01,
+    0x4083aa18,
+    0x40842a2e,
+    0x4084aa3a,
+    0x40852a4d,
+    0x4085aa62,
+    0x40862a74,
+    0x4086aa89,
+    0x40872a92,
+    0x40879c10,
     0x40880083,
-    0x40889fd1,
+    0x40889fe8,
     0x40890a0a,
-    0x41f42333,
-    0x41f923c5,
-    0x41fe22b8,
-    0x41fea4e9,
-    0x41ff25da,
-    0x4203234c,
-    0x4208236e,
-    0x4208a3aa,
-    0x4209229c,
-    0x4209a3e4,
-    0x420a22f3,
-    0x420aa2d3,
-    0x420b2313,
-    0x420ba38c,
-    0x420c25f6,
-    0x420ca4b6,
-    0x420d24d0,
-    0x420da507,
-    0x42122521,
-    0x421725bd,
-    0x4217a563,
-    0x421c2585,
-    0x421f2540,
-    0x4221260d,
-    0x422625a0,
-    0x422b26a6,
-    0x422ba66f,
-    0x422c268e,
-    0x422ca649,
-    0x422d2628,
+    0x4089a184,
+    0x408a1b5f,
+    0x408aa1ae,
+    0x41f4239f,
+    0x41f92431,
+    0x41fe2324,
+    0x41fea555,
+    0x41ff2646,
+    0x420323b8,
+    0x420823da,
+    0x4208a416,
+    0x42092308,
+    0x4209a450,
+    0x420a235f,
+    0x420aa33f,
+    0x420b237f,
+    0x420ba3f8,
+    0x420c2662,
+    0x420ca522,
+    0x420d253c,
+    0x420da573,
+    0x4212258d,
+    0x42172629,
+    0x4217a5cf,
+    0x421c25f1,
+    0x421f25ac,
+    0x42212679,
+    0x4226260c,
+    0x422b2712,
+    0x422ba6db,
+    0x422c26fa,
+    0x422ca6b5,
+    0x422d2694,
     0x443206ad,
     0x443286bc,
     0x443306c8,
@@ -1948,69 +1951,69 @@
     0x4c3d10b0,
     0x4c3d943c,
     0x4c3e1449,
-    0x50322cbc,
-    0x5032accb,
-    0x50332cd6,
-    0x5033ace6,
-    0x50342cff,
-    0x5034ad19,
-    0x50352d27,
-    0x5035ad3d,
-    0x50362d4f,
-    0x5036ad65,
-    0x50372d7e,
-    0x5037ad91,
-    0x50382da9,
-    0x5038adba,
-    0x50392dcf,
-    0x5039ade3,
-    0x503a2e03,
-    0x503aae19,
-    0x503b2e31,
-    0x503bae43,
-    0x503c2e5f,
-    0x503cae76,
-    0x503d2e8f,
-    0x503daea5,
-    0x503e2eb2,
-    0x503eaec8,
-    0x503f2eda,
+    0x50322d28,
+    0x5032ad37,
+    0x50332d42,
+    0x5033ad52,
+    0x50342d6b,
+    0x5034ad85,
+    0x50352d93,
+    0x5035ada9,
+    0x50362dbb,
+    0x5036add1,
+    0x50372dea,
+    0x5037adfd,
+    0x50382e15,
+    0x5038ae26,
+    0x50392e3b,
+    0x5039ae4f,
+    0x503a2e6f,
+    0x503aae85,
+    0x503b2e9d,
+    0x503baeaf,
+    0x503c2ecb,
+    0x503caee2,
+    0x503d2efb,
+    0x503daf11,
+    0x503e2f1e,
+    0x503eaf34,
+    0x503f2f46,
     0x503f8348,
-    0x50402eed,
-    0x5040aefd,
-    0x50412f17,
-    0x5041af26,
-    0x50422f40,
-    0x5042af5d,
-    0x50432f6d,
-    0x5043af7d,
-    0x50442f8c,
+    0x50402f59,
+    0x5040af69,
+    0x50412f83,
+    0x5041af92,
+    0x50422fac,
+    0x5042afc9,
+    0x50432fd9,
+    0x5043afe9,
+    0x50442ff8,
     0x50448414,
-    0x50452fa0,
-    0x5045afbe,
-    0x50462fd1,
-    0x5046afe7,
-    0x50472ff9,
-    0x5047b00e,
-    0x50483034,
-    0x5048b042,
-    0x50493055,
-    0x5049b06a,
-    0x504a3080,
-    0x504ab090,
-    0x504b30b0,
-    0x504bb0c3,
-    0x504c30e6,
-    0x504cb114,
-    0x504d3126,
-    0x504db143,
-    0x504e315e,
-    0x504eb17a,
-    0x504f318c,
-    0x504fb1a3,
-    0x505031b2,
+    0x5045300c,
+    0x5045b02a,
+    0x5046303d,
+    0x5046b053,
+    0x50473065,
+    0x5047b07a,
+    0x504830a0,
+    0x5048b0ae,
+    0x504930c1,
+    0x5049b0d6,
+    0x504a30ec,
+    0x504ab0fc,
+    0x504b311c,
+    0x504bb12f,
+    0x504c3152,
+    0x504cb180,
+    0x504d3192,
+    0x504db1af,
+    0x504e31ca,
+    0x504eb1e6,
+    0x504f31f8,
+    0x504fb20f,
+    0x5050321e,
     0x50508687,
-    0x505131c5,
+    0x50513231,
     0x58320e12,
     0x68320dd4,
     0x68328b8e,
@@ -2403,6 +2406,7 @@
     "DTLS_MESSAGE_TOO_BIG\0"
     "ECC_CERT_NOT_FOR_SIGNING\0"
     "EMPTY_SRTP_PROTECTION_PROFILE_LIST\0"
+    "EMS_STATE_INCONSISTENT\0"
     "ENCRYPTED_LENGTH_TOO_LONG\0"
     "ERROR_IN_RECEIVED_CIPHER_LIST\0"
     "EVP_DIGESTSIGNFINAL_FAILED\0"
@@ -2472,6 +2476,8 @@
     "RENEGOTIATION_ENCODING_ERR\0"
     "RENEGOTIATION_MISMATCH\0"
     "REQUIRED_CIPHER_MISSING\0"
+    "RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION\0"
+    "RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION\0"
     "SCSV_RECEIVED_WHEN_RENEGOTIATING\0"
     "SERVERHELLO_TLSEXT\0"
     "SESSION_ID_CONTEXT_UNINITIALIZED\0"
diff --git a/third_party/boringssl/linux-arm/crypto/sha/sha256-armv4.S b/third_party/boringssl/linux-arm/crypto/sha/sha256-armv4.S
index ba37795..114aa43 100644
--- a/third_party/boringssl/linux-arm/crypto/sha/sha256-armv4.S
+++ b/third_party/boringssl/linux-arm/crypto/sha/sha256-armv4.S
@@ -1881,7 +1881,7 @@
 	stmdb	sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,lr}
 
 	sub	r11,sp,#16*4+16
-	adr	r14,K256
+	adrl	r14,K256
 	bic	r11,r11,#15		@ align for 128-bit stores
 	mov	r12,sp
 	mov	sp,r11			@ alloca
diff --git a/third_party/expat/README.chromium b/third_party/expat/README.chromium
index 7b47f5f..a0af1e2d 100644
--- a/third_party/expat/README.chromium
+++ b/third_party/expat/README.chromium
@@ -4,7 +4,7 @@
 Version: 2.1.0
 License: MIT
 License File: files/COPYING
-Security Critical: no
+Security Critical: yes
 
 Description:
   This is Expat XML parser - very lightweight C library for parsing XML.
@@ -38,5 +38,8 @@
     lib/xmltok_impl.c (see xmltok_imp.c.original for unmodified version)
       * Prevent a compiler warning when compiling with
         WIN32_LEAN_AND_MEAN predefined.
+    lib/xmlparse.c (see xmlparse.c.original for unmodified version)
+      * Apply https://hg.mozilla.org/releases/mozilla-esr31/rev/2f3e78643f5c
+        to prevent an integer overflow.
   Added files:
     lib/expat_config.h (a generated config file)
diff --git a/third_party/expat/files/lib/xmlparse.c b/third_party/expat/files/lib/xmlparse.c
index f35aa36..ede7b5b 100644
--- a/third_party/expat/files/lib/xmlparse.c
+++ b/third_party/expat/files/lib/xmlparse.c
@@ -1678,6 +1678,12 @@
 void * XMLCALL
 XML_GetBuffer(XML_Parser parser, int len)
 {
+/* BEGIN MOZILLA CHANGE (sanity check len) */
+  if (len < 0) {
+    errorCode = XML_ERROR_NO_MEMORY;
+    return NULL;
+  }
+/* END MOZILLA CHANGE */
   switch (ps_parsing) {
   case XML_SUSPENDED:
     errorCode = XML_ERROR_SUSPENDED;
@@ -1689,8 +1695,13 @@
   }
 
   if (len > bufferLim - bufferEnd) {
-    /* FIXME avoid integer overflow */
     int neededSize = len + (int)(bufferEnd - bufferPtr);
+/* BEGIN MOZILLA CHANGE (sanity check neededSize) */
+    if (neededSize < 0) {
+      errorCode = XML_ERROR_NO_MEMORY;
+      return NULL;
+    }
+/* END MOZILLA CHANGE */
 #ifdef XML_CONTEXT_BYTES
     int keep = (int)(bufferPtr - buffer);
 
@@ -1719,7 +1730,15 @@
         bufferSize = INIT_BUFFER_SIZE;
       do {
         bufferSize *= 2;
-      } while (bufferSize < neededSize);
+/* BEGIN MOZILLA CHANGE (prevent infinite loop on overflow) */
+      } while (bufferSize < neededSize && bufferSize > 0);
+/* END MOZILLA CHANGE */
+/* BEGIN MOZILLA CHANGE (sanity check bufferSize) */
+      if (bufferSize <= 0) {
+        errorCode = XML_ERROR_NO_MEMORY;
+        return NULL;
+      }
+/* END MOZILLA CHANGE */
       newBuf = (char *)MALLOC(bufferSize);
       if (newBuf == 0) {
         errorCode = XML_ERROR_NO_MEMORY;
diff --git a/third_party/expat/files/lib/xmlparse.c.original b/third_party/expat/files/lib/xmlparse.c.original
new file mode 100644
index 0000000..f35aa36
--- /dev/null
+++ b/third_party/expat/files/lib/xmlparse.c.original
@@ -0,0 +1,6403 @@
+/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+   See the file COPYING for copying permission.
+*/
+
+#include <stddef.h>
+#include <string.h>                     /* memset(), memcpy() */
+#include <assert.h>
+#include <limits.h>                     /* UINT_MAX */
+#include <time.h>                       /* time() */
+
+#define XML_BUILDING_EXPAT 1
+
+#ifdef COMPILED_FROM_DSP
+#include "winconfig.h"
+#elif defined(MACOS_CLASSIC)
+#include "macconfig.h"
+#elif defined(__amigaos__)
+#include "amigaconfig.h"
+#elif defined(__WATCOMC__)
+#include "watcomconfig.h"
+#elif defined(HAVE_EXPAT_CONFIG_H)
+#include <expat_config.h>
+#endif /* ndef COMPILED_FROM_DSP */
+
+#include "ascii.h"
+#include "expat.h"
+
+#ifdef XML_UNICODE
+#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX
+#define XmlConvert XmlUtf16Convert
+#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding
+#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS
+#define XmlEncode XmlUtf16Encode
+/* Using pointer subtraction to convert to integer type. */
+#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1))
+typedef unsigned short ICHAR;
+#else
+#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX
+#define XmlConvert XmlUtf8Convert
+#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding
+#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS
+#define XmlEncode XmlUtf8Encode
+#define MUST_CONVERT(enc, s) (!(enc)->isUtf8)
+typedef char ICHAR;
+#endif
+
+
+#ifndef XML_NS
+
+#define XmlInitEncodingNS XmlInitEncoding
+#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding
+#undef XmlGetInternalEncodingNS
+#define XmlGetInternalEncodingNS XmlGetInternalEncoding
+#define XmlParseXmlDeclNS XmlParseXmlDecl
+
+#endif
+
+#ifdef XML_UNICODE
+
+#ifdef XML_UNICODE_WCHAR_T
+#define XML_T(x) (const wchar_t)x
+#define XML_L(x) L ## x
+#else
+#define XML_T(x) (const unsigned short)x
+#define XML_L(x) x
+#endif
+
+#else
+
+#define XML_T(x) x
+#define XML_L(x) x
+
+#endif
+
+/* Round up n to be a multiple of sz, where sz is a power of 2. */
+#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
+
+/* Handle the case where memmove() doesn't exist. */
+#ifndef HAVE_MEMMOVE
+#ifdef HAVE_BCOPY
+#define memmove(d,s,l) bcopy((s),(d),(l))
+#else
+#error memmove does not exist on this platform, nor is a substitute available
+#endif /* HAVE_BCOPY */
+#endif /* HAVE_MEMMOVE */
+
+#include "internal.h"
+#include "xmltok.h"
+#include "xmlrole.h"
+
+typedef const XML_Char *KEY;
+
+typedef struct {
+  KEY name;
+} NAMED;
+
+typedef struct {
+  NAMED **v;
+  unsigned char power;
+  size_t size;
+  size_t used;
+  const XML_Memory_Handling_Suite *mem;
+} HASH_TABLE;
+
+/* Basic character hash algorithm, taken from Python's string hash:
+   h = h * 1000003 ^ character, the constant being a prime number.
+
+*/
+#ifdef XML_UNICODE
+#define CHAR_HASH(h, c) \
+  (((h) * 0xF4243) ^ (unsigned short)(c))
+#else
+#define CHAR_HASH(h, c) \
+  (((h) * 0xF4243) ^ (unsigned char)(c))
+#endif
+
+/* For probing (after a collision) we need a step size relative prime
+   to the hash table size, which is a power of 2. We use double-hashing,
+   since we can calculate a second hash value cheaply by taking those bits
+   of the first hash value that were discarded (masked out) when the table
+   index was calculated: index = hash & mask, where mask = table->size - 1.
+   We limit the maximum step size to table->size / 4 (mask >> 2) and make
+   it odd, since odd numbers are always relative prime to a power of 2.
+*/
+#define SECOND_HASH(hash, mask, power) \
+  ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2))
+#define PROBE_STEP(hash, mask, power) \
+  ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1))
+
+typedef struct {
+  NAMED **p;
+  NAMED **end;
+} HASH_TABLE_ITER;
+
+#define INIT_TAG_BUF_SIZE 32  /* must be a multiple of sizeof(XML_Char) */
+#define INIT_DATA_BUF_SIZE 1024
+#define INIT_ATTS_SIZE 16
+#define INIT_ATTS_VERSION 0xFFFFFFFF
+#define INIT_BLOCK_SIZE 1024
+#define INIT_BUFFER_SIZE 1024
+
+#define EXPAND_SPARE 24
+
+typedef struct binding {
+  struct prefix *prefix;
+  struct binding *nextTagBinding;
+  struct binding *prevPrefixBinding;
+  const struct attribute_id *attId;
+  XML_Char *uri;
+  int uriLen;
+  int uriAlloc;
+} BINDING;
+
+typedef struct prefix {
+  const XML_Char *name;
+  BINDING *binding;
+} PREFIX;
+
+typedef struct {
+  const XML_Char *str;
+  const XML_Char *localPart;
+  const XML_Char *prefix;
+  int strLen;
+  int uriLen;
+  int prefixLen;
+} TAG_NAME;
+
+/* TAG represents an open element.
+   The name of the element is stored in both the document and API
+   encodings.  The memory buffer 'buf' is a separately-allocated
+   memory area which stores the name.  During the XML_Parse()/
+   XMLParseBuffer() when the element is open, the memory for the 'raw'
+   version of the name (in the document encoding) is shared with the
+   document buffer.  If the element is open across calls to
+   XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to
+   contain the 'raw' name as well.
+
+   A parser re-uses these structures, maintaining a list of allocated
+   TAG objects in a free list.
+*/
+typedef struct tag {
+  struct tag *parent;           /* parent of this element */
+  const char *rawName;          /* tagName in the original encoding */
+  int rawNameLength;
+  TAG_NAME name;                /* tagName in the API encoding */
+  char *buf;                    /* buffer for name components */
+  char *bufEnd;                 /* end of the buffer */
+  BINDING *bindings;
+} TAG;
+
+typedef struct {
+  const XML_Char *name;
+  const XML_Char *textPtr;
+  int textLen;                  /* length in XML_Chars */
+  int processed;                /* # of processed bytes - when suspended */
+  const XML_Char *systemId;
+  const XML_Char *base;
+  const XML_Char *publicId;
+  const XML_Char *notation;
+  XML_Bool open;
+  XML_Bool is_param;
+  XML_Bool is_internal; /* true if declared in internal subset outside PE */
+} ENTITY;
+
+typedef struct {
+  enum XML_Content_Type         type;
+  enum XML_Content_Quant        quant;
+  const XML_Char *              name;
+  int                           firstchild;
+  int                           lastchild;
+  int                           childcnt;
+  int                           nextsib;
+} CONTENT_SCAFFOLD;
+
+#define INIT_SCAFFOLD_ELEMENTS 32
+
+typedef struct block {
+  struct block *next;
+  int size;
+  XML_Char s[1];
+} BLOCK;
+
+typedef struct {
+  BLOCK *blocks;
+  BLOCK *freeBlocks;
+  const XML_Char *end;
+  XML_Char *ptr;
+  XML_Char *start;
+  const XML_Memory_Handling_Suite *mem;
+} STRING_POOL;
+
+/* The XML_Char before the name is used to determine whether
+   an attribute has been specified. */
+typedef struct attribute_id {
+  XML_Char *name;
+  PREFIX *prefix;
+  XML_Bool maybeTokenized;
+  XML_Bool xmlns;
+} ATTRIBUTE_ID;
+
+typedef struct {
+  const ATTRIBUTE_ID *id;
+  XML_Bool isCdata;
+  const XML_Char *value;
+} DEFAULT_ATTRIBUTE;
+
+typedef struct {
+  unsigned long version;
+  unsigned long hash;
+  const XML_Char *uriName;
+} NS_ATT;
+
+typedef struct {
+  const XML_Char *name;
+  PREFIX *prefix;
+  const ATTRIBUTE_ID *idAtt;
+  int nDefaultAtts;
+  int allocDefaultAtts;
+  DEFAULT_ATTRIBUTE *defaultAtts;
+} ELEMENT_TYPE;
+
+typedef struct {
+  HASH_TABLE generalEntities;
+  HASH_TABLE elementTypes;
+  HASH_TABLE attributeIds;
+  HASH_TABLE prefixes;
+  STRING_POOL pool;
+  STRING_POOL entityValuePool;
+  /* false once a parameter entity reference has been skipped */
+  XML_Bool keepProcessing;
+  /* true once an internal or external PE reference has been encountered;
+     this includes the reference to an external subset */
+  XML_Bool hasParamEntityRefs;
+  XML_Bool standalone;
+#ifdef XML_DTD
+  /* indicates if external PE has been read */
+  XML_Bool paramEntityRead;
+  HASH_TABLE paramEntities;
+#endif /* XML_DTD */
+  PREFIX defaultPrefix;
+  /* === scaffolding for building content model === */
+  XML_Bool in_eldecl;
+  CONTENT_SCAFFOLD *scaffold;
+  unsigned contentStringLen;
+  unsigned scaffSize;
+  unsigned scaffCount;
+  int scaffLevel;
+  int *scaffIndex;
+} DTD;
+
+typedef struct open_internal_entity {
+  const char *internalEventPtr;
+  const char *internalEventEndPtr;
+  struct open_internal_entity *next;
+  ENTITY *entity;
+  int startTagLevel;
+  XML_Bool betweenDecl; /* WFC: PE Between Declarations */
+} OPEN_INTERNAL_ENTITY;
+
+typedef enum XML_Error PTRCALL Processor(XML_Parser parser,
+                                         const char *start,
+                                         const char *end,
+                                         const char **endPtr);
+
+static Processor prologProcessor;
+static Processor prologInitProcessor;
+static Processor contentProcessor;
+static Processor cdataSectionProcessor;
+#ifdef XML_DTD
+static Processor ignoreSectionProcessor;
+static Processor externalParEntProcessor;
+static Processor externalParEntInitProcessor;
+static Processor entityValueProcessor;
+static Processor entityValueInitProcessor;
+#endif /* XML_DTD */
+static Processor epilogProcessor;
+static Processor errorProcessor;
+static Processor externalEntityInitProcessor;
+static Processor externalEntityInitProcessor2;
+static Processor externalEntityInitProcessor3;
+static Processor externalEntityContentProcessor;
+static Processor internalEntityProcessor;
+
+static enum XML_Error
+handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName);
+static enum XML_Error
+processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
+               const char *s, const char *next);
+static enum XML_Error
+initializeEncoding(XML_Parser parser);
+static enum XML_Error
+doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
+         const char *end, int tok, const char *next, const char **nextPtr,
+         XML_Bool haveMore);
+static enum XML_Error
+processInternalEntity(XML_Parser parser, ENTITY *entity,
+                      XML_Bool betweenDecl);
+static enum XML_Error
+doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+          const char *start, const char *end, const char **endPtr,
+          XML_Bool haveMore);
+static enum XML_Error
+doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr,
+               const char *end, const char **nextPtr, XML_Bool haveMore);
+#ifdef XML_DTD
+static enum XML_Error
+doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr,
+                const char *end, const char **nextPtr, XML_Bool haveMore);
+#endif /* XML_DTD */
+
+static enum XML_Error
+storeAtts(XML_Parser parser, const ENCODING *, const char *s,
+          TAG_NAME *tagNamePtr, BINDING **bindingsPtr);
+static enum XML_Error
+addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
+           const XML_Char *uri, BINDING **bindingsPtr);
+static int
+defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
+                XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser);
+static enum XML_Error
+storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
+                    const char *, const char *, STRING_POOL *);
+static enum XML_Error
+appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
+                     const char *, const char *, STRING_POOL *);
+static ATTRIBUTE_ID *
+getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
+               const char *end);
+static int
+setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
+static enum XML_Error
+storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start,
+                 const char *end);
+static int
+reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
+                            const char *start, const char *end);
+static int
+reportComment(XML_Parser parser, const ENCODING *enc, const char *start,
+              const char *end);
+static void
+reportDefault(XML_Parser parser, const ENCODING *enc, const char *start,
+              const char *end);
+
+static const XML_Char * getContext(XML_Parser parser);
+static XML_Bool
+setContext(XML_Parser parser, const XML_Char *context);
+
+static void FASTCALL normalizePublicId(XML_Char *s);
+
+static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms);
+/* do not call if parentParser != NULL */
+static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
+static void
+dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms);
+static int
+dtdCopy(XML_Parser oldParser,
+        DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms);
+static int
+copyEntityTable(XML_Parser oldParser,
+                HASH_TABLE *, STRING_POOL *, const HASH_TABLE *);
+static NAMED *
+lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize);
+static void FASTCALL
+hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms);
+static void FASTCALL hashTableClear(HASH_TABLE *);
+static void FASTCALL hashTableDestroy(HASH_TABLE *);
+static void FASTCALL
+hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
+static NAMED * FASTCALL hashTableIterNext(HASH_TABLE_ITER *);
+
+static void FASTCALL
+poolInit(STRING_POOL *, const XML_Memory_Handling_Suite *ms);
+static void FASTCALL poolClear(STRING_POOL *);
+static void FASTCALL poolDestroy(STRING_POOL *);
+static XML_Char *
+poolAppend(STRING_POOL *pool, const ENCODING *enc,
+           const char *ptr, const char *end);
+static XML_Char *
+poolStoreString(STRING_POOL *pool, const ENCODING *enc,
+                const char *ptr, const char *end);
+static XML_Bool FASTCALL poolGrow(STRING_POOL *pool);
+static const XML_Char * FASTCALL
+poolCopyString(STRING_POOL *pool, const XML_Char *s);
+static const XML_Char *
+poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n);
+static const XML_Char * FASTCALL
+poolAppendString(STRING_POOL *pool, const XML_Char *s);
+
+static int FASTCALL nextScaffoldPart(XML_Parser parser);
+static XML_Content * build_model(XML_Parser parser);
+static ELEMENT_TYPE *
+getElementType(XML_Parser parser, const ENCODING *enc,
+               const char *ptr, const char *end);
+
+static unsigned long generate_hash_secret_salt(void);
+static XML_Bool startParsing(XML_Parser parser);
+
+static XML_Parser
+parserCreate(const XML_Char *encodingName,
+             const XML_Memory_Handling_Suite *memsuite,
+             const XML_Char *nameSep,
+             DTD *dtd);
+
+static void
+parserInit(XML_Parser parser, const XML_Char *encodingName);
+
+#define poolStart(pool) ((pool)->start)
+#define poolEnd(pool) ((pool)->ptr)
+#define poolLength(pool) ((pool)->ptr - (pool)->start)
+#define poolChop(pool) ((void)--(pool->ptr))
+#define poolLastChar(pool) (((pool)->ptr)[-1])
+#define poolDiscard(pool) ((pool)->ptr = (pool)->start)
+#define poolFinish(pool) ((pool)->start = (pool)->ptr)
+#define poolAppendChar(pool, c) \
+  (((pool)->ptr == (pool)->end && !poolGrow(pool)) \
+   ? 0 \
+   : ((*((pool)->ptr)++ = c), 1))
+
+struct XML_ParserStruct {
+  /* The first member must be userData so that the XML_GetUserData
+     macro works. */
+  void *m_userData;
+  void *m_handlerArg;
+  char *m_buffer;
+  const XML_Memory_Handling_Suite m_mem;
+  /* first character to be parsed */
+  const char *m_bufferPtr;
+  /* past last character to be parsed */
+  char *m_bufferEnd;
+  /* allocated end of buffer */
+  const char *m_bufferLim;
+  XML_Index m_parseEndByteIndex;
+  const char *m_parseEndPtr;
+  XML_Char *m_dataBuf;
+  XML_Char *m_dataBufEnd;
+  XML_StartElementHandler m_startElementHandler;
+  XML_EndElementHandler m_endElementHandler;
+  XML_CharacterDataHandler m_characterDataHandler;
+  XML_ProcessingInstructionHandler m_processingInstructionHandler;
+  XML_CommentHandler m_commentHandler;
+  XML_StartCdataSectionHandler m_startCdataSectionHandler;
+  XML_EndCdataSectionHandler m_endCdataSectionHandler;
+  XML_DefaultHandler m_defaultHandler;
+  XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler;
+  XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler;
+  XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler;
+  XML_NotationDeclHandler m_notationDeclHandler;
+  XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler;
+  XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler;
+  XML_NotStandaloneHandler m_notStandaloneHandler;
+  XML_ExternalEntityRefHandler m_externalEntityRefHandler;
+  XML_Parser m_externalEntityRefHandlerArg;
+  XML_SkippedEntityHandler m_skippedEntityHandler;
+  XML_UnknownEncodingHandler m_unknownEncodingHandler;
+  XML_ElementDeclHandler m_elementDeclHandler;
+  XML_AttlistDeclHandler m_attlistDeclHandler;
+  XML_EntityDeclHandler m_entityDeclHandler;
+  XML_XmlDeclHandler m_xmlDeclHandler;
+  const ENCODING *m_encoding;
+  INIT_ENCODING m_initEncoding;
+  const ENCODING *m_internalEncoding;
+  const XML_Char *m_protocolEncodingName;
+  XML_Bool m_ns;
+  XML_Bool m_ns_triplets;
+  void *m_unknownEncodingMem;
+  void *m_unknownEncodingData;
+  void *m_unknownEncodingHandlerData;
+  void (XMLCALL *m_unknownEncodingRelease)(void *);
+  PROLOG_STATE m_prologState;
+  Processor *m_processor;
+  enum XML_Error m_errorCode;
+  const char *m_eventPtr;
+  const char *m_eventEndPtr;
+  const char *m_positionPtr;
+  OPEN_INTERNAL_ENTITY *m_openInternalEntities;
+  OPEN_INTERNAL_ENTITY *m_freeInternalEntities;
+  XML_Bool m_defaultExpandInternalEntities;
+  int m_tagLevel;
+  ENTITY *m_declEntity;
+  const XML_Char *m_doctypeName;
+  const XML_Char *m_doctypeSysid;
+  const XML_Char *m_doctypePubid;
+  const XML_Char *m_declAttributeType;
+  const XML_Char *m_declNotationName;
+  const XML_Char *m_declNotationPublicId;
+  ELEMENT_TYPE *m_declElementType;
+  ATTRIBUTE_ID *m_declAttributeId;
+  XML_Bool m_declAttributeIsCdata;
+  XML_Bool m_declAttributeIsId;
+  DTD *m_dtd;
+  const XML_Char *m_curBase;
+  TAG *m_tagStack;
+  TAG *m_freeTagList;
+  BINDING *m_inheritedBindings;
+  BINDING *m_freeBindingList;
+  int m_attsSize;
+  int m_nSpecifiedAtts;
+  int m_idAttIndex;
+  ATTRIBUTE *m_atts;
+  NS_ATT *m_nsAtts;
+  unsigned long m_nsAttsVersion;
+  unsigned char m_nsAttsPower;
+#ifdef XML_ATTR_INFO
+  XML_AttrInfo *m_attInfo;
+#endif
+  POSITION m_position;
+  STRING_POOL m_tempPool;
+  STRING_POOL m_temp2Pool;
+  char *m_groupConnector;
+  unsigned int m_groupSize;
+  XML_Char m_namespaceSeparator;
+  XML_Parser m_parentParser;
+  XML_ParsingStatus m_parsingStatus;
+#ifdef XML_DTD
+  XML_Bool m_isParamEntity;
+  XML_Bool m_useForeignDTD;
+  enum XML_ParamEntityParsing m_paramEntityParsing;
+#endif
+  unsigned long m_hash_secret_salt;
+};
+
+#define MALLOC(s) (parser->m_mem.malloc_fcn((s)))
+#define REALLOC(p,s) (parser->m_mem.realloc_fcn((p),(s)))
+#define FREE(p) (parser->m_mem.free_fcn((p)))
+
+#define userData (parser->m_userData)
+#define handlerArg (parser->m_handlerArg)
+#define startElementHandler (parser->m_startElementHandler)
+#define endElementHandler (parser->m_endElementHandler)
+#define characterDataHandler (parser->m_characterDataHandler)
+#define processingInstructionHandler \
+        (parser->m_processingInstructionHandler)
+#define commentHandler (parser->m_commentHandler)
+#define startCdataSectionHandler \
+        (parser->m_startCdataSectionHandler)
+#define endCdataSectionHandler (parser->m_endCdataSectionHandler)
+#define defaultHandler (parser->m_defaultHandler)
+#define startDoctypeDeclHandler (parser->m_startDoctypeDeclHandler)
+#define endDoctypeDeclHandler (parser->m_endDoctypeDeclHandler)
+#define unparsedEntityDeclHandler \
+        (parser->m_unparsedEntityDeclHandler)
+#define notationDeclHandler (parser->m_notationDeclHandler)
+#define startNamespaceDeclHandler \
+        (parser->m_startNamespaceDeclHandler)
+#define endNamespaceDeclHandler (parser->m_endNamespaceDeclHandler)
+#define notStandaloneHandler (parser->m_notStandaloneHandler)
+#define externalEntityRefHandler \
+        (parser->m_externalEntityRefHandler)
+#define externalEntityRefHandlerArg \
+        (parser->m_externalEntityRefHandlerArg)
+#define internalEntityRefHandler \
+        (parser->m_internalEntityRefHandler)
+#define skippedEntityHandler (parser->m_skippedEntityHandler)
+#define unknownEncodingHandler (parser->m_unknownEncodingHandler)
+#define elementDeclHandler (parser->m_elementDeclHandler)
+#define attlistDeclHandler (parser->m_attlistDeclHandler)
+#define entityDeclHandler (parser->m_entityDeclHandler)
+#define xmlDeclHandler (parser->m_xmlDeclHandler)
+#define encoding (parser->m_encoding)
+#define initEncoding (parser->m_initEncoding)
+#define internalEncoding (parser->m_internalEncoding)
+#define unknownEncodingMem (parser->m_unknownEncodingMem)
+#define unknownEncodingData (parser->m_unknownEncodingData)
+#define unknownEncodingHandlerData \
+  (parser->m_unknownEncodingHandlerData)
+#define unknownEncodingRelease (parser->m_unknownEncodingRelease)
+#define protocolEncodingName (parser->m_protocolEncodingName)
+#define ns (parser->m_ns)
+#define ns_triplets (parser->m_ns_triplets)
+#define prologState (parser->m_prologState)
+#define processor (parser->m_processor)
+#define errorCode (parser->m_errorCode)
+#define eventPtr (parser->m_eventPtr)
+#define eventEndPtr (parser->m_eventEndPtr)
+#define positionPtr (parser->m_positionPtr)
+#define position (parser->m_position)
+#define openInternalEntities (parser->m_openInternalEntities)
+#define freeInternalEntities (parser->m_freeInternalEntities)
+#define defaultExpandInternalEntities \
+        (parser->m_defaultExpandInternalEntities)
+#define tagLevel (parser->m_tagLevel)
+#define buffer (parser->m_buffer)
+#define bufferPtr (parser->m_bufferPtr)
+#define bufferEnd (parser->m_bufferEnd)
+#define parseEndByteIndex (parser->m_parseEndByteIndex)
+#define parseEndPtr (parser->m_parseEndPtr)
+#define bufferLim (parser->m_bufferLim)
+#define dataBuf (parser->m_dataBuf)
+#define dataBufEnd (parser->m_dataBufEnd)
+#define _dtd (parser->m_dtd)
+#define curBase (parser->m_curBase)
+#define declEntity (parser->m_declEntity)
+#define doctypeName (parser->m_doctypeName)
+#define doctypeSysid (parser->m_doctypeSysid)
+#define doctypePubid (parser->m_doctypePubid)
+#define declAttributeType (parser->m_declAttributeType)
+#define declNotationName (parser->m_declNotationName)
+#define declNotationPublicId (parser->m_declNotationPublicId)
+#define declElementType (parser->m_declElementType)
+#define declAttributeId (parser->m_declAttributeId)
+#define declAttributeIsCdata (parser->m_declAttributeIsCdata)
+#define declAttributeIsId (parser->m_declAttributeIsId)
+#define freeTagList (parser->m_freeTagList)
+#define freeBindingList (parser->m_freeBindingList)
+#define inheritedBindings (parser->m_inheritedBindings)
+#define tagStack (parser->m_tagStack)
+#define atts (parser->m_atts)
+#define attsSize (parser->m_attsSize)
+#define nSpecifiedAtts (parser->m_nSpecifiedAtts)
+#define idAttIndex (parser->m_idAttIndex)
+#define nsAtts (parser->m_nsAtts)
+#define nsAttsVersion (parser->m_nsAttsVersion)
+#define nsAttsPower (parser->m_nsAttsPower)
+#define attInfo (parser->m_attInfo)
+#define tempPool (parser->m_tempPool)
+#define temp2Pool (parser->m_temp2Pool)
+#define groupConnector (parser->m_groupConnector)
+#define groupSize (parser->m_groupSize)
+#define namespaceSeparator (parser->m_namespaceSeparator)
+#define parentParser (parser->m_parentParser)
+#define ps_parsing (parser->m_parsingStatus.parsing)
+#define ps_finalBuffer (parser->m_parsingStatus.finalBuffer)
+#ifdef XML_DTD
+#define isParamEntity (parser->m_isParamEntity)
+#define useForeignDTD (parser->m_useForeignDTD)
+#define paramEntityParsing (parser->m_paramEntityParsing)
+#endif /* XML_DTD */
+#define hash_secret_salt (parser->m_hash_secret_salt)
+
+XML_Parser XMLCALL
+XML_ParserCreate(const XML_Char *encodingName)
+{
+  return XML_ParserCreate_MM(encodingName, NULL, NULL);
+}
+
+XML_Parser XMLCALL
+XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep)
+{
+  XML_Char tmp[2];
+  *tmp = nsSep;
+  return XML_ParserCreate_MM(encodingName, NULL, tmp);
+}
+
+static const XML_Char implicitContext[] = {
+  ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h, ASCII_t, ASCII_t, ASCII_p,
+  ASCII_COLON, ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w,
+  ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g,
+  ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, ASCII_SLASH, ASCII_1, ASCII_9,
+  ASCII_9, ASCII_8, ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m, ASCII_e,
+  ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_e, '\0'
+};
+
+static unsigned long
+generate_hash_secret_salt(void)
+{
+  unsigned int seed = time(NULL) % UINT_MAX;
+  srand(seed);
+  return rand();
+}
+
+static XML_Bool  /* only valid for root parser */
+startParsing(XML_Parser parser)
+{
+    /* hash functions must be initialized before setContext() is called */
+    if (hash_secret_salt == 0)
+      hash_secret_salt = generate_hash_secret_salt();
+    if (ns) {
+      /* implicit context only set for root parser, since child
+         parsers (i.e. external entity parsers) will inherit it
+      */
+      return setContext(parser, implicitContext);
+    }
+    return XML_TRUE;
+}
+
+XML_Parser XMLCALL
+XML_ParserCreate_MM(const XML_Char *encodingName,
+                    const XML_Memory_Handling_Suite *memsuite,
+                    const XML_Char *nameSep)
+{
+  return parserCreate(encodingName, memsuite, nameSep, NULL);
+}
+
+static XML_Parser
+parserCreate(const XML_Char *encodingName,
+             const XML_Memory_Handling_Suite *memsuite,
+             const XML_Char *nameSep,
+             DTD *dtd)
+{
+  XML_Parser parser;
+
+  if (memsuite) {
+    XML_Memory_Handling_Suite *mtemp;
+    parser = (XML_Parser)
+      memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
+    if (parser != NULL) {
+      mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
+      mtemp->malloc_fcn = memsuite->malloc_fcn;
+      mtemp->realloc_fcn = memsuite->realloc_fcn;
+      mtemp->free_fcn = memsuite->free_fcn;
+    }
+  }
+  else {
+    XML_Memory_Handling_Suite *mtemp;
+    parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct));
+    if (parser != NULL) {
+      mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
+      mtemp->malloc_fcn = malloc;
+      mtemp->realloc_fcn = realloc;
+      mtemp->free_fcn = free;
+    }
+  }
+
+  if (!parser)
+    return parser;
+
+  buffer = NULL;
+  bufferLim = NULL;
+
+  attsSize = INIT_ATTS_SIZE;
+  atts = (ATTRIBUTE *)MALLOC(attsSize * sizeof(ATTRIBUTE));
+  if (atts == NULL) {
+    FREE(parser);
+    return NULL;
+  }
+#ifdef XML_ATTR_INFO
+  attInfo = (XML_AttrInfo*)MALLOC(attsSize * sizeof(XML_AttrInfo));
+  if (attInfo == NULL) {
+    FREE(atts);
+    FREE(parser);
+    return NULL;
+  }
+#endif
+  dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char));
+  if (dataBuf == NULL) {
+    FREE(atts);
+#ifdef XML_ATTR_INFO
+    FREE(attInfo);
+#endif
+    FREE(parser);
+    return NULL;
+  }
+  dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE;
+
+  if (dtd)
+    _dtd = dtd;
+  else {
+    _dtd = dtdCreate(&parser->m_mem);
+    if (_dtd == NULL) {
+      FREE(dataBuf);
+      FREE(atts);
+#ifdef XML_ATTR_INFO
+      FREE(attInfo);
+#endif
+      FREE(parser);
+      return NULL;
+    }
+  }
+
+  freeBindingList = NULL;
+  freeTagList = NULL;
+  freeInternalEntities = NULL;
+
+  groupSize = 0;
+  groupConnector = NULL;
+
+  unknownEncodingHandler = NULL;
+  unknownEncodingHandlerData = NULL;
+
+  namespaceSeparator = ASCII_EXCL;
+  ns = XML_FALSE;
+  ns_triplets = XML_FALSE;
+
+  nsAtts = NULL;
+  nsAttsVersion = 0;
+  nsAttsPower = 0;
+
+  poolInit(&tempPool, &(parser->m_mem));
+  poolInit(&temp2Pool, &(parser->m_mem));
+  parserInit(parser, encodingName);
+
+  if (encodingName && !protocolEncodingName) {
+    XML_ParserFree(parser);
+    return NULL;
+  }
+
+  if (nameSep) {
+    ns = XML_TRUE;
+    internalEncoding = XmlGetInternalEncodingNS();
+    namespaceSeparator = *nameSep;
+  }
+  else {
+    internalEncoding = XmlGetInternalEncoding();
+  }
+
+  return parser;
+}
+
+static void
+parserInit(XML_Parser parser, const XML_Char *encodingName)
+{
+  processor = prologInitProcessor;
+  XmlPrologStateInit(&prologState);
+  protocolEncodingName = (encodingName != NULL
+                          ? poolCopyString(&tempPool, encodingName)
+                          : NULL);
+  curBase = NULL;
+  XmlInitEncoding(&initEncoding, &encoding, 0);
+  userData = NULL;
+  handlerArg = NULL;
+  startElementHandler = NULL;
+  endElementHandler = NULL;
+  characterDataHandler = NULL;
+  processingInstructionHandler = NULL;
+  commentHandler = NULL;
+  startCdataSectionHandler = NULL;
+  endCdataSectionHandler = NULL;
+  defaultHandler = NULL;
+  startDoctypeDeclHandler = NULL;
+  endDoctypeDeclHandler = NULL;
+  unparsedEntityDeclHandler = NULL;
+  notationDeclHandler = NULL;
+  startNamespaceDeclHandler = NULL;
+  endNamespaceDeclHandler = NULL;
+  notStandaloneHandler = NULL;
+  externalEntityRefHandler = NULL;
+  externalEntityRefHandlerArg = parser;
+  skippedEntityHandler = NULL;
+  elementDeclHandler = NULL;
+  attlistDeclHandler = NULL;
+  entityDeclHandler = NULL;
+  xmlDeclHandler = NULL;
+  bufferPtr = buffer;
+  bufferEnd = buffer;
+  parseEndByteIndex = 0;
+  parseEndPtr = NULL;
+  declElementType = NULL;
+  declAttributeId = NULL;
+  declEntity = NULL;
+  doctypeName = NULL;
+  doctypeSysid = NULL;
+  doctypePubid = NULL;
+  declAttributeType = NULL;
+  declNotationName = NULL;
+  declNotationPublicId = NULL;
+  declAttributeIsCdata = XML_FALSE;
+  declAttributeIsId = XML_FALSE;
+  memset(&position, 0, sizeof(POSITION));
+  errorCode = XML_ERROR_NONE;
+  eventPtr = NULL;
+  eventEndPtr = NULL;
+  positionPtr = NULL;
+  openInternalEntities = NULL;
+  defaultExpandInternalEntities = XML_TRUE;
+  tagLevel = 0;
+  tagStack = NULL;
+  inheritedBindings = NULL;
+  nSpecifiedAtts = 0;
+  unknownEncodingMem = NULL;
+  unknownEncodingRelease = NULL;
+  unknownEncodingData = NULL;
+  parentParser = NULL;
+  ps_parsing = XML_INITIALIZED;
+#ifdef XML_DTD
+  isParamEntity = XML_FALSE;
+  useForeignDTD = XML_FALSE;
+  paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+#endif
+  hash_secret_salt = 0;
+}
+
+/* moves list of bindings to freeBindingList */
+static void FASTCALL
+moveToFreeBindingList(XML_Parser parser, BINDING *bindings)
+{
+  while (bindings) {
+    BINDING *b = bindings;
+    bindings = bindings->nextTagBinding;
+    b->nextTagBinding = freeBindingList;
+    freeBindingList = b;
+  }
+}
+
+XML_Bool XMLCALL
+XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)
+{
+  TAG *tStk;
+  OPEN_INTERNAL_ENTITY *openEntityList;
+  if (parentParser)
+    return XML_FALSE;
+  /* move tagStack to freeTagList */
+  tStk = tagStack;
+  while (tStk) {
+    TAG *tag = tStk;
+    tStk = tStk->parent;
+    tag->parent = freeTagList;
+    moveToFreeBindingList(parser, tag->bindings);
+    tag->bindings = NULL;
+    freeTagList = tag;
+  }
+  /* move openInternalEntities to freeInternalEntities */
+  openEntityList = openInternalEntities;
+  while (openEntityList) {
+    OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
+    openEntityList = openEntity->next;
+    openEntity->next = freeInternalEntities;
+    freeInternalEntities = openEntity;
+  }
+  moveToFreeBindingList(parser, inheritedBindings);
+  FREE(unknownEncodingMem);
+  if (unknownEncodingRelease)
+    unknownEncodingRelease(unknownEncodingData);
+  poolClear(&tempPool);
+  poolClear(&temp2Pool);
+  parserInit(parser, encodingName);
+  dtdReset(_dtd, &parser->m_mem);
+  return XML_TRUE;
+}
+
+enum XML_Status XMLCALL
+XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName)
+{
+  /* Block after XML_Parse()/XML_ParseBuffer() has been called.
+     XXX There's no way for the caller to determine which of the
+     XXX possible error cases caused the XML_STATUS_ERROR return.
+  */
+  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+    return XML_STATUS_ERROR;
+  if (encodingName == NULL)
+    protocolEncodingName = NULL;
+  else {
+    protocolEncodingName = poolCopyString(&tempPool, encodingName);
+    if (!protocolEncodingName)
+      return XML_STATUS_ERROR;
+  }
+  return XML_STATUS_OK;
+}
+
+XML_Parser XMLCALL
+XML_ExternalEntityParserCreate(XML_Parser oldParser,
+                               const XML_Char *context,
+                               const XML_Char *encodingName)
+{
+  XML_Parser parser = oldParser;
+  DTD *newDtd = NULL;
+  DTD *oldDtd = _dtd;
+  XML_StartElementHandler oldStartElementHandler = startElementHandler;
+  XML_EndElementHandler oldEndElementHandler = endElementHandler;
+  XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler;
+  XML_ProcessingInstructionHandler oldProcessingInstructionHandler
+      = processingInstructionHandler;
+  XML_CommentHandler oldCommentHandler = commentHandler;
+  XML_StartCdataSectionHandler oldStartCdataSectionHandler
+      = startCdataSectionHandler;
+  XML_EndCdataSectionHandler oldEndCdataSectionHandler
+      = endCdataSectionHandler;
+  XML_DefaultHandler oldDefaultHandler = defaultHandler;
+  XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler
+      = unparsedEntityDeclHandler;
+  XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler;
+  XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler
+      = startNamespaceDeclHandler;
+  XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler
+      = endNamespaceDeclHandler;
+  XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler;
+  XML_ExternalEntityRefHandler oldExternalEntityRefHandler
+      = externalEntityRefHandler;
+  XML_SkippedEntityHandler oldSkippedEntityHandler = skippedEntityHandler;
+  XML_UnknownEncodingHandler oldUnknownEncodingHandler
+      = unknownEncodingHandler;
+  XML_ElementDeclHandler oldElementDeclHandler = elementDeclHandler;
+  XML_AttlistDeclHandler oldAttlistDeclHandler = attlistDeclHandler;
+  XML_EntityDeclHandler oldEntityDeclHandler = entityDeclHandler;
+  XML_XmlDeclHandler oldXmlDeclHandler = xmlDeclHandler;
+  ELEMENT_TYPE * oldDeclElementType = declElementType;
+
+  void *oldUserData = userData;
+  void *oldHandlerArg = handlerArg;
+  XML_Bool oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
+  XML_Parser oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
+#ifdef XML_DTD
+  enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing;
+  int oldInEntityValue = prologState.inEntityValue;
+#endif
+  XML_Bool oldns_triplets = ns_triplets;
+  /* Note that the new parser shares the same hash secret as the old
+     parser, so that dtdCopy and copyEntityTable can lookup values
+     from hash tables associated with either parser without us having
+     to worry which hash secrets each table has.
+  */
+  unsigned long oldhash_secret_salt = hash_secret_salt;
+
+#ifdef XML_DTD
+  if (!context)
+    newDtd = oldDtd;
+#endif /* XML_DTD */
+
+  /* Note that the magical uses of the pre-processor to make field
+     access look more like C++ require that `parser' be overwritten
+     here.  This makes this function more painful to follow than it
+     would be otherwise.
+  */
+  if (ns) {
+    XML_Char tmp[2];
+    *tmp = namespaceSeparator;
+    parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
+  }
+  else {
+    parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
+  }
+
+  if (!parser)
+    return NULL;
+
+  startElementHandler = oldStartElementHandler;
+  endElementHandler = oldEndElementHandler;
+  characterDataHandler = oldCharacterDataHandler;
+  processingInstructionHandler = oldProcessingInstructionHandler;
+  commentHandler = oldCommentHandler;
+  startCdataSectionHandler = oldStartCdataSectionHandler;
+  endCdataSectionHandler = oldEndCdataSectionHandler;
+  defaultHandler = oldDefaultHandler;
+  unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler;
+  notationDeclHandler = oldNotationDeclHandler;
+  startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
+  endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
+  notStandaloneHandler = oldNotStandaloneHandler;
+  externalEntityRefHandler = oldExternalEntityRefHandler;
+  skippedEntityHandler = oldSkippedEntityHandler;
+  unknownEncodingHandler = oldUnknownEncodingHandler;
+  elementDeclHandler = oldElementDeclHandler;
+  attlistDeclHandler = oldAttlistDeclHandler;
+  entityDeclHandler = oldEntityDeclHandler;
+  xmlDeclHandler = oldXmlDeclHandler;
+  declElementType = oldDeclElementType;
+  userData = oldUserData;
+  if (oldUserData == oldHandlerArg)
+    handlerArg = userData;
+  else
+    handlerArg = parser;
+  if (oldExternalEntityRefHandlerArg != oldParser)
+    externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
+  defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
+  ns_triplets = oldns_triplets;
+  hash_secret_salt = oldhash_secret_salt;
+  parentParser = oldParser;
+#ifdef XML_DTD
+  paramEntityParsing = oldParamEntityParsing;
+  prologState.inEntityValue = oldInEntityValue;
+  if (context) {
+#endif /* XML_DTD */
+    if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem)
+      || !setContext(parser, context)) {
+      XML_ParserFree(parser);
+      return NULL;
+    }
+    processor = externalEntityInitProcessor;
+#ifdef XML_DTD
+  }
+  else {
+    /* The DTD instance referenced by _dtd is shared between the document's
+       root parser and external PE parsers, therefore one does not need to
+       call setContext. In addition, one also *must* not call setContext,
+       because this would overwrite existing prefix->binding pointers in
+       _dtd with ones that get destroyed with the external PE parser.
+       This would leave those prefixes with dangling pointers.
+    */
+    isParamEntity = XML_TRUE;
+    XmlPrologStateInitExternalEntity(&prologState);
+    processor = externalParEntInitProcessor;
+  }
+#endif /* XML_DTD */
+  return parser;
+}
+
+static void FASTCALL
+destroyBindings(BINDING *bindings, XML_Parser parser)
+{
+  for (;;) {
+    BINDING *b = bindings;
+    if (!b)
+      break;
+    bindings = b->nextTagBinding;
+    FREE(b->uri);
+    FREE(b);
+  }
+}
+
+void XMLCALL
+XML_ParserFree(XML_Parser parser)
+{
+  TAG *tagList;
+  OPEN_INTERNAL_ENTITY *entityList;
+  if (parser == NULL)
+    return;
+  /* free tagStack and freeTagList */
+  tagList = tagStack;
+  for (;;) {
+    TAG *p;
+    if (tagList == NULL) {
+      if (freeTagList == NULL)
+        break;
+      tagList = freeTagList;
+      freeTagList = NULL;
+    }
+    p = tagList;
+    tagList = tagList->parent;
+    FREE(p->buf);
+    destroyBindings(p->bindings, parser);
+    FREE(p);
+  }
+  /* free openInternalEntities and freeInternalEntities */
+  entityList = openInternalEntities;
+  for (;;) {
+    OPEN_INTERNAL_ENTITY *openEntity;
+    if (entityList == NULL) {
+      if (freeInternalEntities == NULL)
+        break;
+      entityList = freeInternalEntities;
+      freeInternalEntities = NULL;
+    }
+    openEntity = entityList;
+    entityList = entityList->next;
+    FREE(openEntity);
+  }
+
+  destroyBindings(freeBindingList, parser);
+  destroyBindings(inheritedBindings, parser);
+  poolDestroy(&tempPool);
+  poolDestroy(&temp2Pool);
+#ifdef XML_DTD
+  /* external parameter entity parsers share the DTD structure
+     parser->m_dtd with the root parser, so we must not destroy it
+  */
+  if (!isParamEntity && _dtd)
+#else
+  if (_dtd)
+#endif /* XML_DTD */
+    dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem);
+  FREE((void *)atts);
+#ifdef XML_ATTR_INFO
+  FREE((void *)attInfo);
+#endif
+  FREE(groupConnector);
+  FREE(buffer);
+  FREE(dataBuf);
+  FREE(nsAtts);
+  FREE(unknownEncodingMem);
+  if (unknownEncodingRelease)
+    unknownEncodingRelease(unknownEncodingData);
+  FREE(parser);
+}
+
+void XMLCALL
+XML_UseParserAsHandlerArg(XML_Parser parser)
+{
+  handlerArg = parser;
+}
+
+enum XML_Error XMLCALL
+XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD)
+{
+#ifdef XML_DTD
+  /* block after XML_Parse()/XML_ParseBuffer() has been called */
+  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+    return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING;
+  useForeignDTD = useDTD;
+  return XML_ERROR_NONE;
+#else
+  return XML_ERROR_FEATURE_REQUIRES_XML_DTD;
+#endif
+}
+
+void XMLCALL
+XML_SetReturnNSTriplet(XML_Parser parser, int do_nst)
+{
+  /* block after XML_Parse()/XML_ParseBuffer() has been called */
+  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+    return;
+  ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
+}
+
+void XMLCALL
+XML_SetUserData(XML_Parser parser, void *p)
+{
+  if (handlerArg == userData)
+    handlerArg = userData = p;
+  else
+    userData = p;
+}
+
+enum XML_Status XMLCALL
+XML_SetBase(XML_Parser parser, const XML_Char *p)
+{
+  if (p) {
+    p = poolCopyString(&_dtd->pool, p);
+    if (!p)
+      return XML_STATUS_ERROR;
+    curBase = p;
+  }
+  else
+    curBase = NULL;
+  return XML_STATUS_OK;
+}
+
+const XML_Char * XMLCALL
+XML_GetBase(XML_Parser parser)
+{
+  return curBase;
+}
+
+int XMLCALL
+XML_GetSpecifiedAttributeCount(XML_Parser parser)
+{
+  return nSpecifiedAtts;
+}
+
+int XMLCALL
+XML_GetIdAttributeIndex(XML_Parser parser)
+{
+  return idAttIndex;
+}
+
+#ifdef XML_ATTR_INFO
+const XML_AttrInfo * XMLCALL
+XML_GetAttributeInfo(XML_Parser parser)
+{
+  return attInfo;
+}
+#endif
+
+void XMLCALL
+XML_SetElementHandler(XML_Parser parser,
+                      XML_StartElementHandler start,
+                      XML_EndElementHandler end)
+{
+  startElementHandler = start;
+  endElementHandler = end;
+}
+
+void XMLCALL
+XML_SetStartElementHandler(XML_Parser parser,
+                           XML_StartElementHandler start) {
+  startElementHandler = start;
+}
+
+void XMLCALL
+XML_SetEndElementHandler(XML_Parser parser,
+                         XML_EndElementHandler end) {
+  endElementHandler = end;
+}
+
+void XMLCALL
+XML_SetCharacterDataHandler(XML_Parser parser,
+                            XML_CharacterDataHandler handler)
+{
+  characterDataHandler = handler;
+}
+
+void XMLCALL
+XML_SetProcessingInstructionHandler(XML_Parser parser,
+                                    XML_ProcessingInstructionHandler handler)
+{
+  processingInstructionHandler = handler;
+}
+
+void XMLCALL
+XML_SetCommentHandler(XML_Parser parser,
+                      XML_CommentHandler handler)
+{
+  commentHandler = handler;
+}
+
+void XMLCALL
+XML_SetCdataSectionHandler(XML_Parser parser,
+                           XML_StartCdataSectionHandler start,
+                           XML_EndCdataSectionHandler end)
+{
+  startCdataSectionHandler = start;
+  endCdataSectionHandler = end;
+}
+
+void XMLCALL
+XML_SetStartCdataSectionHandler(XML_Parser parser,
+                                XML_StartCdataSectionHandler start) {
+  startCdataSectionHandler = start;
+}
+
+void XMLCALL
+XML_SetEndCdataSectionHandler(XML_Parser parser,
+                              XML_EndCdataSectionHandler end) {
+  endCdataSectionHandler = end;
+}
+
+void XMLCALL
+XML_SetDefaultHandler(XML_Parser parser,
+                      XML_DefaultHandler handler)
+{
+  defaultHandler = handler;
+  defaultExpandInternalEntities = XML_FALSE;
+}
+
+void XMLCALL
+XML_SetDefaultHandlerExpand(XML_Parser parser,
+                            XML_DefaultHandler handler)
+{
+  defaultHandler = handler;
+  defaultExpandInternalEntities = XML_TRUE;
+}
+
+void XMLCALL
+XML_SetDoctypeDeclHandler(XML_Parser parser,
+                          XML_StartDoctypeDeclHandler start,
+                          XML_EndDoctypeDeclHandler end)
+{
+  startDoctypeDeclHandler = start;
+  endDoctypeDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetStartDoctypeDeclHandler(XML_Parser parser,
+                               XML_StartDoctypeDeclHandler start) {
+  startDoctypeDeclHandler = start;
+}
+
+void XMLCALL
+XML_SetEndDoctypeDeclHandler(XML_Parser parser,
+                             XML_EndDoctypeDeclHandler end) {
+  endDoctypeDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
+                                 XML_UnparsedEntityDeclHandler handler)
+{
+  unparsedEntityDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetNotationDeclHandler(XML_Parser parser,
+                           XML_NotationDeclHandler handler)
+{
+  notationDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetNamespaceDeclHandler(XML_Parser parser,
+                            XML_StartNamespaceDeclHandler start,
+                            XML_EndNamespaceDeclHandler end)
+{
+  startNamespaceDeclHandler = start;
+  endNamespaceDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetStartNamespaceDeclHandler(XML_Parser parser,
+                                 XML_StartNamespaceDeclHandler start) {
+  startNamespaceDeclHandler = start;
+}
+
+void XMLCALL
+XML_SetEndNamespaceDeclHandler(XML_Parser parser,
+                               XML_EndNamespaceDeclHandler end) {
+  endNamespaceDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetNotStandaloneHandler(XML_Parser parser,
+                            XML_NotStandaloneHandler handler)
+{
+  notStandaloneHandler = handler;
+}
+
+void XMLCALL
+XML_SetExternalEntityRefHandler(XML_Parser parser,
+                                XML_ExternalEntityRefHandler handler)
+{
+  externalEntityRefHandler = handler;
+}
+
+void XMLCALL
+XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg)
+{
+  if (arg)
+    externalEntityRefHandlerArg = (XML_Parser)arg;
+  else
+    externalEntityRefHandlerArg = parser;
+}
+
+void XMLCALL
+XML_SetSkippedEntityHandler(XML_Parser parser,
+                            XML_SkippedEntityHandler handler)
+{
+  skippedEntityHandler = handler;
+}
+
+void XMLCALL
+XML_SetUnknownEncodingHandler(XML_Parser parser,
+                              XML_UnknownEncodingHandler handler,
+                              void *data)
+{
+  unknownEncodingHandler = handler;
+  unknownEncodingHandlerData = data;
+}
+
+void XMLCALL
+XML_SetElementDeclHandler(XML_Parser parser,
+                          XML_ElementDeclHandler eldecl)
+{
+  elementDeclHandler = eldecl;
+}
+
+void XMLCALL
+XML_SetAttlistDeclHandler(XML_Parser parser,
+                          XML_AttlistDeclHandler attdecl)
+{
+  attlistDeclHandler = attdecl;
+}
+
+void XMLCALL
+XML_SetEntityDeclHandler(XML_Parser parser,
+                         XML_EntityDeclHandler handler)
+{
+  entityDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetXmlDeclHandler(XML_Parser parser,
+                      XML_XmlDeclHandler handler) {
+  xmlDeclHandler = handler;
+}
+
+int XMLCALL
+XML_SetParamEntityParsing(XML_Parser parser,
+                          enum XML_ParamEntityParsing peParsing)
+{
+  /* block after XML_Parse()/XML_ParseBuffer() has been called */
+  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+    return 0;
+#ifdef XML_DTD
+  paramEntityParsing = peParsing;
+  return 1;
+#else
+  return peParsing == XML_PARAM_ENTITY_PARSING_NEVER;
+#endif
+}
+
+int XMLCALL
+XML_SetHashSalt(XML_Parser parser,
+                unsigned long hash_salt)
+{
+  /* block after XML_Parse()/XML_ParseBuffer() has been called */
+  if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+    return 0;
+  hash_secret_salt = hash_salt;
+  return 1;
+}
+
+enum XML_Status XMLCALL
+XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
+{
+  switch (ps_parsing) {
+  case XML_SUSPENDED:
+    errorCode = XML_ERROR_SUSPENDED;
+    return XML_STATUS_ERROR;
+  case XML_FINISHED:
+    errorCode = XML_ERROR_FINISHED;
+    return XML_STATUS_ERROR;
+  case XML_INITIALIZED:
+    if (parentParser == NULL && !startParsing(parser)) {
+      errorCode = XML_ERROR_NO_MEMORY;
+      return XML_STATUS_ERROR;
+    }
+  default:
+    ps_parsing = XML_PARSING;
+  }
+
+  if (len == 0) {
+    ps_finalBuffer = (XML_Bool)isFinal;
+    if (!isFinal)
+      return XML_STATUS_OK;
+    positionPtr = bufferPtr;
+    parseEndPtr = bufferEnd;
+
+    /* If data are left over from last buffer, and we now know that these
+       data are the final chunk of input, then we have to check them again
+       to detect errors based on that fact.
+    */
+    errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+
+    if (errorCode == XML_ERROR_NONE) {
+      switch (ps_parsing) {
+      case XML_SUSPENDED:
+        XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+        positionPtr = bufferPtr;
+        return XML_STATUS_SUSPENDED;
+      case XML_INITIALIZED:
+      case XML_PARSING:
+        ps_parsing = XML_FINISHED;
+        /* fall through */
+      default:
+        return XML_STATUS_OK;
+      }
+    }
+    eventEndPtr = eventPtr;
+    processor = errorProcessor;
+    return XML_STATUS_ERROR;
+  }
+#ifndef XML_CONTEXT_BYTES
+  else if (bufferPtr == bufferEnd) {
+    const char *end;
+    int nLeftOver;
+    enum XML_Error result;
+    parseEndByteIndex += len;
+    positionPtr = s;
+    ps_finalBuffer = (XML_Bool)isFinal;
+
+    errorCode = processor(parser, s, parseEndPtr = s + len, &end);
+
+    if (errorCode != XML_ERROR_NONE) {
+      eventEndPtr = eventPtr;
+      processor = errorProcessor;
+      return XML_STATUS_ERROR;
+    }
+    else {
+      switch (ps_parsing) {
+      case XML_SUSPENDED:
+        result = XML_STATUS_SUSPENDED;
+        break;
+      case XML_INITIALIZED:
+      case XML_PARSING:
+        if (isFinal) {
+          ps_parsing = XML_FINISHED;
+          return XML_STATUS_OK;
+        }
+      /* fall through */
+      default:
+        result = XML_STATUS_OK;
+      }
+    }
+
+    XmlUpdatePosition(encoding, positionPtr, end, &position);
+    nLeftOver = s + len - end;
+    if (nLeftOver) {
+      if (buffer == NULL || nLeftOver > bufferLim - buffer) {
+        /* FIXME avoid integer overflow */
+        char *temp;
+        temp = (buffer == NULL
+                ? (char *)MALLOC(len * 2)
+                : (char *)REALLOC(buffer, len * 2));
+        if (temp == NULL) {
+          errorCode = XML_ERROR_NO_MEMORY;
+          eventPtr = eventEndPtr = NULL;
+          processor = errorProcessor;
+          return XML_STATUS_ERROR;
+        }
+        buffer = temp;
+        bufferLim = buffer + len * 2;
+      }
+      memcpy(buffer, end, nLeftOver);
+    }
+    bufferPtr = buffer;
+    bufferEnd = buffer + nLeftOver;
+    positionPtr = bufferPtr;
+    parseEndPtr = bufferEnd;
+    eventPtr = bufferPtr;
+    eventEndPtr = bufferPtr;
+    return result;
+  }
+#endif  /* not defined XML_CONTEXT_BYTES */
+  else {
+    void *buff = XML_GetBuffer(parser, len);
+    if (buff == NULL)
+      return XML_STATUS_ERROR;
+    else {
+      memcpy(buff, s, len);
+      return XML_ParseBuffer(parser, len, isFinal);
+    }
+  }
+}
+
+enum XML_Status XMLCALL
+XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
+{
+  const char *start;
+  enum XML_Status result = XML_STATUS_OK;
+
+  switch (ps_parsing) {
+  case XML_SUSPENDED:
+    errorCode = XML_ERROR_SUSPENDED;
+    return XML_STATUS_ERROR;
+  case XML_FINISHED:
+    errorCode = XML_ERROR_FINISHED;
+    return XML_STATUS_ERROR;
+  case XML_INITIALIZED:
+    if (parentParser == NULL && !startParsing(parser)) {
+      errorCode = XML_ERROR_NO_MEMORY;
+      return XML_STATUS_ERROR;
+    }
+  default:
+    ps_parsing = XML_PARSING;
+  }
+
+  start = bufferPtr;
+  positionPtr = start;
+  bufferEnd += len;
+  parseEndPtr = bufferEnd;
+  parseEndByteIndex += len;
+  ps_finalBuffer = (XML_Bool)isFinal;
+
+  errorCode = processor(parser, start, parseEndPtr, &bufferPtr);
+
+  if (errorCode != XML_ERROR_NONE) {
+    eventEndPtr = eventPtr;
+    processor = errorProcessor;
+    return XML_STATUS_ERROR;
+  }
+  else {
+    switch (ps_parsing) {
+    case XML_SUSPENDED:
+      result = XML_STATUS_SUSPENDED;
+      break;
+    case XML_INITIALIZED:
+    case XML_PARSING:
+      if (isFinal) {
+        ps_parsing = XML_FINISHED;
+        return result;
+      }
+    default: ;  /* should not happen */
+    }
+  }
+
+  XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+  positionPtr = bufferPtr;
+  return result;
+}
+
+void * XMLCALL
+XML_GetBuffer(XML_Parser parser, int len)
+{
+  switch (ps_parsing) {
+  case XML_SUSPENDED:
+    errorCode = XML_ERROR_SUSPENDED;
+    return NULL;
+  case XML_FINISHED:
+    errorCode = XML_ERROR_FINISHED;
+    return NULL;
+  default: ;
+  }
+
+  if (len > bufferLim - bufferEnd) {
+    /* FIXME avoid integer overflow */
+    int neededSize = len + (int)(bufferEnd - bufferPtr);
+#ifdef XML_CONTEXT_BYTES
+    int keep = (int)(bufferPtr - buffer);
+
+    if (keep > XML_CONTEXT_BYTES)
+      keep = XML_CONTEXT_BYTES;
+    neededSize += keep;
+#endif  /* defined XML_CONTEXT_BYTES */
+    if (neededSize  <= bufferLim - buffer) {
+#ifdef XML_CONTEXT_BYTES
+      if (keep < bufferPtr - buffer) {
+        int offset = (int)(bufferPtr - buffer) - keep;
+        memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep);
+        bufferEnd -= offset;
+        bufferPtr -= offset;
+      }
+#else
+      memmove(buffer, bufferPtr, bufferEnd - bufferPtr);
+      bufferEnd = buffer + (bufferEnd - bufferPtr);
+      bufferPtr = buffer;
+#endif  /* not defined XML_CONTEXT_BYTES */
+    }
+    else {
+      char *newBuf;
+      int bufferSize = (int)(bufferLim - bufferPtr);
+      if (bufferSize == 0)
+        bufferSize = INIT_BUFFER_SIZE;
+      do {
+        bufferSize *= 2;
+      } while (bufferSize < neededSize);
+      newBuf = (char *)MALLOC(bufferSize);
+      if (newBuf == 0) {
+        errorCode = XML_ERROR_NO_MEMORY;
+        return NULL;
+      }
+      bufferLim = newBuf + bufferSize;
+#ifdef XML_CONTEXT_BYTES
+      if (bufferPtr) {
+        int keep = (int)(bufferPtr - buffer);
+        if (keep > XML_CONTEXT_BYTES)
+          keep = XML_CONTEXT_BYTES;
+        memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep);
+        FREE(buffer);
+        buffer = newBuf;
+        bufferEnd = buffer + (bufferEnd - bufferPtr) + keep;
+        bufferPtr = buffer + keep;
+      }
+      else {
+        bufferEnd = newBuf + (bufferEnd - bufferPtr);
+        bufferPtr = buffer = newBuf;
+      }
+#else
+      if (bufferPtr) {
+        memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr);
+        FREE(buffer);
+      }
+      bufferEnd = newBuf + (bufferEnd - bufferPtr);
+      bufferPtr = buffer = newBuf;
+#endif  /* not defined XML_CONTEXT_BYTES */
+    }
+    eventPtr = eventEndPtr = NULL;
+    positionPtr = NULL;
+  }
+  return bufferEnd;
+}
+
+enum XML_Status XMLCALL
+XML_StopParser(XML_Parser parser, XML_Bool resumable)
+{
+  switch (ps_parsing) {
+  case XML_SUSPENDED:
+    if (resumable) {
+      errorCode = XML_ERROR_SUSPENDED;
+      return XML_STATUS_ERROR;
+    }
+    ps_parsing = XML_FINISHED;
+    break;
+  case XML_FINISHED:
+    errorCode = XML_ERROR_FINISHED;
+    return XML_STATUS_ERROR;
+  default:
+    if (resumable) {
+#ifdef XML_DTD
+      if (isParamEntity) {
+        errorCode = XML_ERROR_SUSPEND_PE;
+        return XML_STATUS_ERROR;
+      }
+#endif
+      ps_parsing = XML_SUSPENDED;
+    }
+    else
+      ps_parsing = XML_FINISHED;
+  }
+  return XML_STATUS_OK;
+}
+
+enum XML_Status XMLCALL
+XML_ResumeParser(XML_Parser parser)
+{
+  enum XML_Status result = XML_STATUS_OK;
+
+  if (ps_parsing != XML_SUSPENDED) {
+    errorCode = XML_ERROR_NOT_SUSPENDED;
+    return XML_STATUS_ERROR;
+  }
+  ps_parsing = XML_PARSING;
+
+  errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+
+  if (errorCode != XML_ERROR_NONE) {
+    eventEndPtr = eventPtr;
+    processor = errorProcessor;
+    return XML_STATUS_ERROR;
+  }
+  else {
+    switch (ps_parsing) {
+    case XML_SUSPENDED:
+      result = XML_STATUS_SUSPENDED;
+      break;
+    case XML_INITIALIZED:
+    case XML_PARSING:
+      if (ps_finalBuffer) {
+        ps_parsing = XML_FINISHED;
+        return result;
+      }
+    default: ;
+    }
+  }
+
+  XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+  positionPtr = bufferPtr;
+  return result;
+}
+
+void XMLCALL
+XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status)
+{
+  assert(status != NULL);
+  *status = parser->m_parsingStatus;
+}
+
+enum XML_Error XMLCALL
+XML_GetErrorCode(XML_Parser parser)
+{
+  return errorCode;
+}
+
+XML_Index XMLCALL
+XML_GetCurrentByteIndex(XML_Parser parser)
+{
+  if (eventPtr)
+    return parseEndByteIndex - (parseEndPtr - eventPtr);
+  return -1;
+}
+
+int XMLCALL
+XML_GetCurrentByteCount(XML_Parser parser)
+{
+  if (eventEndPtr && eventPtr)
+    return (int)(eventEndPtr - eventPtr);
+  return 0;
+}
+
+const char * XMLCALL
+XML_GetInputContext(XML_Parser parser, int *offset, int *size)
+{
+#ifdef XML_CONTEXT_BYTES
+  if (eventPtr && buffer) {
+    *offset = (int)(eventPtr - buffer);
+    *size   = (int)(bufferEnd - buffer);
+    return buffer;
+  }
+#endif /* defined XML_CONTEXT_BYTES */
+  return (char *) 0;
+}
+
+XML_Size XMLCALL
+XML_GetCurrentLineNumber(XML_Parser parser)
+{
+  if (eventPtr && eventPtr >= positionPtr) {
+    XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
+    positionPtr = eventPtr;
+  }
+  return position.lineNumber + 1;
+}
+
+XML_Size XMLCALL
+XML_GetCurrentColumnNumber(XML_Parser parser)
+{
+  if (eventPtr && eventPtr >= positionPtr) {
+    XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
+    positionPtr = eventPtr;
+  }
+  return position.columnNumber;
+}
+
+void XMLCALL
+XML_FreeContentModel(XML_Parser parser, XML_Content *model)
+{
+  FREE(model);
+}
+
+void * XMLCALL
+XML_MemMalloc(XML_Parser parser, size_t size)
+{
+  return MALLOC(size);
+}
+
+void * XMLCALL
+XML_MemRealloc(XML_Parser parser, void *ptr, size_t size)
+{
+  return REALLOC(ptr, size);
+}
+
+void XMLCALL
+XML_MemFree(XML_Parser parser, void *ptr)
+{
+  FREE(ptr);
+}
+
+void XMLCALL
+XML_DefaultCurrent(XML_Parser parser)
+{
+  if (defaultHandler) {
+    if (openInternalEntities)
+      reportDefault(parser,
+                    internalEncoding,
+                    openInternalEntities->internalEventPtr,
+                    openInternalEntities->internalEventEndPtr);
+    else
+      reportDefault(parser, encoding, eventPtr, eventEndPtr);
+  }
+}
+
+const XML_LChar * XMLCALL
+XML_ErrorString(enum XML_Error code)
+{
+  static const XML_LChar* const message[] = {
+    0,
+    XML_L("out of memory"),
+    XML_L("syntax error"),
+    XML_L("no element found"),
+    XML_L("not well-formed (invalid token)"),
+    XML_L("unclosed token"),
+    XML_L("partial character"),
+    XML_L("mismatched tag"),
+    XML_L("duplicate attribute"),
+    XML_L("junk after document element"),
+    XML_L("illegal parameter entity reference"),
+    XML_L("undefined entity"),
+    XML_L("recursive entity reference"),
+    XML_L("asynchronous entity"),
+    XML_L("reference to invalid character number"),
+    XML_L("reference to binary entity"),
+    XML_L("reference to external entity in attribute"),
+    XML_L("XML or text declaration not at start of entity"),
+    XML_L("unknown encoding"),
+    XML_L("encoding specified in XML declaration is incorrect"),
+    XML_L("unclosed CDATA section"),
+    XML_L("error in processing external entity reference"),
+    XML_L("document is not standalone"),
+    XML_L("unexpected parser state - please send a bug report"),
+    XML_L("entity declared in parameter entity"),
+    XML_L("requested feature requires XML_DTD support in Expat"),
+    XML_L("cannot change setting once parsing has begun"),
+    XML_L("unbound prefix"),
+    XML_L("must not undeclare prefix"),
+    XML_L("incomplete markup in parameter entity"),
+    XML_L("XML declaration not well-formed"),
+    XML_L("text declaration not well-formed"),
+    XML_L("illegal character(s) in public id"),
+    XML_L("parser suspended"),
+    XML_L("parser not suspended"),
+    XML_L("parsing aborted"),
+    XML_L("parsing finished"),
+    XML_L("cannot suspend in external parameter entity"),
+    XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name"),
+    XML_L("reserved prefix (xmlns) must not be declared or undeclared"),
+    XML_L("prefix must not be bound to one of the reserved namespace names")
+  };
+  if (code > 0 && code < sizeof(message)/sizeof(message[0]))
+    return message[code];
+  return NULL;
+}
+
+const XML_LChar * XMLCALL
+XML_ExpatVersion(void) {
+
+  /* V1 is used to string-ize the version number. However, it would
+     string-ize the actual version macro *names* unless we get them
+     substituted before being passed to V1. CPP is defined to expand
+     a macro, then rescan for more expansions. Thus, we use V2 to expand
+     the version macros, then CPP will expand the resulting V1() macro
+     with the correct numerals. */
+  /* ### I'm assuming cpp is portable in this respect... */
+
+#define V1(a,b,c) XML_L(#a)XML_L(".")XML_L(#b)XML_L(".")XML_L(#c)
+#define V2(a,b,c) XML_L("expat_")V1(a,b,c)
+
+  return V2(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION);
+
+#undef V1
+#undef V2
+}
+
+XML_Expat_Version XMLCALL
+XML_ExpatVersionInfo(void)
+{
+  XML_Expat_Version version;
+
+  version.major = XML_MAJOR_VERSION;
+  version.minor = XML_MINOR_VERSION;
+  version.micro = XML_MICRO_VERSION;
+
+  return version;
+}
+
+const XML_Feature * XMLCALL
+XML_GetFeatureList(void)
+{
+  static const XML_Feature features[] = {
+    {XML_FEATURE_SIZEOF_XML_CHAR,  XML_L("sizeof(XML_Char)"),
+     sizeof(XML_Char)},
+    {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
+     sizeof(XML_LChar)},
+#ifdef XML_UNICODE
+    {XML_FEATURE_UNICODE,          XML_L("XML_UNICODE"), 0},
+#endif
+#ifdef XML_UNICODE_WCHAR_T
+    {XML_FEATURE_UNICODE_WCHAR_T,  XML_L("XML_UNICODE_WCHAR_T"), 0},
+#endif
+#ifdef XML_DTD
+    {XML_FEATURE_DTD,              XML_L("XML_DTD"), 0},
+#endif
+#ifdef XML_CONTEXT_BYTES
+    {XML_FEATURE_CONTEXT_BYTES,    XML_L("XML_CONTEXT_BYTES"),
+     XML_CONTEXT_BYTES},
+#endif
+#ifdef XML_MIN_SIZE
+    {XML_FEATURE_MIN_SIZE,         XML_L("XML_MIN_SIZE"), 0},
+#endif
+#ifdef XML_NS
+    {XML_FEATURE_NS,               XML_L("XML_NS"), 0},
+#endif
+#ifdef XML_LARGE_SIZE
+    {XML_FEATURE_LARGE_SIZE,       XML_L("XML_LARGE_SIZE"), 0},
+#endif
+#ifdef XML_ATTR_INFO
+    {XML_FEATURE_ATTR_INFO,        XML_L("XML_ATTR_INFO"), 0},
+#endif
+    {XML_FEATURE_END,              NULL, 0}
+  };
+
+  return features;
+}
+
+/* Initially tag->rawName always points into the parse buffer;
+   for those TAG instances opened while the current parse buffer was
+   processed, and not yet closed, we need to store tag->rawName in a more
+   permanent location, since the parse buffer is about to be discarded.
+*/
+static XML_Bool
+storeRawNames(XML_Parser parser)
+{
+  TAG *tag = tagStack;
+  while (tag) {
+    int bufSize;
+    int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
+    char *rawNameBuf = tag->buf + nameLen;
+    /* Stop if already stored.  Since tagStack is a stack, we can stop
+       at the first entry that has already been copied; everything
+       below it in the stack is already been accounted for in a
+       previous call to this function.
+    */
+    if (tag->rawName == rawNameBuf)
+      break;
+    /* For re-use purposes we need to ensure that the
+       size of tag->buf is a multiple of sizeof(XML_Char).
+    */
+    bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
+    if (bufSize > tag->bufEnd - tag->buf) {
+      char *temp = (char *)REALLOC(tag->buf, bufSize);
+      if (temp == NULL)
+        return XML_FALSE;
+      /* if tag->name.str points to tag->buf (only when namespace
+         processing is off) then we have to update it
+      */
+      if (tag->name.str == (XML_Char *)tag->buf)
+        tag->name.str = (XML_Char *)temp;
+      /* if tag->name.localPart is set (when namespace processing is on)
+         then update it as well, since it will always point into tag->buf
+      */
+      if (tag->name.localPart)
+        tag->name.localPart = (XML_Char *)temp + (tag->name.localPart -
+                                                  (XML_Char *)tag->buf);
+      tag->buf = temp;
+      tag->bufEnd = temp + bufSize;
+      rawNameBuf = temp + nameLen;
+    }
+    memcpy(rawNameBuf, tag->rawName, tag->rawNameLength);
+    tag->rawName = rawNameBuf;
+    tag = tag->parent;
+  }
+  return XML_TRUE;
+}
+
+static enum XML_Error PTRCALL
+contentProcessor(XML_Parser parser,
+                 const char *start,
+                 const char *end,
+                 const char **endPtr)
+{
+  enum XML_Error result = doContent(parser, 0, encoding, start, end,
+                                    endPtr, (XML_Bool)!ps_finalBuffer);
+  if (result == XML_ERROR_NONE) {
+    if (!storeRawNames(parser))
+      return XML_ERROR_NO_MEMORY;
+  }
+  return result;
+}
+
+static enum XML_Error PTRCALL
+externalEntityInitProcessor(XML_Parser parser,
+                            const char *start,
+                            const char *end,
+                            const char **endPtr)
+{
+  enum XML_Error result = initializeEncoding(parser);
+  if (result != XML_ERROR_NONE)
+    return result;
+  processor = externalEntityInitProcessor2;
+  return externalEntityInitProcessor2(parser, start, end, endPtr);
+}
+
+static enum XML_Error PTRCALL
+externalEntityInitProcessor2(XML_Parser parser,
+                             const char *start,
+                             const char *end,
+                             const char **endPtr)
+{
+  const char *next = start; /* XmlContentTok doesn't always set the last arg */
+  int tok = XmlContentTok(encoding, start, end, &next);
+  switch (tok) {
+  case XML_TOK_BOM:
+    /* If we are at the end of the buffer, this would cause the next stage,
+       i.e. externalEntityInitProcessor3, to pass control directly to
+       doContent (by detecting XML_TOK_NONE) without processing any xml text
+       declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent.
+    */
+    if (next == end && !ps_finalBuffer) {
+      *endPtr = next;
+      return XML_ERROR_NONE;
+    }
+    start = next;
+    break;
+  case XML_TOK_PARTIAL:
+    if (!ps_finalBuffer) {
+      *endPtr = start;
+      return XML_ERROR_NONE;
+    }
+    eventPtr = start;
+    return XML_ERROR_UNCLOSED_TOKEN;
+  case XML_TOK_PARTIAL_CHAR:
+    if (!ps_finalBuffer) {
+      *endPtr = start;
+      return XML_ERROR_NONE;
+    }
+    eventPtr = start;
+    return XML_ERROR_PARTIAL_CHAR;
+  }
+  processor = externalEntityInitProcessor3;
+  return externalEntityInitProcessor3(parser, start, end, endPtr);
+}
+
+static enum XML_Error PTRCALL
+externalEntityInitProcessor3(XML_Parser parser,
+                             const char *start,
+                             const char *end,
+                             const char **endPtr)
+{
+  int tok;
+  const char *next = start; /* XmlContentTok doesn't always set the last arg */
+  eventPtr = start;
+  tok = XmlContentTok(encoding, start, end, &next);
+  eventEndPtr = next;
+
+  switch (tok) {
+  case XML_TOK_XML_DECL:
+    {
+      enum XML_Error result;
+      result = processXmlDecl(parser, 1, start, next);
+      if (result != XML_ERROR_NONE)
+        return result;
+      switch (ps_parsing) {
+      case XML_SUSPENDED:
+        *endPtr = next;
+        return XML_ERROR_NONE;
+      case XML_FINISHED:
+        return XML_ERROR_ABORTED;
+      default:
+        start = next;
+      }
+    }
+    break;
+  case XML_TOK_PARTIAL:
+    if (!ps_finalBuffer) {
+      *endPtr = start;
+      return XML_ERROR_NONE;
+    }
+    return XML_ERROR_UNCLOSED_TOKEN;
+  case XML_TOK_PARTIAL_CHAR:
+    if (!ps_finalBuffer) {
+      *endPtr = start;
+      return XML_ERROR_NONE;
+    }
+    return XML_ERROR_PARTIAL_CHAR;
+  }
+  processor = externalEntityContentProcessor;
+  tagLevel = 1;
+  return externalEntityContentProcessor(parser, start, end, endPtr);
+}
+
+static enum XML_Error PTRCALL
+externalEntityContentProcessor(XML_Parser parser,
+                               const char *start,
+                               const char *end,
+                               const char **endPtr)
+{
+  enum XML_Error result = doContent(parser, 1, encoding, start, end,
+                                    endPtr, (XML_Bool)!ps_finalBuffer);
+  if (result == XML_ERROR_NONE) {
+    if (!storeRawNames(parser))
+      return XML_ERROR_NO_MEMORY;
+  }
+  return result;
+}
+
+static enum XML_Error
+doContent(XML_Parser parser,
+          int startTagLevel,
+          const ENCODING *enc,
+          const char *s,
+          const char *end,
+          const char **nextPtr,
+          XML_Bool haveMore)
+{
+  /* save one level of indirection */
+  DTD * const dtd = _dtd;
+
+  const char **eventPP;
+  const char **eventEndPP;
+  if (enc == encoding) {
+    eventPP = &eventPtr;
+    eventEndPP = &eventEndPtr;
+  }
+  else {
+    eventPP = &(openInternalEntities->internalEventPtr);
+    eventEndPP = &(openInternalEntities->internalEventEndPtr);
+  }
+  *eventPP = s;
+
+  for (;;) {
+    const char *next = s; /* XmlContentTok doesn't always set the last arg */
+    int tok = XmlContentTok(enc, s, end, &next);
+    *eventEndPP = next;
+    switch (tok) {
+    case XML_TOK_TRAILING_CR:
+      if (haveMore) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      *eventEndPP = end;
+      if (characterDataHandler) {
+        XML_Char c = 0xA;
+        characterDataHandler(handlerArg, &c, 1);
+      }
+      else if (defaultHandler)
+        reportDefault(parser, enc, s, end);
+      /* We are at the end of the final buffer, should we check for
+         XML_SUSPENDED, XML_FINISHED?
+      */
+      if (startTagLevel == 0)
+        return XML_ERROR_NO_ELEMENTS;
+      if (tagLevel != startTagLevel)
+        return XML_ERROR_ASYNC_ENTITY;
+      *nextPtr = end;
+      return XML_ERROR_NONE;
+    case XML_TOK_NONE:
+      if (haveMore) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      if (startTagLevel > 0) {
+        if (tagLevel != startTagLevel)
+          return XML_ERROR_ASYNC_ENTITY;
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      return XML_ERROR_NO_ELEMENTS;
+    case XML_TOK_INVALID:
+      *eventPP = next;
+      return XML_ERROR_INVALID_TOKEN;
+    case XML_TOK_PARTIAL:
+      if (haveMore) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      return XML_ERROR_UNCLOSED_TOKEN;
+    case XML_TOK_PARTIAL_CHAR:
+      if (haveMore) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      return XML_ERROR_PARTIAL_CHAR;
+    case XML_TOK_ENTITY_REF:
+      {
+        const XML_Char *name;
+        ENTITY *entity;
+        XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc,
+                                              s + enc->minBytesPerChar,
+                                              next - enc->minBytesPerChar);
+        if (ch) {
+          if (characterDataHandler)
+            characterDataHandler(handlerArg, &ch, 1);
+          else if (defaultHandler)
+            reportDefault(parser, enc, s, next);
+          break;
+        }
+        name = poolStoreString(&dtd->pool, enc,
+                                s + enc->minBytesPerChar,
+                                next - enc->minBytesPerChar);
+        if (!name)
+          return XML_ERROR_NO_MEMORY;
+        entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
+        poolDiscard(&dtd->pool);
+        /* First, determine if a check for an existing declaration is needed;
+           if yes, check that the entity exists, and that it is internal,
+           otherwise call the skipped entity or default handler.
+        */
+        if (!dtd->hasParamEntityRefs || dtd->standalone) {
+          if (!entity)
+            return XML_ERROR_UNDEFINED_ENTITY;
+          else if (!entity->is_internal)
+            return XML_ERROR_ENTITY_DECLARED_IN_PE;
+        }
+        else if (!entity) {
+          if (skippedEntityHandler)
+            skippedEntityHandler(handlerArg, name, 0);
+          else if (defaultHandler)
+            reportDefault(parser, enc, s, next);
+          break;
+        }
+        if (entity->open)
+          return XML_ERROR_RECURSIVE_ENTITY_REF;
+        if (entity->notation)
+          return XML_ERROR_BINARY_ENTITY_REF;
+        if (entity->textPtr) {
+          enum XML_Error result;
+          if (!defaultExpandInternalEntities) {
+            if (skippedEntityHandler)
+              skippedEntityHandler(handlerArg, entity->name, 0);
+            else if (defaultHandler)
+              reportDefault(parser, enc, s, next);
+            break;
+          }
+          result = processInternalEntity(parser, entity, XML_FALSE);
+          if (result != XML_ERROR_NONE)
+            return result;
+        }
+        else if (externalEntityRefHandler) {
+          const XML_Char *context;
+          entity->open = XML_TRUE;
+          context = getContext(parser);
+          entity->open = XML_FALSE;
+          if (!context)
+            return XML_ERROR_NO_MEMORY;
+          if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+                                        context,
+                                        entity->base,
+                                        entity->systemId,
+                                        entity->publicId))
+            return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+          poolDiscard(&tempPool);
+        }
+        else if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+        break;
+      }
+    case XML_TOK_START_TAG_NO_ATTS:
+      /* fall through */
+    case XML_TOK_START_TAG_WITH_ATTS:
+      {
+        TAG *tag;
+        enum XML_Error result;
+        XML_Char *toPtr;
+        if (freeTagList) {
+          tag = freeTagList;
+          freeTagList = freeTagList->parent;
+        }
+        else {
+          tag = (TAG *)MALLOC(sizeof(TAG));
+          if (!tag)
+            return XML_ERROR_NO_MEMORY;
+          tag->buf = (char *)MALLOC(INIT_TAG_BUF_SIZE);
+          if (!tag->buf) {
+            FREE(tag);
+            return XML_ERROR_NO_MEMORY;
+          }
+          tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
+        }
+        tag->bindings = NULL;
+        tag->parent = tagStack;
+        tagStack = tag;
+        tag->name.localPart = NULL;
+        tag->name.prefix = NULL;
+        tag->rawName = s + enc->minBytesPerChar;
+        tag->rawNameLength = XmlNameLength(enc, tag->rawName);
+        ++tagLevel;
+        {
+          const char *rawNameEnd = tag->rawName + tag->rawNameLength;
+          const char *fromPtr = tag->rawName;
+          toPtr = (XML_Char *)tag->buf;
+          for (;;) {
+            int bufSize;
+            int convLen;
+            XmlConvert(enc,
+                       &fromPtr, rawNameEnd,
+                       (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1);
+            convLen = (int)(toPtr - (XML_Char *)tag->buf);
+            if (fromPtr == rawNameEnd) {
+              tag->name.strLen = convLen;
+              break;
+            }
+            bufSize = (int)(tag->bufEnd - tag->buf) << 1;
+            {
+              char *temp = (char *)REALLOC(tag->buf, bufSize);
+              if (temp == NULL)
+                return XML_ERROR_NO_MEMORY;
+              tag->buf = temp;
+              tag->bufEnd = temp + bufSize;
+              toPtr = (XML_Char *)temp + convLen;
+            }
+          }
+        }
+        tag->name.str = (XML_Char *)tag->buf;
+        *toPtr = XML_T('\0');
+        result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
+        if (result)
+          return result;
+        if (startElementHandler)
+          startElementHandler(handlerArg, tag->name.str,
+                              (const XML_Char **)atts);
+        else if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+        poolClear(&tempPool);
+        break;
+      }
+    case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
+      /* fall through */
+    case XML_TOK_EMPTY_ELEMENT_WITH_ATTS:
+      {
+        const char *rawName = s + enc->minBytesPerChar;
+        enum XML_Error result;
+        BINDING *bindings = NULL;
+        XML_Bool noElmHandlers = XML_TRUE;
+        TAG_NAME name;
+        name.str = poolStoreString(&tempPool, enc, rawName,
+                                   rawName + XmlNameLength(enc, rawName));
+        if (!name.str)
+          return XML_ERROR_NO_MEMORY;
+        poolFinish(&tempPool);
+        result = storeAtts(parser, enc, s, &name, &bindings);
+        if (result)
+          return result;
+        poolFinish(&tempPool);
+        if (startElementHandler) {
+          startElementHandler(handlerArg, name.str, (const XML_Char **)atts);
+          noElmHandlers = XML_FALSE;
+        }
+        if (endElementHandler) {
+          if (startElementHandler)
+            *eventPP = *eventEndPP;
+          endElementHandler(handlerArg, name.str);
+          noElmHandlers = XML_FALSE;
+        }
+        if (noElmHandlers && defaultHandler)
+          reportDefault(parser, enc, s, next);
+        poolClear(&tempPool);
+        while (bindings) {
+          BINDING *b = bindings;
+          if (endNamespaceDeclHandler)
+            endNamespaceDeclHandler(handlerArg, b->prefix->name);
+          bindings = bindings->nextTagBinding;
+          b->nextTagBinding = freeBindingList;
+          freeBindingList = b;
+          b->prefix->binding = b->prevPrefixBinding;
+        }
+      }
+      if (tagLevel == 0)
+        return epilogProcessor(parser, next, end, nextPtr);
+      break;
+    case XML_TOK_END_TAG:
+      if (tagLevel == startTagLevel)
+        return XML_ERROR_ASYNC_ENTITY;
+      else {
+        int len;
+        const char *rawName;
+        TAG *tag = tagStack;
+        tagStack = tag->parent;
+        tag->parent = freeTagList;
+        freeTagList = tag;
+        rawName = s + enc->minBytesPerChar*2;
+        len = XmlNameLength(enc, rawName);
+        if (len != tag->rawNameLength
+            || memcmp(tag->rawName, rawName, len) != 0) {
+          *eventPP = rawName;
+          return XML_ERROR_TAG_MISMATCH;
+        }
+        --tagLevel;
+        if (endElementHandler) {
+          const XML_Char *localPart;
+          const XML_Char *prefix;
+          XML_Char *uri;
+          localPart = tag->name.localPart;
+          if (ns && localPart) {
+            /* localPart and prefix may have been overwritten in
+               tag->name.str, since this points to the binding->uri
+               buffer which gets re-used; so we have to add them again
+            */
+            uri = (XML_Char *)tag->name.str + tag->name.uriLen;
+            /* don't need to check for space - already done in storeAtts() */
+            while (*localPart) *uri++ = *localPart++;
+            prefix = (XML_Char *)tag->name.prefix;
+            if (ns_triplets && prefix) {
+              *uri++ = namespaceSeparator;
+              while (*prefix) *uri++ = *prefix++;
+             }
+            *uri = XML_T('\0');
+          }
+          endElementHandler(handlerArg, tag->name.str);
+        }
+        else if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+        while (tag->bindings) {
+          BINDING *b = tag->bindings;
+          if (endNamespaceDeclHandler)
+            endNamespaceDeclHandler(handlerArg, b->prefix->name);
+          tag->bindings = tag->bindings->nextTagBinding;
+          b->nextTagBinding = freeBindingList;
+          freeBindingList = b;
+          b->prefix->binding = b->prevPrefixBinding;
+        }
+        if (tagLevel == 0)
+          return epilogProcessor(parser, next, end, nextPtr);
+      }
+      break;
+    case XML_TOK_CHAR_REF:
+      {
+        int n = XmlCharRefNumber(enc, s);
+        if (n < 0)
+          return XML_ERROR_BAD_CHAR_REF;
+        if (characterDataHandler) {
+          XML_Char buf[XML_ENCODE_MAX];
+          characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf));
+        }
+        else if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+      }
+      break;
+    case XML_TOK_XML_DECL:
+      return XML_ERROR_MISPLACED_XML_PI;
+    case XML_TOK_DATA_NEWLINE:
+      if (characterDataHandler) {
+        XML_Char c = 0xA;
+        characterDataHandler(handlerArg, &c, 1);
+      }
+      else if (defaultHandler)
+        reportDefault(parser, enc, s, next);
+      break;
+    case XML_TOK_CDATA_SECT_OPEN:
+      {
+        enum XML_Error result;
+        if (startCdataSectionHandler)
+          startCdataSectionHandler(handlerArg);
+#if 0
+        /* Suppose you doing a transformation on a document that involves
+           changing only the character data.  You set up a defaultHandler
+           and a characterDataHandler.  The defaultHandler simply copies
+           characters through.  The characterDataHandler does the
+           transformation and writes the characters out escaping them as
+           necessary.  This case will fail to work if we leave out the
+           following two lines (because & and < inside CDATA sections will
+           be incorrectly escaped).
+
+           However, now we have a start/endCdataSectionHandler, so it seems
+           easier to let the user deal with this.
+        */
+        else if (characterDataHandler)
+          characterDataHandler(handlerArg, dataBuf, 0);
+#endif
+        else if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+        result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
+        if (result != XML_ERROR_NONE)
+          return result;
+        else if (!next) {
+          processor = cdataSectionProcessor;
+          return result;
+        }
+      }
+      break;
+    case XML_TOK_TRAILING_RSQB:
+      if (haveMore) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      if (characterDataHandler) {
+        if (MUST_CONVERT(enc, s)) {
+          ICHAR *dataPtr = (ICHAR *)dataBuf;
+          XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+          characterDataHandler(handlerArg, dataBuf,
+                               (int)(dataPtr - (ICHAR *)dataBuf));
+        }
+        else
+          characterDataHandler(handlerArg,
+                               (XML_Char *)s,
+                               (int)((XML_Char *)end - (XML_Char *)s));
+      }
+      else if (defaultHandler)
+        reportDefault(parser, enc, s, end);
+      /* We are at the end of the final buffer, should we check for
+         XML_SUSPENDED, XML_FINISHED?
+      */
+      if (startTagLevel == 0) {
+        *eventPP = end;
+        return XML_ERROR_NO_ELEMENTS;
+      }
+      if (tagLevel != startTagLevel) {
+        *eventPP = end;
+        return XML_ERROR_ASYNC_ENTITY;
+      }
+      *nextPtr = end;
+      return XML_ERROR_NONE;
+    case XML_TOK_DATA_CHARS:
+      {
+        XML_CharacterDataHandler charDataHandler = characterDataHandler;
+        if (charDataHandler) {
+          if (MUST_CONVERT(enc, s)) {
+            for (;;) {
+              ICHAR *dataPtr = (ICHAR *)dataBuf;
+              XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+              *eventEndPP = s;
+              charDataHandler(handlerArg, dataBuf,
+                              (int)(dataPtr - (ICHAR *)dataBuf));
+              if (s == next)
+                break;
+              *eventPP = s;
+            }
+          }
+          else
+            charDataHandler(handlerArg,
+                            (XML_Char *)s,
+                            (int)((XML_Char *)next - (XML_Char *)s));
+        }
+        else if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+      }
+      break;
+    case XML_TOK_PI:
+      if (!reportProcessingInstruction(parser, enc, s, next))
+        return XML_ERROR_NO_MEMORY;
+      break;
+    case XML_TOK_COMMENT:
+      if (!reportComment(parser, enc, s, next))
+        return XML_ERROR_NO_MEMORY;
+      break;
+    default:
+      if (defaultHandler)
+        reportDefault(parser, enc, s, next);
+      break;
+    }
+    *eventPP = s = next;
+    switch (ps_parsing) {
+    case XML_SUSPENDED:
+      *nextPtr = next;
+      return XML_ERROR_NONE;
+    case XML_FINISHED:
+      return XML_ERROR_ABORTED;
+    default: ;
+    }
+  }
+  /* not reached */
+}
+
+/* Precondition: all arguments must be non-NULL;
+   Purpose:
+   - normalize attributes
+   - check attributes for well-formedness
+   - generate namespace aware attribute names (URI, prefix)
+   - build list of attributes for startElementHandler
+   - default attributes
+   - process namespace declarations (check and report them)
+   - generate namespace aware element name (URI, prefix)
+*/
+static enum XML_Error
+storeAtts(XML_Parser parser, const ENCODING *enc,
+          const char *attStr, TAG_NAME *tagNamePtr,
+          BINDING **bindingsPtr)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  ELEMENT_TYPE *elementType;
+  int nDefaultAtts;
+  const XML_Char **appAtts;   /* the attribute list for the application */
+  int attIndex = 0;
+  int prefixLen;
+  int i;
+  int n;
+  XML_Char *uri;
+  int nPrefixes = 0;
+  BINDING *binding;
+  const XML_Char *localPart;
+
+  /* lookup the element type name */
+  elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0);
+  if (!elementType) {
+    const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str);
+    if (!name)
+      return XML_ERROR_NO_MEMORY;
+    elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name,
+                                         sizeof(ELEMENT_TYPE));
+    if (!elementType)
+      return XML_ERROR_NO_MEMORY;
+    if (ns && !setElementTypePrefix(parser, elementType))
+      return XML_ERROR_NO_MEMORY;
+  }
+  nDefaultAtts = elementType->nDefaultAtts;
+
+  /* get the attributes from the tokenizer */
+  n = XmlGetAttributes(enc, attStr, attsSize, atts);
+  if (n + nDefaultAtts > attsSize) {
+    int oldAttsSize = attsSize;
+    ATTRIBUTE *temp;
+#ifdef XML_ATTR_INFO
+    XML_AttrInfo *temp2;
+#endif
+    attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
+    temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE));
+    if (temp == NULL)
+      return XML_ERROR_NO_MEMORY;
+    atts = temp;
+#ifdef XML_ATTR_INFO
+    temp2 = (XML_AttrInfo *)REALLOC((void *)attInfo, attsSize * sizeof(XML_AttrInfo));
+    if (temp2 == NULL)
+      return XML_ERROR_NO_MEMORY;
+    attInfo = temp2;
+#endif
+    if (n > oldAttsSize)
+      XmlGetAttributes(enc, attStr, n, atts);
+  }
+
+  appAtts = (const XML_Char **)atts;
+  for (i = 0; i < n; i++) {
+    ATTRIBUTE *currAtt = &atts[i];
+#ifdef XML_ATTR_INFO
+    XML_AttrInfo *currAttInfo = &attInfo[i];
+#endif
+    /* add the name and value to the attribute list */
+    ATTRIBUTE_ID *attId = getAttributeId(parser, enc, currAtt->name,
+                                         currAtt->name
+                                         + XmlNameLength(enc, currAtt->name));
+    if (!attId)
+      return XML_ERROR_NO_MEMORY;
+#ifdef XML_ATTR_INFO
+    currAttInfo->nameStart = parseEndByteIndex - (parseEndPtr - currAtt->name);
+    currAttInfo->nameEnd = currAttInfo->nameStart +
+                           XmlNameLength(enc, currAtt->name);
+    currAttInfo->valueStart = parseEndByteIndex -
+                            (parseEndPtr - currAtt->valuePtr);
+    currAttInfo->valueEnd = parseEndByteIndex - (parseEndPtr - currAtt->valueEnd);
+#endif
+    /* Detect duplicate attributes by their QNames. This does not work when
+       namespace processing is turned on and different prefixes for the same
+       namespace are used. For this case we have a check further down.
+    */
+    if ((attId->name)[-1]) {
+      if (enc == encoding)
+        eventPtr = atts[i].name;
+      return XML_ERROR_DUPLICATE_ATTRIBUTE;
+    }
+    (attId->name)[-1] = 1;
+    appAtts[attIndex++] = attId->name;
+    if (!atts[i].normalized) {
+      enum XML_Error result;
+      XML_Bool isCdata = XML_TRUE;
+
+      /* figure out whether declared as other than CDATA */
+      if (attId->maybeTokenized) {
+        int j;
+        for (j = 0; j < nDefaultAtts; j++) {
+          if (attId == elementType->defaultAtts[j].id) {
+            isCdata = elementType->defaultAtts[j].isCdata;
+            break;
+          }
+        }
+      }
+
+      /* normalize the attribute value */
+      result = storeAttributeValue(parser, enc, isCdata,
+                                   atts[i].valuePtr, atts[i].valueEnd,
+                                   &tempPool);
+      if (result)
+        return result;
+      appAtts[attIndex] = poolStart(&tempPool);
+      poolFinish(&tempPool);
+    }
+    else {
+      /* the value did not need normalizing */
+      appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr,
+                                          atts[i].valueEnd);
+      if (appAtts[attIndex] == 0)
+        return XML_ERROR_NO_MEMORY;
+      poolFinish(&tempPool);
+    }
+    /* handle prefixed attribute names */
+    if (attId->prefix) {
+      if (attId->xmlns) {
+        /* deal with namespace declarations here */
+        enum XML_Error result = addBinding(parser, attId->prefix, attId,
+                                           appAtts[attIndex], bindingsPtr);
+        if (result)
+          return result;
+        --attIndex;
+      }
+      else {
+        /* deal with other prefixed names later */
+        attIndex++;
+        nPrefixes++;
+        (attId->name)[-1] = 2;
+      }
+    }
+    else
+      attIndex++;
+  }
+
+  /* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */
+  nSpecifiedAtts = attIndex;
+  if (elementType->idAtt && (elementType->idAtt->name)[-1]) {
+    for (i = 0; i < attIndex; i += 2)
+      if (appAtts[i] == elementType->idAtt->name) {
+        idAttIndex = i;
+        break;
+      }
+  }
+  else
+    idAttIndex = -1;
+
+  /* do attribute defaulting */
+  for (i = 0; i < nDefaultAtts; i++) {
+    const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i;
+    if (!(da->id->name)[-1] && da->value) {
+      if (da->id->prefix) {
+        if (da->id->xmlns) {
+          enum XML_Error result = addBinding(parser, da->id->prefix, da->id,
+                                             da->value, bindingsPtr);
+          if (result)
+            return result;
+        }
+        else {
+          (da->id->name)[-1] = 2;
+          nPrefixes++;
+          appAtts[attIndex++] = da->id->name;
+          appAtts[attIndex++] = da->value;
+        }
+      }
+      else {
+        (da->id->name)[-1] = 1;
+        appAtts[attIndex++] = da->id->name;
+        appAtts[attIndex++] = da->value;
+      }
+    }
+  }
+  appAtts[attIndex] = 0;
+
+  /* expand prefixed attribute names, check for duplicates,
+     and clear flags that say whether attributes were specified */
+  i = 0;
+  if (nPrefixes) {
+    int j;  /* hash table index */
+    unsigned long version = nsAttsVersion;
+    int nsAttsSize = (int)1 << nsAttsPower;
+    /* size of hash table must be at least 2 * (# of prefixed attributes) */
+    if ((nPrefixes << 1) >> nsAttsPower) {  /* true for nsAttsPower = 0 */
+      NS_ATT *temp;
+      /* hash table size must also be a power of 2 and >= 8 */
+      while (nPrefixes >> nsAttsPower++);
+      if (nsAttsPower < 3)
+        nsAttsPower = 3;
+      nsAttsSize = (int)1 << nsAttsPower;
+      temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT));
+      if (!temp)
+        return XML_ERROR_NO_MEMORY;
+      nsAtts = temp;
+      version = 0;  /* force re-initialization of nsAtts hash table */
+    }
+    /* using a version flag saves us from initializing nsAtts every time */
+    if (!version) {  /* initialize version flags when version wraps around */
+      version = INIT_ATTS_VERSION;
+      for (j = nsAttsSize; j != 0; )
+        nsAtts[--j].version = version;
+    }
+    nsAttsVersion = --version;
+
+    /* expand prefixed names and check for duplicates */
+    for (; i < attIndex; i += 2) {
+      const XML_Char *s = appAtts[i];
+      if (s[-1] == 2) {  /* prefixed */
+        ATTRIBUTE_ID *id;
+        const BINDING *b;
+        unsigned long uriHash = hash_secret_salt;
+        ((XML_Char *)s)[-1] = 0;  /* clear flag */
+        id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0);
+        b = id->prefix->binding;
+        if (!b)
+          return XML_ERROR_UNBOUND_PREFIX;
+
+        /* as we expand the name we also calculate its hash value */
+        for (j = 0; j < b->uriLen; j++) {
+          const XML_Char c = b->uri[j];
+          if (!poolAppendChar(&tempPool, c))
+            return XML_ERROR_NO_MEMORY;
+          uriHash = CHAR_HASH(uriHash, c);
+        }
+        while (*s++ != XML_T(ASCII_COLON))
+          ;
+        do {  /* copies null terminator */
+          const XML_Char c = *s;
+          if (!poolAppendChar(&tempPool, *s))
+            return XML_ERROR_NO_MEMORY;
+          uriHash = CHAR_HASH(uriHash, c);
+        } while (*s++);
+
+        { /* Check hash table for duplicate of expanded name (uriName).
+             Derived from code in lookup(parser, HASH_TABLE *table, ...).
+          */
+          unsigned char step = 0;
+          unsigned long mask = nsAttsSize - 1;
+          j = uriHash & mask;  /* index into hash table */
+          while (nsAtts[j].version == version) {
+            /* for speed we compare stored hash values first */
+            if (uriHash == nsAtts[j].hash) {
+              const XML_Char *s1 = poolStart(&tempPool);
+              const XML_Char *s2 = nsAtts[j].uriName;
+              /* s1 is null terminated, but not s2 */
+              for (; *s1 == *s2 && *s1 != 0; s1++, s2++);
+              if (*s1 == 0)
+                return XML_ERROR_DUPLICATE_ATTRIBUTE;
+            }
+            if (!step)
+              step = PROBE_STEP(uriHash, mask, nsAttsPower);
+            j < step ? (j += nsAttsSize - step) : (j -= step);
+          }
+        }
+
+        if (ns_triplets) {  /* append namespace separator and prefix */
+          tempPool.ptr[-1] = namespaceSeparator;
+          s = b->prefix->name;
+          do {
+            if (!poolAppendChar(&tempPool, *s))
+              return XML_ERROR_NO_MEMORY;
+          } while (*s++);
+        }
+
+        /* store expanded name in attribute list */
+        s = poolStart(&tempPool);
+        poolFinish(&tempPool);
+        appAtts[i] = s;
+
+        /* fill empty slot with new version, uriName and hash value */
+        nsAtts[j].version = version;
+        nsAtts[j].hash = uriHash;
+        nsAtts[j].uriName = s;
+
+        if (!--nPrefixes) {
+          i += 2;
+          break;
+        }
+      }
+      else  /* not prefixed */
+        ((XML_Char *)s)[-1] = 0;  /* clear flag */
+    }
+  }
+  /* clear flags for the remaining attributes */
+  for (; i < attIndex; i += 2)
+    ((XML_Char *)(appAtts[i]))[-1] = 0;
+  for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
+    binding->attId->name[-1] = 0;
+
+  if (!ns)
+    return XML_ERROR_NONE;
+
+  /* expand the element type name */
+  if (elementType->prefix) {
+    binding = elementType->prefix->binding;
+    if (!binding)
+      return XML_ERROR_UNBOUND_PREFIX;
+    localPart = tagNamePtr->str;
+    while (*localPart++ != XML_T(ASCII_COLON))
+      ;
+  }
+  else if (dtd->defaultPrefix.binding) {
+    binding = dtd->defaultPrefix.binding;
+    localPart = tagNamePtr->str;
+  }
+  else
+    return XML_ERROR_NONE;
+  prefixLen = 0;
+  if (ns_triplets && binding->prefix->name) {
+    for (; binding->prefix->name[prefixLen++];)
+      ;  /* prefixLen includes null terminator */
+  }
+  tagNamePtr->localPart = localPart;
+  tagNamePtr->uriLen = binding->uriLen;
+  tagNamePtr->prefix = binding->prefix->name;
+  tagNamePtr->prefixLen = prefixLen;
+  for (i = 0; localPart[i++];)
+    ;  /* i includes null terminator */
+  n = i + binding->uriLen + prefixLen;
+  if (n > binding->uriAlloc) {
+    TAG *p;
+    uri = (XML_Char *)MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char));
+    if (!uri)
+      return XML_ERROR_NO_MEMORY;
+    binding->uriAlloc = n + EXPAND_SPARE;
+    memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char));
+    for (p = tagStack; p; p = p->parent)
+      if (p->name.str == binding->uri)
+        p->name.str = uri;
+    FREE(binding->uri);
+    binding->uri = uri;
+  }
+  /* if namespaceSeparator != '\0' then uri includes it already */
+  uri = binding->uri + binding->uriLen;
+  memcpy(uri, localPart, i * sizeof(XML_Char));
+  /* we always have a namespace separator between localPart and prefix */
+  if (prefixLen) {
+    uri += i - 1;
+    *uri = namespaceSeparator;  /* replace null terminator */
+    memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char));
+  }
+  tagNamePtr->str = binding->uri;
+  return XML_ERROR_NONE;
+}
+
+/* addBinding() overwrites the value of prefix->binding without checking.
+   Therefore one must keep track of the old value outside of addBinding().
+*/
+static enum XML_Error
+addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
+           const XML_Char *uri, BINDING **bindingsPtr)
+{
+  static const XML_Char xmlNamespace[] = {
+    ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH,
+    ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD,
+    ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L,
+    ASCII_SLASH, ASCII_1, ASCII_9, ASCII_9, ASCII_8, ASCII_SLASH,
+    ASCII_n, ASCII_a, ASCII_m, ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c,
+    ASCII_e, '\0'
+  };
+  static const int xmlLen =
+    (int)sizeof(xmlNamespace)/sizeof(XML_Char) - 1;
+  static const XML_Char xmlnsNamespace[] = {
+    ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH,
+    ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD,
+    ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_2, ASCII_0, ASCII_0,
+    ASCII_0, ASCII_SLASH, ASCII_x, ASCII_m, ASCII_l, ASCII_n, ASCII_s,
+    ASCII_SLASH, '\0'
+  };
+  static const int xmlnsLen =
+    (int)sizeof(xmlnsNamespace)/sizeof(XML_Char) - 1;
+
+  XML_Bool mustBeXML = XML_FALSE;
+  XML_Bool isXML = XML_TRUE;
+  XML_Bool isXMLNS = XML_TRUE;
+
+  BINDING *b;
+  int len;
+
+  /* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */
+  if (*uri == XML_T('\0') && prefix->name)
+    return XML_ERROR_UNDECLARING_PREFIX;
+
+  if (prefix->name
+      && prefix->name[0] == XML_T(ASCII_x)
+      && prefix->name[1] == XML_T(ASCII_m)
+      && prefix->name[2] == XML_T(ASCII_l)) {
+
+    /* Not allowed to bind xmlns */
+    if (prefix->name[3] == XML_T(ASCII_n)
+        && prefix->name[4] == XML_T(ASCII_s)
+        && prefix->name[5] == XML_T('\0'))
+      return XML_ERROR_RESERVED_PREFIX_XMLNS;
+
+    if (prefix->name[3] == XML_T('\0'))
+      mustBeXML = XML_TRUE;
+  }
+
+  for (len = 0; uri[len]; len++) {
+    if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len]))
+      isXML = XML_FALSE;
+
+    if (!mustBeXML && isXMLNS
+        && (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
+      isXMLNS = XML_FALSE;
+  }
+  isXML = isXML && len == xmlLen;
+  isXMLNS = isXMLNS && len == xmlnsLen;
+
+  if (mustBeXML != isXML)
+    return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML
+                     : XML_ERROR_RESERVED_NAMESPACE_URI;
+
+  if (isXMLNS)
+    return XML_ERROR_RESERVED_NAMESPACE_URI;
+
+  if (namespaceSeparator)
+    len++;
+  if (freeBindingList) {
+    b = freeBindingList;
+    if (len > b->uriAlloc) {
+      XML_Char *temp = (XML_Char *)REALLOC(b->uri,
+                          sizeof(XML_Char) * (len + EXPAND_SPARE));
+      if (temp == NULL)
+        return XML_ERROR_NO_MEMORY;
+      b->uri = temp;
+      b->uriAlloc = len + EXPAND_SPARE;
+    }
+    freeBindingList = b->nextTagBinding;
+  }
+  else {
+    b = (BINDING *)MALLOC(sizeof(BINDING));
+    if (!b)
+      return XML_ERROR_NO_MEMORY;
+    b->uri = (XML_Char *)MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE));
+    if (!b->uri) {
+      FREE(b);
+      return XML_ERROR_NO_MEMORY;
+    }
+    b->uriAlloc = len + EXPAND_SPARE;
+  }
+  b->uriLen = len;
+  memcpy(b->uri, uri, len * sizeof(XML_Char));
+  if (namespaceSeparator)
+    b->uri[len - 1] = namespaceSeparator;
+  b->prefix = prefix;
+  b->attId = attId;
+  b->prevPrefixBinding = prefix->binding;
+  /* NULL binding when default namespace undeclared */
+  if (*uri == XML_T('\0') && prefix == &_dtd->defaultPrefix)
+    prefix->binding = NULL;
+  else
+    prefix->binding = b;
+  b->nextTagBinding = *bindingsPtr;
+  *bindingsPtr = b;
+  /* if attId == NULL then we are not starting a namespace scope */
+  if (attId && startNamespaceDeclHandler)
+    startNamespaceDeclHandler(handlerArg, prefix->name,
+                              prefix->binding ? uri : 0);
+  return XML_ERROR_NONE;
+}
+
+/* The idea here is to avoid using stack for each CDATA section when
+   the whole file is parsed with one call.
+*/
+static enum XML_Error PTRCALL
+cdataSectionProcessor(XML_Parser parser,
+                      const char *start,
+                      const char *end,
+                      const char **endPtr)
+{
+  enum XML_Error result = doCdataSection(parser, encoding, &start, end,
+                                         endPtr, (XML_Bool)!ps_finalBuffer);
+  if (result != XML_ERROR_NONE)
+    return result;
+  if (start) {
+    if (parentParser) {  /* we are parsing an external entity */
+      processor = externalEntityContentProcessor;
+      return externalEntityContentProcessor(parser, start, end, endPtr);
+    }
+    else {
+      processor = contentProcessor;
+      return contentProcessor(parser, start, end, endPtr);
+    }
+  }
+  return result;
+}
+
+/* startPtr gets set to non-null if the section is closed, and to null if
+   the section is not yet closed.
+*/
+static enum XML_Error
+doCdataSection(XML_Parser parser,
+               const ENCODING *enc,
+               const char **startPtr,
+               const char *end,
+               const char **nextPtr,
+               XML_Bool haveMore)
+{
+  const char *s = *startPtr;
+  const char **eventPP;
+  const char **eventEndPP;
+  if (enc == encoding) {
+    eventPP = &eventPtr;
+    *eventPP = s;
+    eventEndPP = &eventEndPtr;
+  }
+  else {
+    eventPP = &(openInternalEntities->internalEventPtr);
+    eventEndPP = &(openInternalEntities->internalEventEndPtr);
+  }
+  *eventPP = s;
+  *startPtr = NULL;
+
+  for (;;) {
+    const char *next;
+    int tok = XmlCdataSectionTok(enc, s, end, &next);
+    *eventEndPP = next;
+    switch (tok) {
+    case XML_TOK_CDATA_SECT_CLOSE:
+      if (endCdataSectionHandler)
+        endCdataSectionHandler(handlerArg);
+#if 0
+      /* see comment under XML_TOK_CDATA_SECT_OPEN */
+      else if (characterDataHandler)
+        characterDataHandler(handlerArg, dataBuf, 0);
+#endif
+      else if (defaultHandler)
+        reportDefault(parser, enc, s, next);
+      *startPtr = next;
+      *nextPtr = next;
+      if (ps_parsing == XML_FINISHED)
+        return XML_ERROR_ABORTED;
+      else
+        return XML_ERROR_NONE;
+    case XML_TOK_DATA_NEWLINE:
+      if (characterDataHandler) {
+        XML_Char c = 0xA;
+        characterDataHandler(handlerArg, &c, 1);
+      }
+      else if (defaultHandler)
+        reportDefault(parser, enc, s, next);
+      break;
+    case XML_TOK_DATA_CHARS:
+      {
+        XML_CharacterDataHandler charDataHandler = characterDataHandler;
+        if (charDataHandler) {
+          if (MUST_CONVERT(enc, s)) {
+            for (;;) {
+              ICHAR *dataPtr = (ICHAR *)dataBuf;
+              XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+              *eventEndPP = next;
+              charDataHandler(handlerArg, dataBuf,
+                              (int)(dataPtr - (ICHAR *)dataBuf));
+              if (s == next)
+                break;
+              *eventPP = s;
+            }
+          }
+          else
+            charDataHandler(handlerArg,
+                            (XML_Char *)s,
+                            (int)((XML_Char *)next - (XML_Char *)s));
+        }
+        else if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+      }
+      break;
+    case XML_TOK_INVALID:
+      *eventPP = next;
+      return XML_ERROR_INVALID_TOKEN;
+    case XML_TOK_PARTIAL_CHAR:
+      if (haveMore) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      return XML_ERROR_PARTIAL_CHAR;
+    case XML_TOK_PARTIAL:
+    case XML_TOK_NONE:
+      if (haveMore) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      return XML_ERROR_UNCLOSED_CDATA_SECTION;
+    default:
+      *eventPP = next;
+      return XML_ERROR_UNEXPECTED_STATE;
+    }
+
+    *eventPP = s = next;
+    switch (ps_parsing) {
+    case XML_SUSPENDED:
+      *nextPtr = next;
+      return XML_ERROR_NONE;
+    case XML_FINISHED:
+      return XML_ERROR_ABORTED;
+    default: ;
+    }
+  }
+  /* not reached */
+}
+
+#ifdef XML_DTD
+
+/* The idea here is to avoid using stack for each IGNORE section when
+   the whole file is parsed with one call.
+*/
+static enum XML_Error PTRCALL
+ignoreSectionProcessor(XML_Parser parser,
+                       const char *start,
+                       const char *end,
+                       const char **endPtr)
+{
+  enum XML_Error result = doIgnoreSection(parser, encoding, &start, end,
+                                          endPtr, (XML_Bool)!ps_finalBuffer);
+  if (result != XML_ERROR_NONE)
+    return result;
+  if (start) {
+    processor = prologProcessor;
+    return prologProcessor(parser, start, end, endPtr);
+  }
+  return result;
+}
+
+/* startPtr gets set to non-null is the section is closed, and to null
+   if the section is not yet closed.
+*/
+static enum XML_Error
+doIgnoreSection(XML_Parser parser,
+                const ENCODING *enc,
+                const char **startPtr,
+                const char *end,
+                const char **nextPtr,
+                XML_Bool haveMore)
+{
+  const char *next;
+  int tok;
+  const char *s = *startPtr;
+  const char **eventPP;
+  const char **eventEndPP;
+  if (enc == encoding) {
+    eventPP = &eventPtr;
+    *eventPP = s;
+    eventEndPP = &eventEndPtr;
+  }
+  else {
+    eventPP = &(openInternalEntities->internalEventPtr);
+    eventEndPP = &(openInternalEntities->internalEventEndPtr);
+  }
+  *eventPP = s;
+  *startPtr = NULL;
+  tok = XmlIgnoreSectionTok(enc, s, end, &next);
+  *eventEndPP = next;
+  switch (tok) {
+  case XML_TOK_IGNORE_SECT:
+    if (defaultHandler)
+      reportDefault(parser, enc, s, next);
+    *startPtr = next;
+    *nextPtr = next;
+    if (ps_parsing == XML_FINISHED)
+      return XML_ERROR_ABORTED;
+    else
+      return XML_ERROR_NONE;
+  case XML_TOK_INVALID:
+    *eventPP = next;
+    return XML_ERROR_INVALID_TOKEN;
+  case XML_TOK_PARTIAL_CHAR:
+    if (haveMore) {
+      *nextPtr = s;
+      return XML_ERROR_NONE;
+    }
+    return XML_ERROR_PARTIAL_CHAR;
+  case XML_TOK_PARTIAL:
+  case XML_TOK_NONE:
+    if (haveMore) {
+      *nextPtr = s;
+      return XML_ERROR_NONE;
+    }
+    return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */
+  default:
+    *eventPP = next;
+    return XML_ERROR_UNEXPECTED_STATE;
+  }
+  /* not reached */
+}
+
+#endif /* XML_DTD */
+
+static enum XML_Error
+initializeEncoding(XML_Parser parser)
+{
+  const char *s;
+#ifdef XML_UNICODE
+  char encodingBuf[128];
+  if (!protocolEncodingName)
+    s = NULL;
+  else {
+    int i;
+    for (i = 0; protocolEncodingName[i]; i++) {
+      if (i == sizeof(encodingBuf) - 1
+          || (protocolEncodingName[i] & ~0x7f) != 0) {
+        encodingBuf[0] = '\0';
+        break;
+      }
+      encodingBuf[i] = (char)protocolEncodingName[i];
+    }
+    encodingBuf[i] = '\0';
+    s = encodingBuf;
+  }
+#else
+  s = protocolEncodingName;
+#endif
+  if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s))
+    return XML_ERROR_NONE;
+  return handleUnknownEncoding(parser, protocolEncodingName);
+}
+
+static enum XML_Error
+processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
+               const char *s, const char *next)
+{
+  const char *encodingName = NULL;
+  const XML_Char *storedEncName = NULL;
+  const ENCODING *newEncoding = NULL;
+  const char *version = NULL;
+  const char *versionend;
+  const XML_Char *storedversion = NULL;
+  int standalone = -1;
+  if (!(ns
+        ? XmlParseXmlDeclNS
+        : XmlParseXmlDecl)(isGeneralTextEntity,
+                           encoding,
+                           s,
+                           next,
+                           &eventPtr,
+                           &version,
+                           &versionend,
+                           &encodingName,
+                           &newEncoding,
+                           &standalone)) {
+    if (isGeneralTextEntity)
+      return XML_ERROR_TEXT_DECL;
+    else
+      return XML_ERROR_XML_DECL;
+  }
+  if (!isGeneralTextEntity && standalone == 1) {
+    _dtd->standalone = XML_TRUE;
+#ifdef XML_DTD
+    if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
+      paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+#endif /* XML_DTD */
+  }
+  if (xmlDeclHandler) {
+    if (encodingName != NULL) {
+      storedEncName = poolStoreString(&temp2Pool,
+                                      encoding,
+                                      encodingName,
+                                      encodingName
+                                      + XmlNameLength(encoding, encodingName));
+      if (!storedEncName)
+              return XML_ERROR_NO_MEMORY;
+      poolFinish(&temp2Pool);
+    }
+    if (version) {
+      storedversion = poolStoreString(&temp2Pool,
+                                      encoding,
+                                      version,
+                                      versionend - encoding->minBytesPerChar);
+      if (!storedversion)
+        return XML_ERROR_NO_MEMORY;
+    }
+    xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone);
+  }
+  else if (defaultHandler)
+    reportDefault(parser, encoding, s, next);
+  if (protocolEncodingName == NULL) {
+    if (newEncoding) {
+      if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) {
+        eventPtr = encodingName;
+        return XML_ERROR_INCORRECT_ENCODING;
+      }
+      encoding = newEncoding;
+    }
+    else if (encodingName) {
+      enum XML_Error result;
+      if (!storedEncName) {
+        storedEncName = poolStoreString(
+          &temp2Pool, encoding, encodingName,
+          encodingName + XmlNameLength(encoding, encodingName));
+        if (!storedEncName)
+          return XML_ERROR_NO_MEMORY;
+      }
+      result = handleUnknownEncoding(parser, storedEncName);
+      poolClear(&temp2Pool);
+      if (result == XML_ERROR_UNKNOWN_ENCODING)
+        eventPtr = encodingName;
+      return result;
+    }
+  }
+
+  if (storedEncName || storedversion)
+    poolClear(&temp2Pool);
+
+  return XML_ERROR_NONE;
+}
+
+static enum XML_Error
+handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)
+{
+  if (unknownEncodingHandler) {
+    XML_Encoding info;
+    int i;
+    for (i = 0; i < 256; i++)
+      info.map[i] = -1;
+    info.convert = NULL;
+    info.data = NULL;
+    info.release = NULL;
+    if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName,
+                               &info)) {
+      ENCODING *enc;
+      unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding());
+      if (!unknownEncodingMem) {
+        if (info.release)
+          info.release(info.data);
+        return XML_ERROR_NO_MEMORY;
+      }
+      enc = (ns
+             ? XmlInitUnknownEncodingNS
+             : XmlInitUnknownEncoding)(unknownEncodingMem,
+                                       info.map,
+                                       info.convert,
+                                       info.data);
+      if (enc) {
+        unknownEncodingData = info.data;
+        unknownEncodingRelease = info.release;
+        encoding = enc;
+        return XML_ERROR_NONE;
+      }
+    }
+    if (info.release != NULL)
+      info.release(info.data);
+  }
+  return XML_ERROR_UNKNOWN_ENCODING;
+}
+
+static enum XML_Error PTRCALL
+prologInitProcessor(XML_Parser parser,
+                    const char *s,
+                    const char *end,
+                    const char **nextPtr)
+{
+  enum XML_Error result = initializeEncoding(parser);
+  if (result != XML_ERROR_NONE)
+    return result;
+  processor = prologProcessor;
+  return prologProcessor(parser, s, end, nextPtr);
+}
+
+#ifdef XML_DTD
+
+static enum XML_Error PTRCALL
+externalParEntInitProcessor(XML_Parser parser,
+                            const char *s,
+                            const char *end,
+                            const char **nextPtr)
+{
+  enum XML_Error result = initializeEncoding(parser);
+  if (result != XML_ERROR_NONE)
+    return result;
+
+  /* we know now that XML_Parse(Buffer) has been called,
+     so we consider the external parameter entity read */
+  _dtd->paramEntityRead = XML_TRUE;
+
+  if (prologState.inEntityValue) {
+    processor = entityValueInitProcessor;
+    return entityValueInitProcessor(parser, s, end, nextPtr);
+  }
+  else {
+    processor = externalParEntProcessor;
+    return externalParEntProcessor(parser, s, end, nextPtr);
+  }
+}
+
+static enum XML_Error PTRCALL
+entityValueInitProcessor(XML_Parser parser,
+                         const char *s,
+                         const char *end,
+                         const char **nextPtr)
+{
+  int tok;
+  const char *start = s;
+  const char *next = start;
+  eventPtr = start;
+
+  for (;;) {
+    tok = XmlPrologTok(encoding, start, end, &next);
+    eventEndPtr = next;
+    if (tok <= 0) {
+      if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      switch (tok) {
+      case XML_TOK_INVALID:
+        return XML_ERROR_INVALID_TOKEN;
+      case XML_TOK_PARTIAL:
+        return XML_ERROR_UNCLOSED_TOKEN;
+      case XML_TOK_PARTIAL_CHAR:
+        return XML_ERROR_PARTIAL_CHAR;
+      case XML_TOK_NONE:   /* start == end */
+      default:
+        break;
+      }
+      /* found end of entity value - can store it now */
+      return storeEntityValue(parser, encoding, s, end);
+    }
+    else if (tok == XML_TOK_XML_DECL) {
+      enum XML_Error result;
+      result = processXmlDecl(parser, 0, start, next);
+      if (result != XML_ERROR_NONE)
+        return result;
+      switch (ps_parsing) {
+      case XML_SUSPENDED:
+        *nextPtr = next;
+        return XML_ERROR_NONE;
+      case XML_FINISHED:
+        return XML_ERROR_ABORTED;
+      default:
+        *nextPtr = next;
+      }
+      /* stop scanning for text declaration - we found one */
+      processor = entityValueProcessor;
+      return entityValueProcessor(parser, next, end, nextPtr);
+    }
+    /* If we are at the end of the buffer, this would cause XmlPrologTok to
+       return XML_TOK_NONE on the next call, which would then cause the
+       function to exit with *nextPtr set to s - that is what we want for other
+       tokens, but not for the BOM - we would rather like to skip it;
+       then, when this routine is entered the next time, XmlPrologTok will
+       return XML_TOK_INVALID, since the BOM is still in the buffer
+    */
+    else if (tok == XML_TOK_BOM && next == end && !ps_finalBuffer) {
+      *nextPtr = next;
+      return XML_ERROR_NONE;
+    }
+    start = next;
+    eventPtr = start;
+  }
+}
+
+static enum XML_Error PTRCALL
+externalParEntProcessor(XML_Parser parser,
+                        const char *s,
+                        const char *end,
+                        const char **nextPtr)
+{
+  const char *next = s;
+  int tok;
+
+  tok = XmlPrologTok(encoding, s, end, &next);
+  if (tok <= 0) {
+    if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+      *nextPtr = s;
+      return XML_ERROR_NONE;
+    }
+    switch (tok) {
+    case XML_TOK_INVALID:
+      return XML_ERROR_INVALID_TOKEN;
+    case XML_TOK_PARTIAL:
+      return XML_ERROR_UNCLOSED_TOKEN;
+    case XML_TOK_PARTIAL_CHAR:
+      return XML_ERROR_PARTIAL_CHAR;
+    case XML_TOK_NONE:   /* start == end */
+    default:
+      break;
+    }
+  }
+  /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM.
+     However, when parsing an external subset, doProlog will not accept a BOM
+     as valid, and report a syntax error, so we have to skip the BOM
+  */
+  else if (tok == XML_TOK_BOM) {
+    s = next;
+    tok = XmlPrologTok(encoding, s, end, &next);
+  }
+
+  processor = prologProcessor;
+  return doProlog(parser, encoding, s, end, tok, next,
+                  nextPtr, (XML_Bool)!ps_finalBuffer);
+}
+
+static enum XML_Error PTRCALL
+entityValueProcessor(XML_Parser parser,
+                     const char *s,
+                     const char *end,
+                     const char **nextPtr)
+{
+  const char *start = s;
+  const char *next = s;
+  const ENCODING *enc = encoding;
+  int tok;
+
+  for (;;) {
+    tok = XmlPrologTok(enc, start, end, &next);
+    if (tok <= 0) {
+      if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      switch (tok) {
+      case XML_TOK_INVALID:
+        return XML_ERROR_INVALID_TOKEN;
+      case XML_TOK_PARTIAL:
+        return XML_ERROR_UNCLOSED_TOKEN;
+      case XML_TOK_PARTIAL_CHAR:
+        return XML_ERROR_PARTIAL_CHAR;
+      case XML_TOK_NONE:   /* start == end */
+      default:
+        break;
+      }
+      /* found end of entity value - can store it now */
+      return storeEntityValue(parser, enc, s, end);
+    }
+    start = next;
+  }
+}
+
+#endif /* XML_DTD */
+
+static enum XML_Error PTRCALL
+prologProcessor(XML_Parser parser,
+                const char *s,
+                const char *end,
+                const char **nextPtr)
+{
+  const char *next = s;
+  int tok = XmlPrologTok(encoding, s, end, &next);
+  return doProlog(parser, encoding, s, end, tok, next,
+                  nextPtr, (XML_Bool)!ps_finalBuffer);
+}
+
+static enum XML_Error
+doProlog(XML_Parser parser,
+         const ENCODING *enc,
+         const char *s,
+         const char *end,
+         int tok,
+         const char *next,
+         const char **nextPtr,
+         XML_Bool haveMore)
+{
+#ifdef XML_DTD
+  static const XML_Char externalSubsetName[] = { ASCII_HASH , '\0' };
+#endif /* XML_DTD */
+  static const XML_Char atypeCDATA[] =
+      { ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+  static const XML_Char atypeID[] = { ASCII_I, ASCII_D, '\0' };
+  static const XML_Char atypeIDREF[] =
+      { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' };
+  static const XML_Char atypeIDREFS[] =
+      { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' };
+  static const XML_Char atypeENTITY[] =
+      { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' };
+  static const XML_Char atypeENTITIES[] = { ASCII_E, ASCII_N,
+      ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, '\0' };
+  static const XML_Char atypeNMTOKEN[] = {
+      ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' };
+  static const XML_Char atypeNMTOKENS[] = { ASCII_N, ASCII_M, ASCII_T,
+      ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, '\0' };
+  static const XML_Char notationPrefix[] = { ASCII_N, ASCII_O, ASCII_T,
+      ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, ASCII_LPAREN, '\0' };
+  static const XML_Char enumValueSep[] = { ASCII_PIPE, '\0' };
+  static const XML_Char enumValueStart[] = { ASCII_LPAREN, '\0' };
+
+  /* save one level of indirection */
+  DTD * const dtd = _dtd;
+
+  const char **eventPP;
+  const char **eventEndPP;
+  enum XML_Content_Quant quant;
+
+  if (enc == encoding) {
+    eventPP = &eventPtr;
+    eventEndPP = &eventEndPtr;
+  }
+  else {
+    eventPP = &(openInternalEntities->internalEventPtr);
+    eventEndPP = &(openInternalEntities->internalEventEndPtr);
+  }
+
+  for (;;) {
+    int role;
+    XML_Bool handleDefault = XML_TRUE;
+    *eventPP = s;
+    *eventEndPP = next;
+    if (tok <= 0) {
+      if (haveMore && tok != XML_TOK_INVALID) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      switch (tok) {
+      case XML_TOK_INVALID:
+        *eventPP = next;
+        return XML_ERROR_INVALID_TOKEN;
+      case XML_TOK_PARTIAL:
+        return XML_ERROR_UNCLOSED_TOKEN;
+      case XML_TOK_PARTIAL_CHAR:
+        return XML_ERROR_PARTIAL_CHAR;
+      case -XML_TOK_PROLOG_S:
+        tok = -tok;
+        break;
+      case XML_TOK_NONE:
+#ifdef XML_DTD
+        /* for internal PE NOT referenced between declarations */
+        if (enc != encoding && !openInternalEntities->betweenDecl) {
+          *nextPtr = s;
+          return XML_ERROR_NONE;
+        }
+        /* WFC: PE Between Declarations - must check that PE contains
+           complete markup, not only for external PEs, but also for
+           internal PEs if the reference occurs between declarations.
+        */
+        if (isParamEntity || enc != encoding) {
+          if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc)
+              == XML_ROLE_ERROR)
+            return XML_ERROR_INCOMPLETE_PE;
+          *nextPtr = s;
+          return XML_ERROR_NONE;
+        }
+#endif /* XML_DTD */
+        return XML_ERROR_NO_ELEMENTS;
+      default:
+        tok = -tok;
+        next = end;
+        break;
+      }
+    }
+    role = XmlTokenRole(&prologState, tok, s, next, enc);
+    switch (role) {
+    case XML_ROLE_XML_DECL:
+      {
+        enum XML_Error result = processXmlDecl(parser, 0, s, next);
+        if (result != XML_ERROR_NONE)
+          return result;
+        enc = encoding;
+        handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_DOCTYPE_NAME:
+      if (startDoctypeDeclHandler) {
+        doctypeName = poolStoreString(&tempPool, enc, s, next);
+        if (!doctypeName)
+          return XML_ERROR_NO_MEMORY;
+        poolFinish(&tempPool);
+        doctypePubid = NULL;
+        handleDefault = XML_FALSE;
+      }
+      doctypeSysid = NULL; /* always initialize to NULL */
+      break;
+    case XML_ROLE_DOCTYPE_INTERNAL_SUBSET:
+      if (startDoctypeDeclHandler) {
+        startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid,
+                                doctypePubid, 1);
+        doctypeName = NULL;
+        poolClear(&tempPool);
+        handleDefault = XML_FALSE;
+      }
+      break;
+#ifdef XML_DTD
+    case XML_ROLE_TEXT_DECL:
+      {
+        enum XML_Error result = processXmlDecl(parser, 1, s, next);
+        if (result != XML_ERROR_NONE)
+          return result;
+        enc = encoding;
+        handleDefault = XML_FALSE;
+      }
+      break;
+#endif /* XML_DTD */
+    case XML_ROLE_DOCTYPE_PUBLIC_ID:
+#ifdef XML_DTD
+      useForeignDTD = XML_FALSE;
+      declEntity = (ENTITY *)lookup(parser,
+                                    &dtd->paramEntities,
+                                    externalSubsetName,
+                                    sizeof(ENTITY));
+      if (!declEntity)
+        return XML_ERROR_NO_MEMORY;
+#endif /* XML_DTD */
+      dtd->hasParamEntityRefs = XML_TRUE;
+      if (startDoctypeDeclHandler) {
+        XML_Char *pubId;
+        if (!XmlIsPublicId(enc, s, next, eventPP))
+          return XML_ERROR_PUBLICID;
+        pubId = poolStoreString(&tempPool, enc,
+                                s + enc->minBytesPerChar,
+                                next - enc->minBytesPerChar);
+        if (!pubId)
+          return XML_ERROR_NO_MEMORY;
+        normalizePublicId(pubId);
+        poolFinish(&tempPool);
+        doctypePubid = pubId;
+        handleDefault = XML_FALSE;
+        goto alreadyChecked;
+      }
+      /* fall through */
+    case XML_ROLE_ENTITY_PUBLIC_ID:
+      if (!XmlIsPublicId(enc, s, next, eventPP))
+        return XML_ERROR_PUBLICID;
+    alreadyChecked:
+      if (dtd->keepProcessing && declEntity) {
+        XML_Char *tem = poolStoreString(&dtd->pool,
+                                        enc,
+                                        s + enc->minBytesPerChar,
+                                        next - enc->minBytesPerChar);
+        if (!tem)
+          return XML_ERROR_NO_MEMORY;
+        normalizePublicId(tem);
+        declEntity->publicId = tem;
+        poolFinish(&dtd->pool);
+        if (entityDeclHandler)
+          handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_DOCTYPE_CLOSE:
+      if (doctypeName) {
+        startDoctypeDeclHandler(handlerArg, doctypeName,
+                                doctypeSysid, doctypePubid, 0);
+        poolClear(&tempPool);
+        handleDefault = XML_FALSE;
+      }
+      /* doctypeSysid will be non-NULL in the case of a previous
+         XML_ROLE_DOCTYPE_SYSTEM_ID, even if startDoctypeDeclHandler
+         was not set, indicating an external subset
+      */
+#ifdef XML_DTD
+      if (doctypeSysid || useForeignDTD) {
+        XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
+        dtd->hasParamEntityRefs = XML_TRUE;
+        if (paramEntityParsing && externalEntityRefHandler) {
+          ENTITY *entity = (ENTITY *)lookup(parser,
+                                            &dtd->paramEntities,
+                                            externalSubsetName,
+                                            sizeof(ENTITY));
+          if (!entity)
+            return XML_ERROR_NO_MEMORY;
+          if (useForeignDTD)
+            entity->base = curBase;
+          dtd->paramEntityRead = XML_FALSE;
+          if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+                                        0,
+                                        entity->base,
+                                        entity->systemId,
+                                        entity->publicId))
+            return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+          if (dtd->paramEntityRead) {
+            if (!dtd->standalone &&
+                notStandaloneHandler &&
+                !notStandaloneHandler(handlerArg))
+              return XML_ERROR_NOT_STANDALONE;
+          }
+          /* if we didn't read the foreign DTD then this means that there
+             is no external subset and we must reset dtd->hasParamEntityRefs
+          */
+          else if (!doctypeSysid)
+            dtd->hasParamEntityRefs = hadParamEntityRefs;
+          /* end of DTD - no need to update dtd->keepProcessing */
+        }
+        useForeignDTD = XML_FALSE;
+      }
+#endif /* XML_DTD */
+      if (endDoctypeDeclHandler) {
+        endDoctypeDeclHandler(handlerArg);
+        handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_INSTANCE_START:
+#ifdef XML_DTD
+      /* if there is no DOCTYPE declaration then now is the
+         last chance to read the foreign DTD
+      */
+      if (useForeignDTD) {
+        XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
+        dtd->hasParamEntityRefs = XML_TRUE;
+        if (paramEntityParsing && externalEntityRefHandler) {
+          ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities,
+                                            externalSubsetName,
+                                            sizeof(ENTITY));
+          if (!entity)
+            return XML_ERROR_NO_MEMORY;
+          entity->base = curBase;
+          dtd->paramEntityRead = XML_FALSE;
+          if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+                                        0,
+                                        entity->base,
+                                        entity->systemId,
+                                        entity->publicId))
+            return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+          if (dtd->paramEntityRead) {
+            if (!dtd->standalone &&
+                notStandaloneHandler &&
+                !notStandaloneHandler(handlerArg))
+              return XML_ERROR_NOT_STANDALONE;
+          }
+          /* if we didn't read the foreign DTD then this means that there
+             is no external subset and we must reset dtd->hasParamEntityRefs
+          */
+          else
+            dtd->hasParamEntityRefs = hadParamEntityRefs;
+          /* end of DTD - no need to update dtd->keepProcessing */
+        }
+      }
+#endif /* XML_DTD */
+      processor = contentProcessor;
+      return contentProcessor(parser, s, end, nextPtr);
+    case XML_ROLE_ATTLIST_ELEMENT_NAME:
+      declElementType = getElementType(parser, enc, s, next);
+      if (!declElementType)
+        return XML_ERROR_NO_MEMORY;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_NAME:
+      declAttributeId = getAttributeId(parser, enc, s, next);
+      if (!declAttributeId)
+        return XML_ERROR_NO_MEMORY;
+      declAttributeIsCdata = XML_FALSE;
+      declAttributeType = NULL;
+      declAttributeIsId = XML_FALSE;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_CDATA:
+      declAttributeIsCdata = XML_TRUE;
+      declAttributeType = atypeCDATA;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_ID:
+      declAttributeIsId = XML_TRUE;
+      declAttributeType = atypeID;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_IDREF:
+      declAttributeType = atypeIDREF;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_IDREFS:
+      declAttributeType = atypeIDREFS;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_ENTITY:
+      declAttributeType = atypeENTITY;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES:
+      declAttributeType = atypeENTITIES;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN:
+      declAttributeType = atypeNMTOKEN;
+      goto checkAttListDeclHandler;
+    case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS:
+      declAttributeType = atypeNMTOKENS;
+    checkAttListDeclHandler:
+      if (dtd->keepProcessing && attlistDeclHandler)
+        handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_ATTRIBUTE_ENUM_VALUE:
+    case XML_ROLE_ATTRIBUTE_NOTATION_VALUE:
+      if (dtd->keepProcessing && attlistDeclHandler) {
+        const XML_Char *prefix;
+        if (declAttributeType) {
+          prefix = enumValueSep;
+        }
+        else {
+          prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE
+                    ? notationPrefix
+                    : enumValueStart);
+        }
+        if (!poolAppendString(&tempPool, prefix))
+          return XML_ERROR_NO_MEMORY;
+        if (!poolAppend(&tempPool, enc, s, next))
+          return XML_ERROR_NO_MEMORY;
+        declAttributeType = tempPool.start;
+        handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE:
+    case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE:
+      if (dtd->keepProcessing) {
+        if (!defineAttribute(declElementType, declAttributeId,
+                             declAttributeIsCdata, declAttributeIsId,
+                             0, parser))
+          return XML_ERROR_NO_MEMORY;
+        if (attlistDeclHandler && declAttributeType) {
+          if (*declAttributeType == XML_T(ASCII_LPAREN)
+              || (*declAttributeType == XML_T(ASCII_N)
+                  && declAttributeType[1] == XML_T(ASCII_O))) {
+            /* Enumerated or Notation type */
+            if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
+                || !poolAppendChar(&tempPool, XML_T('\0')))
+              return XML_ERROR_NO_MEMORY;
+            declAttributeType = tempPool.start;
+            poolFinish(&tempPool);
+          }
+          *eventEndPP = s;
+          attlistDeclHandler(handlerArg, declElementType->name,
+                             declAttributeId->name, declAttributeType,
+                             0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
+          poolClear(&tempPool);
+          handleDefault = XML_FALSE;
+        }
+      }
+      break;
+    case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE:
+    case XML_ROLE_FIXED_ATTRIBUTE_VALUE:
+      if (dtd->keepProcessing) {
+        const XML_Char *attVal;
+        enum XML_Error result =
+          storeAttributeValue(parser, enc, declAttributeIsCdata,
+                              s + enc->minBytesPerChar,
+                              next - enc->minBytesPerChar,
+                              &dtd->pool);
+        if (result)
+          return result;
+        attVal = poolStart(&dtd->pool);
+        poolFinish(&dtd->pool);
+        /* ID attributes aren't allowed to have a default */
+        if (!defineAttribute(declElementType, declAttributeId,
+                             declAttributeIsCdata, XML_FALSE, attVal, parser))
+          return XML_ERROR_NO_MEMORY;
+        if (attlistDeclHandler && declAttributeType) {
+          if (*declAttributeType == XML_T(ASCII_LPAREN)
+              || (*declAttributeType == XML_T(ASCII_N)
+                  && declAttributeType[1] == XML_T(ASCII_O))) {
+            /* Enumerated or Notation type */
+            if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
+                || !poolAppendChar(&tempPool, XML_T('\0')))
+              return XML_ERROR_NO_MEMORY;
+            declAttributeType = tempPool.start;
+            poolFinish(&tempPool);
+          }
+          *eventEndPP = s;
+          attlistDeclHandler(handlerArg, declElementType->name,
+                             declAttributeId->name, declAttributeType,
+                             attVal,
+                             role == XML_ROLE_FIXED_ATTRIBUTE_VALUE);
+          poolClear(&tempPool);
+          handleDefault = XML_FALSE;
+        }
+      }
+      break;
+    case XML_ROLE_ENTITY_VALUE:
+      if (dtd->keepProcessing) {
+        enum XML_Error result = storeEntityValue(parser, enc,
+                                            s + enc->minBytesPerChar,
+                                            next - enc->minBytesPerChar);
+        if (declEntity) {
+          declEntity->textPtr = poolStart(&dtd->entityValuePool);
+          declEntity->textLen = (int)(poolLength(&dtd->entityValuePool));
+          poolFinish(&dtd->entityValuePool);
+          if (entityDeclHandler) {
+            *eventEndPP = s;
+            entityDeclHandler(handlerArg,
+                              declEntity->name,
+                              declEntity->is_param,
+                              declEntity->textPtr,
+                              declEntity->textLen,
+                              curBase, 0, 0, 0);
+            handleDefault = XML_FALSE;
+          }
+        }
+        else
+          poolDiscard(&dtd->entityValuePool);
+        if (result != XML_ERROR_NONE)
+          return result;
+      }
+      break;
+    case XML_ROLE_DOCTYPE_SYSTEM_ID:
+#ifdef XML_DTD
+      useForeignDTD = XML_FALSE;
+#endif /* XML_DTD */
+      dtd->hasParamEntityRefs = XML_TRUE;
+      if (startDoctypeDeclHandler) {
+        doctypeSysid = poolStoreString(&tempPool, enc,
+                                       s + enc->minBytesPerChar,
+                                       next - enc->minBytesPerChar);
+        if (doctypeSysid == NULL)
+          return XML_ERROR_NO_MEMORY;
+        poolFinish(&tempPool);
+        handleDefault = XML_FALSE;
+      }
+#ifdef XML_DTD
+      else
+        /* use externalSubsetName to make doctypeSysid non-NULL
+           for the case where no startDoctypeDeclHandler is set */
+        doctypeSysid = externalSubsetName;
+#endif /* XML_DTD */
+      if (!dtd->standalone
+#ifdef XML_DTD
+          && !paramEntityParsing
+#endif /* XML_DTD */
+          && notStandaloneHandler
+          && !notStandaloneHandler(handlerArg))
+        return XML_ERROR_NOT_STANDALONE;
+#ifndef XML_DTD
+      break;
+#else /* XML_DTD */
+      if (!declEntity) {
+        declEntity = (ENTITY *)lookup(parser,
+                                      &dtd->paramEntities,
+                                      externalSubsetName,
+                                      sizeof(ENTITY));
+        if (!declEntity)
+          return XML_ERROR_NO_MEMORY;
+        declEntity->publicId = NULL;
+      }
+      /* fall through */
+#endif /* XML_DTD */
+    case XML_ROLE_ENTITY_SYSTEM_ID:
+      if (dtd->keepProcessing && declEntity) {
+        declEntity->systemId = poolStoreString(&dtd->pool, enc,
+                                               s + enc->minBytesPerChar,
+                                               next - enc->minBytesPerChar);
+        if (!declEntity->systemId)
+          return XML_ERROR_NO_MEMORY;
+        declEntity->base = curBase;
+        poolFinish(&dtd->pool);
+        if (entityDeclHandler)
+          handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_ENTITY_COMPLETE:
+      if (dtd->keepProcessing && declEntity && entityDeclHandler) {
+        *eventEndPP = s;
+        entityDeclHandler(handlerArg,
+                          declEntity->name,
+                          declEntity->is_param,
+                          0,0,
+                          declEntity->base,
+                          declEntity->systemId,
+                          declEntity->publicId,
+                          0);
+        handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_ENTITY_NOTATION_NAME:
+      if (dtd->keepProcessing && declEntity) {
+        declEntity->notation = poolStoreString(&dtd->pool, enc, s, next);
+        if (!declEntity->notation)
+          return XML_ERROR_NO_MEMORY;
+        poolFinish(&dtd->pool);
+        if (unparsedEntityDeclHandler) {
+          *eventEndPP = s;
+          unparsedEntityDeclHandler(handlerArg,
+                                    declEntity->name,
+                                    declEntity->base,
+                                    declEntity->systemId,
+                                    declEntity->publicId,
+                                    declEntity->notation);
+          handleDefault = XML_FALSE;
+        }
+        else if (entityDeclHandler) {
+          *eventEndPP = s;
+          entityDeclHandler(handlerArg,
+                            declEntity->name,
+                            0,0,0,
+                            declEntity->base,
+                            declEntity->systemId,
+                            declEntity->publicId,
+                            declEntity->notation);
+          handleDefault = XML_FALSE;
+        }
+      }
+      break;
+    case XML_ROLE_GENERAL_ENTITY_NAME:
+      {
+        if (XmlPredefinedEntityName(enc, s, next)) {
+          declEntity = NULL;
+          break;
+        }
+        if (dtd->keepProcessing) {
+          const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
+          if (!name)
+            return XML_ERROR_NO_MEMORY;
+          declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name,
+                                        sizeof(ENTITY));
+          if (!declEntity)
+            return XML_ERROR_NO_MEMORY;
+          if (declEntity->name != name) {
+            poolDiscard(&dtd->pool);
+            declEntity = NULL;
+          }
+          else {
+            poolFinish(&dtd->pool);
+            declEntity->publicId = NULL;
+            declEntity->is_param = XML_FALSE;
+            /* if we have a parent parser or are reading an internal parameter
+               entity, then the entity declaration is not considered "internal"
+            */
+            declEntity->is_internal = !(parentParser || openInternalEntities);
+            if (entityDeclHandler)
+              handleDefault = XML_FALSE;
+          }
+        }
+        else {
+          poolDiscard(&dtd->pool);
+          declEntity = NULL;
+        }
+      }
+      break;
+    case XML_ROLE_PARAM_ENTITY_NAME:
+#ifdef XML_DTD
+      if (dtd->keepProcessing) {
+        const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
+        if (!name)
+          return XML_ERROR_NO_MEMORY;
+        declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities,
+                                           name, sizeof(ENTITY));
+        if (!declEntity)
+          return XML_ERROR_NO_MEMORY;
+        if (declEntity->name != name) {
+          poolDiscard(&dtd->pool);
+          declEntity = NULL;
+        }
+        else {
+          poolFinish(&dtd->pool);
+          declEntity->publicId = NULL;
+          declEntity->is_param = XML_TRUE;
+          /* if we have a parent parser or are reading an internal parameter
+             entity, then the entity declaration is not considered "internal"
+          */
+          declEntity->is_internal = !(parentParser || openInternalEntities);
+          if (entityDeclHandler)
+            handleDefault = XML_FALSE;
+        }
+      }
+      else {
+        poolDiscard(&dtd->pool);
+        declEntity = NULL;
+      }
+#else /* not XML_DTD */
+      declEntity = NULL;
+#endif /* XML_DTD */
+      break;
+    case XML_ROLE_NOTATION_NAME:
+      declNotationPublicId = NULL;
+      declNotationName = NULL;
+      if (notationDeclHandler) {
+        declNotationName = poolStoreString(&tempPool, enc, s, next);
+        if (!declNotationName)
+          return XML_ERROR_NO_MEMORY;
+        poolFinish(&tempPool);
+        handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_NOTATION_PUBLIC_ID:
+      if (!XmlIsPublicId(enc, s, next, eventPP))
+        return XML_ERROR_PUBLICID;
+      if (declNotationName) {  /* means notationDeclHandler != NULL */
+        XML_Char *tem = poolStoreString(&tempPool,
+                                        enc,
+                                        s + enc->minBytesPerChar,
+                                        next - enc->minBytesPerChar);
+        if (!tem)
+          return XML_ERROR_NO_MEMORY;
+        normalizePublicId(tem);
+        declNotationPublicId = tem;
+        poolFinish(&tempPool);
+        handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_NOTATION_SYSTEM_ID:
+      if (declNotationName && notationDeclHandler) {
+        const XML_Char *systemId
+          = poolStoreString(&tempPool, enc,
+                            s + enc->minBytesPerChar,
+                            next - enc->minBytesPerChar);
+        if (!systemId)
+          return XML_ERROR_NO_MEMORY;
+        *eventEndPP = s;
+        notationDeclHandler(handlerArg,
+                            declNotationName,
+                            curBase,
+                            systemId,
+                            declNotationPublicId);
+        handleDefault = XML_FALSE;
+      }
+      poolClear(&tempPool);
+      break;
+    case XML_ROLE_NOTATION_NO_SYSTEM_ID:
+      if (declNotationPublicId && notationDeclHandler) {
+        *eventEndPP = s;
+        notationDeclHandler(handlerArg,
+                            declNotationName,
+                            curBase,
+                            0,
+                            declNotationPublicId);
+        handleDefault = XML_FALSE;
+      }
+      poolClear(&tempPool);
+      break;
+    case XML_ROLE_ERROR:
+      switch (tok) {
+      case XML_TOK_PARAM_ENTITY_REF:
+        /* PE references in internal subset are
+           not allowed within declarations. */
+        return XML_ERROR_PARAM_ENTITY_REF;
+      case XML_TOK_XML_DECL:
+        return XML_ERROR_MISPLACED_XML_PI;
+      default:
+        return XML_ERROR_SYNTAX;
+      }
+#ifdef XML_DTD
+    case XML_ROLE_IGNORE_SECT:
+      {
+        enum XML_Error result;
+        if (defaultHandler)
+          reportDefault(parser, enc, s, next);
+        handleDefault = XML_FALSE;
+        result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore);
+        if (result != XML_ERROR_NONE)
+          return result;
+        else if (!next) {
+          processor = ignoreSectionProcessor;
+          return result;
+        }
+      }
+      break;
+#endif /* XML_DTD */
+    case XML_ROLE_GROUP_OPEN:
+      if (prologState.level >= groupSize) {
+        if (groupSize) {
+          char *temp = (char *)REALLOC(groupConnector, groupSize *= 2);
+          if (temp == NULL)
+            return XML_ERROR_NO_MEMORY;
+          groupConnector = temp;
+          if (dtd->scaffIndex) {
+            int *temp = (int *)REALLOC(dtd->scaffIndex,
+                          groupSize * sizeof(int));
+            if (temp == NULL)
+              return XML_ERROR_NO_MEMORY;
+            dtd->scaffIndex = temp;
+          }
+        }
+        else {
+          groupConnector = (char *)MALLOC(groupSize = 32);
+          if (!groupConnector)
+            return XML_ERROR_NO_MEMORY;
+        }
+      }
+      groupConnector[prologState.level] = 0;
+      if (dtd->in_eldecl) {
+        int myindex = nextScaffoldPart(parser);
+        if (myindex < 0)
+          return XML_ERROR_NO_MEMORY;
+        dtd->scaffIndex[dtd->scaffLevel] = myindex;
+        dtd->scaffLevel++;
+        dtd->scaffold[myindex].type = XML_CTYPE_SEQ;
+        if (elementDeclHandler)
+          handleDefault = XML_FALSE;
+      }
+      break;
+    case XML_ROLE_GROUP_SEQUENCE:
+      if (groupConnector[prologState.level] == ASCII_PIPE)
+        return XML_ERROR_SYNTAX;
+      groupConnector[prologState.level] = ASCII_COMMA;
+      if (dtd->in_eldecl && elementDeclHandler)
+        handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_GROUP_CHOICE:
+      if (groupConnector[prologState.level] == ASCII_COMMA)
+        return XML_ERROR_SYNTAX;
+      if (dtd->in_eldecl
+          && !groupConnector[prologState.level]
+          && (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
+              != XML_CTYPE_MIXED)
+          ) {
+        dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
+            = XML_CTYPE_CHOICE;
+        if (elementDeclHandler)
+          handleDefault = XML_FALSE;
+      }
+      groupConnector[prologState.level] = ASCII_PIPE;
+      break;
+    case XML_ROLE_PARAM_ENTITY_REF:
+#ifdef XML_DTD
+    case XML_ROLE_INNER_PARAM_ENTITY_REF:
+      dtd->hasParamEntityRefs = XML_TRUE;
+      if (!paramEntityParsing)
+        dtd->keepProcessing = dtd->standalone;
+      else {
+        const XML_Char *name;
+        ENTITY *entity;
+        name = poolStoreString(&dtd->pool, enc,
+                                s + enc->minBytesPerChar,
+                                next - enc->minBytesPerChar);
+        if (!name)
+          return XML_ERROR_NO_MEMORY;
+        entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
+        poolDiscard(&dtd->pool);
+        /* first, determine if a check for an existing declaration is needed;
+           if yes, check that the entity exists, and that it is internal,
+           otherwise call the skipped entity handler
+        */
+        if (prologState.documentEntity &&
+            (dtd->standalone
+             ? !openInternalEntities
+             : !dtd->hasParamEntityRefs)) {
+          if (!entity)
+            return XML_ERROR_UNDEFINED_ENTITY;
+          else if (!entity->is_internal)
+            return XML_ERROR_ENTITY_DECLARED_IN_PE;
+        }
+        else if (!entity) {
+          dtd->keepProcessing = dtd->standalone;
+          /* cannot report skipped entities in declarations */
+          if ((role == XML_ROLE_PARAM_ENTITY_REF) && skippedEntityHandler) {
+            skippedEntityHandler(handlerArg, name, 1);
+            handleDefault = XML_FALSE;
+          }
+          break;
+        }
+        if (entity->open)
+          return XML_ERROR_RECURSIVE_ENTITY_REF;
+        if (entity->textPtr) {
+          enum XML_Error result;
+          XML_Bool betweenDecl =
+            (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE);
+          result = processInternalEntity(parser, entity, betweenDecl);
+          if (result != XML_ERROR_NONE)
+            return result;
+          handleDefault = XML_FALSE;
+          break;
+        }
+        if (externalEntityRefHandler) {
+          dtd->paramEntityRead = XML_FALSE;
+          entity->open = XML_TRUE;
+          if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+                                        0,
+                                        entity->base,
+                                        entity->systemId,
+                                        entity->publicId)) {
+            entity->open = XML_FALSE;
+            return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+          }
+          entity->open = XML_FALSE;
+          handleDefault = XML_FALSE;
+          if (!dtd->paramEntityRead) {
+            dtd->keepProcessing = dtd->standalone;
+            break;
+          }
+        }
+        else {
+          dtd->keepProcessing = dtd->standalone;
+          break;
+        }
+      }
+#endif /* XML_DTD */
+      if (!dtd->standalone &&
+          notStandaloneHandler &&
+          !notStandaloneHandler(handlerArg))
+        return XML_ERROR_NOT_STANDALONE;
+      break;
+
+    /* Element declaration stuff */
+
+    case XML_ROLE_ELEMENT_NAME:
+      if (elementDeclHandler) {
+        declElementType = getElementType(parser, enc, s, next);
+        if (!declElementType)
+          return XML_ERROR_NO_MEMORY;
+        dtd->scaffLevel = 0;
+        dtd->scaffCount = 0;
+        dtd->in_eldecl = XML_TRUE;
+        handleDefault = XML_FALSE;
+      }
+      break;
+
+    case XML_ROLE_CONTENT_ANY:
+    case XML_ROLE_CONTENT_EMPTY:
+      if (dtd->in_eldecl) {
+        if (elementDeclHandler) {
+          XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content));
+          if (!content)
+            return XML_ERROR_NO_MEMORY;
+          content->quant = XML_CQUANT_NONE;
+          content->name = NULL;
+          content->numchildren = 0;
+          content->children = NULL;
+          content->type = ((role == XML_ROLE_CONTENT_ANY) ?
+                           XML_CTYPE_ANY :
+                           XML_CTYPE_EMPTY);
+          *eventEndPP = s;
+          elementDeclHandler(handlerArg, declElementType->name, content);
+          handleDefault = XML_FALSE;
+        }
+        dtd->in_eldecl = XML_FALSE;
+      }
+      break;
+
+    case XML_ROLE_CONTENT_PCDATA:
+      if (dtd->in_eldecl) {
+        dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
+            = XML_CTYPE_MIXED;
+        if (elementDeclHandler)
+          handleDefault = XML_FALSE;
+      }
+      break;
+
+    case XML_ROLE_CONTENT_ELEMENT:
+      quant = XML_CQUANT_NONE;
+      goto elementContent;
+    case XML_ROLE_CONTENT_ELEMENT_OPT:
+      quant = XML_CQUANT_OPT;
+      goto elementContent;
+    case XML_ROLE_CONTENT_ELEMENT_REP:
+      quant = XML_CQUANT_REP;
+      goto elementContent;
+    case XML_ROLE_CONTENT_ELEMENT_PLUS:
+      quant = XML_CQUANT_PLUS;
+    elementContent:
+      if (dtd->in_eldecl) {
+        ELEMENT_TYPE *el;
+        const XML_Char *name;
+        int nameLen;
+        const char *nxt = (quant == XML_CQUANT_NONE
+                           ? next
+                           : next - enc->minBytesPerChar);
+        int myindex = nextScaffoldPart(parser);
+        if (myindex < 0)
+          return XML_ERROR_NO_MEMORY;
+        dtd->scaffold[myindex].type = XML_CTYPE_NAME;
+        dtd->scaffold[myindex].quant = quant;
+        el = getElementType(parser, enc, s, nxt);
+        if (!el)
+          return XML_ERROR_NO_MEMORY;
+        name = el->name;
+        dtd->scaffold[myindex].name = name;
+        nameLen = 0;
+        for (; name[nameLen++]; );
+        dtd->contentStringLen +=  nameLen;
+        if (elementDeclHandler)
+          handleDefault = XML_FALSE;
+      }
+      break;
+
+    case XML_ROLE_GROUP_CLOSE:
+      quant = XML_CQUANT_NONE;
+      goto closeGroup;
+    case XML_ROLE_GROUP_CLOSE_OPT:
+      quant = XML_CQUANT_OPT;
+      goto closeGroup;
+    case XML_ROLE_GROUP_CLOSE_REP:
+      quant = XML_CQUANT_REP;
+      goto closeGroup;
+    case XML_ROLE_GROUP_CLOSE_PLUS:
+      quant = XML_CQUANT_PLUS;
+    closeGroup:
+      if (dtd->in_eldecl) {
+        if (elementDeclHandler)
+          handleDefault = XML_FALSE;
+        dtd->scaffLevel--;
+        dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant;
+        if (dtd->scaffLevel == 0) {
+          if (!handleDefault) {
+            XML_Content *model = build_model(parser);
+            if (!model)
+              return XML_ERROR_NO_MEMORY;
+            *eventEndPP = s;
+            elementDeclHandler(handlerArg, declElementType->name, model);
+          }
+          dtd->in_eldecl = XML_FALSE;
+          dtd->contentStringLen = 0;
+        }
+      }
+      break;
+      /* End element declaration stuff */
+
+    case XML_ROLE_PI:
+      if (!reportProcessingInstruction(parser, enc, s, next))
+        return XML_ERROR_NO_MEMORY;
+      handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_COMMENT:
+      if (!reportComment(parser, enc, s, next))
+        return XML_ERROR_NO_MEMORY;
+      handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_NONE:
+      switch (tok) {
+      case XML_TOK_BOM:
+        handleDefault = XML_FALSE;
+        break;
+      }
+      break;
+    case XML_ROLE_DOCTYPE_NONE:
+      if (startDoctypeDeclHandler)
+        handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_ENTITY_NONE:
+      if (dtd->keepProcessing && entityDeclHandler)
+        handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_NOTATION_NONE:
+      if (notationDeclHandler)
+        handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_ATTLIST_NONE:
+      if (dtd->keepProcessing && attlistDeclHandler)
+        handleDefault = XML_FALSE;
+      break;
+    case XML_ROLE_ELEMENT_NONE:
+      if (elementDeclHandler)
+        handleDefault = XML_FALSE;
+      break;
+    } /* end of big switch */
+
+    if (handleDefault && defaultHandler)
+      reportDefault(parser, enc, s, next);
+
+    switch (ps_parsing) {
+    case XML_SUSPENDED:
+      *nextPtr = next;
+      return XML_ERROR_NONE;
+    case XML_FINISHED:
+      return XML_ERROR_ABORTED;
+    default:
+      s = next;
+      tok = XmlPrologTok(enc, s, end, &next);
+    }
+  }
+  /* not reached */
+}
+
+static enum XML_Error PTRCALL
+epilogProcessor(XML_Parser parser,
+                const char *s,
+                const char *end,
+                const char **nextPtr)
+{
+  processor = epilogProcessor;
+  eventPtr = s;
+  for (;;) {
+    const char *next = NULL;
+    int tok = XmlPrologTok(encoding, s, end, &next);
+    eventEndPtr = next;
+    switch (tok) {
+    /* report partial linebreak - it might be the last token */
+    case -XML_TOK_PROLOG_S:
+      if (defaultHandler) {
+        reportDefault(parser, encoding, s, next);
+        if (ps_parsing == XML_FINISHED)
+          return XML_ERROR_ABORTED;
+      }
+      *nextPtr = next;
+      return XML_ERROR_NONE;
+    case XML_TOK_NONE:
+      *nextPtr = s;
+      return XML_ERROR_NONE;
+    case XML_TOK_PROLOG_S:
+      if (defaultHandler)
+        reportDefault(parser, encoding, s, next);
+      break;
+    case XML_TOK_PI:
+      if (!reportProcessingInstruction(parser, encoding, s, next))
+        return XML_ERROR_NO_MEMORY;
+      break;
+    case XML_TOK_COMMENT:
+      if (!reportComment(parser, encoding, s, next))
+        return XML_ERROR_NO_MEMORY;
+      break;
+    case XML_TOK_INVALID:
+      eventPtr = next;
+      return XML_ERROR_INVALID_TOKEN;
+    case XML_TOK_PARTIAL:
+      if (!ps_finalBuffer) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      return XML_ERROR_UNCLOSED_TOKEN;
+    case XML_TOK_PARTIAL_CHAR:
+      if (!ps_finalBuffer) {
+        *nextPtr = s;
+        return XML_ERROR_NONE;
+      }
+      return XML_ERROR_PARTIAL_CHAR;
+    default:
+      return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
+    }
+    eventPtr = s = next;
+    switch (ps_parsing) {
+    case XML_SUSPENDED:
+      *nextPtr = next;
+      return XML_ERROR_NONE;
+    case XML_FINISHED:
+      return XML_ERROR_ABORTED;
+    default: ;
+    }
+  }
+}
+
+static enum XML_Error
+processInternalEntity(XML_Parser parser, ENTITY *entity,
+                      XML_Bool betweenDecl)
+{
+  const char *textStart, *textEnd;
+  const char *next;
+  enum XML_Error result;
+  OPEN_INTERNAL_ENTITY *openEntity;
+
+  if (freeInternalEntities) {
+    openEntity = freeInternalEntities;
+    freeInternalEntities = openEntity->next;
+  }
+  else {
+    openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(sizeof(OPEN_INTERNAL_ENTITY));
+    if (!openEntity)
+      return XML_ERROR_NO_MEMORY;
+  }
+  entity->open = XML_TRUE;
+  entity->processed = 0;
+  openEntity->next = openInternalEntities;
+  openInternalEntities = openEntity;
+  openEntity->entity = entity;
+  openEntity->startTagLevel = tagLevel;
+  openEntity->betweenDecl = betweenDecl;
+  openEntity->internalEventPtr = NULL;
+  openEntity->internalEventEndPtr = NULL;
+  textStart = (char *)entity->textPtr;
+  textEnd = (char *)(entity->textPtr + entity->textLen);
+
+#ifdef XML_DTD
+  if (entity->is_param) {
+    int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
+    result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
+                      next, &next, XML_FALSE);
+  }
+  else
+#endif /* XML_DTD */
+    result = doContent(parser, tagLevel, internalEncoding, textStart,
+                       textEnd, &next, XML_FALSE);
+
+  if (result == XML_ERROR_NONE) {
+    if (textEnd != next && ps_parsing == XML_SUSPENDED) {
+      entity->processed = (int)(next - textStart);
+      processor = internalEntityProcessor;
+    }
+    else {
+      entity->open = XML_FALSE;
+      openInternalEntities = openEntity->next;
+      /* put openEntity back in list of free instances */
+      openEntity->next = freeInternalEntities;
+      freeInternalEntities = openEntity;
+    }
+  }
+  return result;
+}
+
+static enum XML_Error PTRCALL
+internalEntityProcessor(XML_Parser parser,
+                        const char *s,
+                        const char *end,
+                        const char **nextPtr)
+{
+  ENTITY *entity;
+  const char *textStart, *textEnd;
+  const char *next;
+  enum XML_Error result;
+  OPEN_INTERNAL_ENTITY *openEntity = openInternalEntities;
+  if (!openEntity)
+    return XML_ERROR_UNEXPECTED_STATE;
+
+  entity = openEntity->entity;
+  textStart = ((char *)entity->textPtr) + entity->processed;
+  textEnd = (char *)(entity->textPtr + entity->textLen);
+
+#ifdef XML_DTD
+  if (entity->is_param) {
+    int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
+    result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
+                      next, &next, XML_FALSE);
+  }
+  else
+#endif /* XML_DTD */
+    result = doContent(parser, openEntity->startTagLevel, internalEncoding,
+                       textStart, textEnd, &next, XML_FALSE);
+
+  if (result != XML_ERROR_NONE)
+    return result;
+  else if (textEnd != next && ps_parsing == XML_SUSPENDED) {
+    entity->processed = (int)(next - (char *)entity->textPtr);
+    return result;
+  }
+  else {
+    entity->open = XML_FALSE;
+    openInternalEntities = openEntity->next;
+    /* put openEntity back in list of free instances */
+    openEntity->next = freeInternalEntities;
+    freeInternalEntities = openEntity;
+  }
+
+#ifdef XML_DTD
+  if (entity->is_param) {
+    int tok;
+    processor = prologProcessor;
+    tok = XmlPrologTok(encoding, s, end, &next);
+    return doProlog(parser, encoding, s, end, tok, next, nextPtr,
+                    (XML_Bool)!ps_finalBuffer);
+  }
+  else
+#endif /* XML_DTD */
+  {
+    processor = contentProcessor;
+    /* see externalEntityContentProcessor vs contentProcessor */
+    return doContent(parser, parentParser ? 1 : 0, encoding, s, end,
+                     nextPtr, (XML_Bool)!ps_finalBuffer);
+  }
+}
+
+static enum XML_Error PTRCALL
+errorProcessor(XML_Parser parser,
+               const char *s,
+               const char *end,
+               const char **nextPtr)
+{
+  return errorCode;
+}
+
+static enum XML_Error
+storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+                    const char *ptr, const char *end,
+                    STRING_POOL *pool)
+{
+  enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr,
+                                               end, pool);
+  if (result)
+    return result;
+  if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
+    poolChop(pool);
+  if (!poolAppendChar(pool, XML_T('\0')))
+    return XML_ERROR_NO_MEMORY;
+  return XML_ERROR_NONE;
+}
+
+static enum XML_Error
+appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+                     const char *ptr, const char *end,
+                     STRING_POOL *pool)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  for (;;) {
+    const char *next;
+    int tok = XmlAttributeValueTok(enc, ptr, end, &next);
+    switch (tok) {
+    case XML_TOK_NONE:
+      return XML_ERROR_NONE;
+    case XML_TOK_INVALID:
+      if (enc == encoding)
+        eventPtr = next;
+      return XML_ERROR_INVALID_TOKEN;
+    case XML_TOK_PARTIAL:
+      if (enc == encoding)
+        eventPtr = ptr;
+      return XML_ERROR_INVALID_TOKEN;
+    case XML_TOK_CHAR_REF:
+      {
+        XML_Char buf[XML_ENCODE_MAX];
+        int i;
+        int n = XmlCharRefNumber(enc, ptr);
+        if (n < 0) {
+          if (enc == encoding)
+            eventPtr = ptr;
+          return XML_ERROR_BAD_CHAR_REF;
+        }
+        if (!isCdata
+            && n == 0x20 /* space */
+            && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
+          break;
+        n = XmlEncode(n, (ICHAR *)buf);
+        if (!n) {
+          if (enc == encoding)
+            eventPtr = ptr;
+          return XML_ERROR_BAD_CHAR_REF;
+        }
+        for (i = 0; i < n; i++) {
+          if (!poolAppendChar(pool, buf[i]))
+            return XML_ERROR_NO_MEMORY;
+        }
+      }
+      break;
+    case XML_TOK_DATA_CHARS:
+      if (!poolAppend(pool, enc, ptr, next))
+        return XML_ERROR_NO_MEMORY;
+      break;
+    case XML_TOK_TRAILING_CR:
+      next = ptr + enc->minBytesPerChar;
+      /* fall through */
+    case XML_TOK_ATTRIBUTE_VALUE_S:
+    case XML_TOK_DATA_NEWLINE:
+      if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
+        break;
+      if (!poolAppendChar(pool, 0x20))
+        return XML_ERROR_NO_MEMORY;
+      break;
+    case XML_TOK_ENTITY_REF:
+      {
+        const XML_Char *name;
+        ENTITY *entity;
+        char checkEntityDecl;
+        XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc,
+                                              ptr + enc->minBytesPerChar,
+                                              next - enc->minBytesPerChar);
+        if (ch) {
+          if (!poolAppendChar(pool, ch))
+                return XML_ERROR_NO_MEMORY;
+          break;
+        }
+        name = poolStoreString(&temp2Pool, enc,
+                               ptr + enc->minBytesPerChar,
+                               next - enc->minBytesPerChar);
+        if (!name)
+          return XML_ERROR_NO_MEMORY;
+        entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
+        poolDiscard(&temp2Pool);
+        /* First, determine if a check for an existing declaration is needed;
+           if yes, check that the entity exists, and that it is internal.
+        */
+        if (pool == &dtd->pool)  /* are we called from prolog? */
+          checkEntityDecl =
+#ifdef XML_DTD
+              prologState.documentEntity &&
+#endif /* XML_DTD */
+              (dtd->standalone
+               ? !openInternalEntities
+               : !dtd->hasParamEntityRefs);
+        else /* if (pool == &tempPool): we are called from content */
+          checkEntityDecl = !dtd->hasParamEntityRefs || dtd->standalone;
+        if (checkEntityDecl) {
+          if (!entity)
+            return XML_ERROR_UNDEFINED_ENTITY;
+          else if (!entity->is_internal)
+            return XML_ERROR_ENTITY_DECLARED_IN_PE;
+        }
+        else if (!entity) {
+          /* Cannot report skipped entity here - see comments on
+             skippedEntityHandler.
+          if (skippedEntityHandler)
+            skippedEntityHandler(handlerArg, name, 0);
+          */
+          /* Cannot call the default handler because this would be
+             out of sync with the call to the startElementHandler.
+          if ((pool == &tempPool) && defaultHandler)
+            reportDefault(parser, enc, ptr, next);
+          */
+          break;
+        }
+        if (entity->open) {
+          if (enc == encoding)
+            eventPtr = ptr;
+          return XML_ERROR_RECURSIVE_ENTITY_REF;
+        }
+        if (entity->notation) {
+          if (enc == encoding)
+            eventPtr = ptr;
+          return XML_ERROR_BINARY_ENTITY_REF;
+        }
+        if (!entity->textPtr) {
+          if (enc == encoding)
+            eventPtr = ptr;
+          return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
+        }
+        else {
+          enum XML_Error result;
+          const XML_Char *textEnd = entity->textPtr + entity->textLen;
+          entity->open = XML_TRUE;
+          result = appendAttributeValue(parser, internalEncoding, isCdata,
+                                        (char *)entity->textPtr,
+                                        (char *)textEnd, pool);
+          entity->open = XML_FALSE;
+          if (result)
+            return result;
+        }
+      }
+      break;
+    default:
+      if (enc == encoding)
+        eventPtr = ptr;
+      return XML_ERROR_UNEXPECTED_STATE;
+    }
+    ptr = next;
+  }
+  /* not reached */
+}
+
+static enum XML_Error
+storeEntityValue(XML_Parser parser,
+                 const ENCODING *enc,
+                 const char *entityTextPtr,
+                 const char *entityTextEnd)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  STRING_POOL *pool = &(dtd->entityValuePool);
+  enum XML_Error result = XML_ERROR_NONE;
+#ifdef XML_DTD
+  int oldInEntityValue = prologState.inEntityValue;
+  prologState.inEntityValue = 1;
+#endif /* XML_DTD */
+  /* never return Null for the value argument in EntityDeclHandler,
+     since this would indicate an external entity; therefore we
+     have to make sure that entityValuePool.start is not null */
+  if (!pool->blocks) {
+    if (!poolGrow(pool))
+      return XML_ERROR_NO_MEMORY;
+  }
+
+  for (;;) {
+    const char *next;
+    int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
+    switch (tok) {
+    case XML_TOK_PARAM_ENTITY_REF:
+#ifdef XML_DTD
+      if (isParamEntity || enc != encoding) {
+        const XML_Char *name;
+        ENTITY *entity;
+        name = poolStoreString(&tempPool, enc,
+                               entityTextPtr + enc->minBytesPerChar,
+                               next - enc->minBytesPerChar);
+        if (!name) {
+          result = XML_ERROR_NO_MEMORY;
+          goto endEntityValue;
+        }
+        entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
+        poolDiscard(&tempPool);
+        if (!entity) {
+          /* not a well-formedness error - see XML 1.0: WFC Entity Declared */
+          /* cannot report skipped entity here - see comments on
+             skippedEntityHandler
+          if (skippedEntityHandler)
+            skippedEntityHandler(handlerArg, name, 0);
+          */
+          dtd->keepProcessing = dtd->standalone;
+          goto endEntityValue;
+        }
+        if (entity->open) {
+          if (enc == encoding)
+            eventPtr = entityTextPtr;
+          result = XML_ERROR_RECURSIVE_ENTITY_REF;
+          goto endEntityValue;
+        }
+        if (entity->systemId) {
+          if (externalEntityRefHandler) {
+            dtd->paramEntityRead = XML_FALSE;
+            entity->open = XML_TRUE;
+            if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+                                          0,
+                                          entity->base,
+                                          entity->systemId,
+                                          entity->publicId)) {
+              entity->open = XML_FALSE;
+              result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+              goto endEntityValue;
+            }
+            entity->open = XML_FALSE;
+            if (!dtd->paramEntityRead)
+              dtd->keepProcessing = dtd->standalone;
+          }
+          else
+            dtd->keepProcessing = dtd->standalone;
+        }
+        else {
+          entity->open = XML_TRUE;
+          result = storeEntityValue(parser,
+                                    internalEncoding,
+                                    (char *)entity->textPtr,
+                                    (char *)(entity->textPtr
+                                             + entity->textLen));
+          entity->open = XML_FALSE;
+          if (result)
+            goto endEntityValue;
+        }
+        break;
+      }
+#endif /* XML_DTD */
+      /* In the internal subset, PE references are not legal
+         within markup declarations, e.g entity values in this case. */
+      eventPtr = entityTextPtr;
+      result = XML_ERROR_PARAM_ENTITY_REF;
+      goto endEntityValue;
+    case XML_TOK_NONE:
+      result = XML_ERROR_NONE;
+      goto endEntityValue;
+    case XML_TOK_ENTITY_REF:
+    case XML_TOK_DATA_CHARS:
+      if (!poolAppend(pool, enc, entityTextPtr, next)) {
+        result = XML_ERROR_NO_MEMORY;
+        goto endEntityValue;
+      }
+      break;
+    case XML_TOK_TRAILING_CR:
+      next = entityTextPtr + enc->minBytesPerChar;
+      /* fall through */
+    case XML_TOK_DATA_NEWLINE:
+      if (pool->end == pool->ptr && !poolGrow(pool)) {
+              result = XML_ERROR_NO_MEMORY;
+        goto endEntityValue;
+      }
+      *(pool->ptr)++ = 0xA;
+      break;
+    case XML_TOK_CHAR_REF:
+      {
+        XML_Char buf[XML_ENCODE_MAX];
+        int i;
+        int n = XmlCharRefNumber(enc, entityTextPtr);
+        if (n < 0) {
+          if (enc == encoding)
+            eventPtr = entityTextPtr;
+          result = XML_ERROR_BAD_CHAR_REF;
+          goto endEntityValue;
+        }
+        n = XmlEncode(n, (ICHAR *)buf);
+        if (!n) {
+          if (enc == encoding)
+            eventPtr = entityTextPtr;
+          result = XML_ERROR_BAD_CHAR_REF;
+          goto endEntityValue;
+        }
+        for (i = 0; i < n; i++) {
+          if (pool->end == pool->ptr && !poolGrow(pool)) {
+            result = XML_ERROR_NO_MEMORY;
+            goto endEntityValue;
+          }
+          *(pool->ptr)++ = buf[i];
+        }
+      }
+      break;
+    case XML_TOK_PARTIAL:
+      if (enc == encoding)
+        eventPtr = entityTextPtr;
+      result = XML_ERROR_INVALID_TOKEN;
+      goto endEntityValue;
+    case XML_TOK_INVALID:
+      if (enc == encoding)
+        eventPtr = next;
+      result = XML_ERROR_INVALID_TOKEN;
+      goto endEntityValue;
+    default:
+      if (enc == encoding)
+        eventPtr = entityTextPtr;
+      result = XML_ERROR_UNEXPECTED_STATE;
+      goto endEntityValue;
+    }
+    entityTextPtr = next;
+  }
+endEntityValue:
+#ifdef XML_DTD
+  prologState.inEntityValue = oldInEntityValue;
+#endif /* XML_DTD */
+  return result;
+}
+
+static void FASTCALL
+normalizeLines(XML_Char *s)
+{
+  XML_Char *p;
+  for (;; s++) {
+    if (*s == XML_T('\0'))
+      return;
+    if (*s == 0xD)
+      break;
+  }
+  p = s;
+  do {
+    if (*s == 0xD) {
+      *p++ = 0xA;
+      if (*++s == 0xA)
+        s++;
+    }
+    else
+      *p++ = *s++;
+  } while (*s);
+  *p = XML_T('\0');
+}
+
+static int
+reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
+                            const char *start, const char *end)
+{
+  const XML_Char *target;
+  XML_Char *data;
+  const char *tem;
+  if (!processingInstructionHandler) {
+    if (defaultHandler)
+      reportDefault(parser, enc, start, end);
+    return 1;
+  }
+  start += enc->minBytesPerChar * 2;
+  tem = start + XmlNameLength(enc, start);
+  target = poolStoreString(&tempPool, enc, start, tem);
+  if (!target)
+    return 0;
+  poolFinish(&tempPool);
+  data = poolStoreString(&tempPool, enc,
+                        XmlSkipS(enc, tem),
+                        end - enc->minBytesPerChar*2);
+  if (!data)
+    return 0;
+  normalizeLines(data);
+  processingInstructionHandler(handlerArg, target, data);
+  poolClear(&tempPool);
+  return 1;
+}
+
+static int
+reportComment(XML_Parser parser, const ENCODING *enc,
+              const char *start, const char *end)
+{
+  XML_Char *data;
+  if (!commentHandler) {
+    if (defaultHandler)
+      reportDefault(parser, enc, start, end);
+    return 1;
+  }
+  data = poolStoreString(&tempPool,
+                         enc,
+                         start + enc->minBytesPerChar * 4,
+                         end - enc->minBytesPerChar * 3);
+  if (!data)
+    return 0;
+  normalizeLines(data);
+  commentHandler(handlerArg, data);
+  poolClear(&tempPool);
+  return 1;
+}
+
+static void
+reportDefault(XML_Parser parser, const ENCODING *enc,
+              const char *s, const char *end)
+{
+  if (MUST_CONVERT(enc, s)) {
+    const char **eventPP;
+    const char **eventEndPP;
+    if (enc == encoding) {
+      eventPP = &eventPtr;
+      eventEndPP = &eventEndPtr;
+    }
+    else {
+      eventPP = &(openInternalEntities->internalEventPtr);
+      eventEndPP = &(openInternalEntities->internalEventEndPtr);
+    }
+    do {
+      ICHAR *dataPtr = (ICHAR *)dataBuf;
+      XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+      *eventEndPP = s;
+      defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf));
+      *eventPP = s;
+    } while (s != end);
+  }
+  else
+    defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s));
+}
+
+
+static int
+defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
+                XML_Bool isId, const XML_Char *value, XML_Parser parser)
+{
+  DEFAULT_ATTRIBUTE *att;
+  if (value || isId) {
+    /* The handling of default attributes gets messed up if we have
+       a default which duplicates a non-default. */
+    int i;
+    for (i = 0; i < type->nDefaultAtts; i++)
+      if (attId == type->defaultAtts[i].id)
+        return 1;
+    if (isId && !type->idAtt && !attId->xmlns)
+      type->idAtt = attId;
+  }
+  if (type->nDefaultAtts == type->allocDefaultAtts) {
+    if (type->allocDefaultAtts == 0) {
+      type->allocDefaultAtts = 8;
+      type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(type->allocDefaultAtts
+                            * sizeof(DEFAULT_ATTRIBUTE));
+      if (!type->defaultAtts)
+        return 0;
+    }
+    else {
+      DEFAULT_ATTRIBUTE *temp;
+      int count = type->allocDefaultAtts * 2;
+      temp = (DEFAULT_ATTRIBUTE *)
+        REALLOC(type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE)));
+      if (temp == NULL)
+        return 0;
+      type->allocDefaultAtts = count;
+      type->defaultAtts = temp;
+    }
+  }
+  att = type->defaultAtts + type->nDefaultAtts;
+  att->id = attId;
+  att->value = value;
+  att->isCdata = isCdata;
+  if (!isCdata)
+    attId->maybeTokenized = XML_TRUE;
+  type->nDefaultAtts += 1;
+  return 1;
+}
+
+static int
+setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  const XML_Char *name;
+  for (name = elementType->name; *name; name++) {
+    if (*name == XML_T(ASCII_COLON)) {
+      PREFIX *prefix;
+      const XML_Char *s;
+      for (s = elementType->name; s != name; s++) {
+        if (!poolAppendChar(&dtd->pool, *s))
+          return 0;
+      }
+      if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+        return 0;
+      prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
+                                sizeof(PREFIX));
+      if (!prefix)
+        return 0;
+      if (prefix->name == poolStart(&dtd->pool))
+        poolFinish(&dtd->pool);
+      else
+        poolDiscard(&dtd->pool);
+      elementType->prefix = prefix;
+
+    }
+  }
+  return 1;
+}
+
+static ATTRIBUTE_ID *
+getAttributeId(XML_Parser parser, const ENCODING *enc,
+               const char *start, const char *end)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  ATTRIBUTE_ID *id;
+  const XML_Char *name;
+  if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+    return NULL;
+  name = poolStoreString(&dtd->pool, enc, start, end);
+  if (!name)
+    return NULL;
+  /* skip quotation mark - its storage will be re-used (like in name[-1]) */
+  ++name;
+  id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID));
+  if (!id)
+    return NULL;
+  if (id->name != name)
+    poolDiscard(&dtd->pool);
+  else {
+    poolFinish(&dtd->pool);
+    if (!ns)
+      ;
+    else if (name[0] == XML_T(ASCII_x)
+        && name[1] == XML_T(ASCII_m)
+        && name[2] == XML_T(ASCII_l)
+        && name[3] == XML_T(ASCII_n)
+        && name[4] == XML_T(ASCII_s)
+        && (name[5] == XML_T('\0') || name[5] == XML_T(ASCII_COLON))) {
+      if (name[5] == XML_T('\0'))
+        id->prefix = &dtd->defaultPrefix;
+      else
+        id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX));
+      id->xmlns = XML_TRUE;
+    }
+    else {
+      int i;
+      for (i = 0; name[i]; i++) {
+        /* attributes without prefix are *not* in the default namespace */
+        if (name[i] == XML_T(ASCII_COLON)) {
+          int j;
+          for (j = 0; j < i; j++) {
+            if (!poolAppendChar(&dtd->pool, name[j]))
+              return NULL;
+          }
+          if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+            return NULL;
+          id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
+                                        sizeof(PREFIX));
+          if (id->prefix->name == poolStart(&dtd->pool))
+            poolFinish(&dtd->pool);
+          else
+            poolDiscard(&dtd->pool);
+          break;
+        }
+      }
+    }
+  }
+  return id;
+}
+
+#define CONTEXT_SEP XML_T(ASCII_FF)
+
+static const XML_Char *
+getContext(XML_Parser parser)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  HASH_TABLE_ITER iter;
+  XML_Bool needSep = XML_FALSE;
+
+  if (dtd->defaultPrefix.binding) {
+    int i;
+    int len;
+    if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
+      return NULL;
+    len = dtd->defaultPrefix.binding->uriLen;
+    if (namespaceSeparator)
+      len--;
+    for (i = 0; i < len; i++)
+      if (!poolAppendChar(&tempPool, dtd->defaultPrefix.binding->uri[i]))
+        return NULL;
+    needSep = XML_TRUE;
+  }
+
+  hashTableIterInit(&iter, &(dtd->prefixes));
+  for (;;) {
+    int i;
+    int len;
+    const XML_Char *s;
+    PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter);
+    if (!prefix)
+      break;
+    if (!prefix->binding)
+      continue;
+    if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+      return NULL;
+    for (s = prefix->name; *s; s++)
+      if (!poolAppendChar(&tempPool, *s))
+        return NULL;
+    if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
+      return NULL;
+    len = prefix->binding->uriLen;
+    if (namespaceSeparator)
+      len--;
+    for (i = 0; i < len; i++)
+      if (!poolAppendChar(&tempPool, prefix->binding->uri[i]))
+        return NULL;
+    needSep = XML_TRUE;
+  }
+
+
+  hashTableIterInit(&iter, &(dtd->generalEntities));
+  for (;;) {
+    const XML_Char *s;
+    ENTITY *e = (ENTITY *)hashTableIterNext(&iter);
+    if (!e)
+      break;
+    if (!e->open)
+      continue;
+    if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+      return NULL;
+    for (s = e->name; *s; s++)
+      if (!poolAppendChar(&tempPool, *s))
+        return 0;
+    needSep = XML_TRUE;
+  }
+
+  if (!poolAppendChar(&tempPool, XML_T('\0')))
+    return NULL;
+  return tempPool.start;
+}
+
+static XML_Bool
+setContext(XML_Parser parser, const XML_Char *context)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  const XML_Char *s = context;
+
+  while (*context != XML_T('\0')) {
+    if (*s == CONTEXT_SEP || *s == XML_T('\0')) {
+      ENTITY *e;
+      if (!poolAppendChar(&tempPool, XML_T('\0')))
+        return XML_FALSE;
+      e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0);
+      if (e)
+        e->open = XML_TRUE;
+      if (*s != XML_T('\0'))
+        s++;
+      context = s;
+      poolDiscard(&tempPool);
+    }
+    else if (*s == XML_T(ASCII_EQUALS)) {
+      PREFIX *prefix;
+      if (poolLength(&tempPool) == 0)
+        prefix = &dtd->defaultPrefix;
+      else {
+        if (!poolAppendChar(&tempPool, XML_T('\0')))
+          return XML_FALSE;
+        prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool),
+                                  sizeof(PREFIX));
+        if (!prefix)
+          return XML_FALSE;
+        if (prefix->name == poolStart(&tempPool)) {
+          prefix->name = poolCopyString(&dtd->pool, prefix->name);
+          if (!prefix->name)
+            return XML_FALSE;
+        }
+        poolDiscard(&tempPool);
+      }
+      for (context = s + 1;
+           *context != CONTEXT_SEP && *context != XML_T('\0');
+           context++)
+        if (!poolAppendChar(&tempPool, *context))
+          return XML_FALSE;
+      if (!poolAppendChar(&tempPool, XML_T('\0')))
+        return XML_FALSE;
+      if (addBinding(parser, prefix, NULL, poolStart(&tempPool),
+                     &inheritedBindings) != XML_ERROR_NONE)
+        return XML_FALSE;
+      poolDiscard(&tempPool);
+      if (*context != XML_T('\0'))
+        ++context;
+      s = context;
+    }
+    else {
+      if (!poolAppendChar(&tempPool, *s))
+        return XML_FALSE;
+      s++;
+    }
+  }
+  return XML_TRUE;
+}
+
+static void FASTCALL
+normalizePublicId(XML_Char *publicId)
+{
+  XML_Char *p = publicId;
+  XML_Char *s;
+  for (s = publicId; *s; s++) {
+    switch (*s) {
+    case 0x20:
+    case 0xD:
+    case 0xA:
+      if (p != publicId && p[-1] != 0x20)
+        *p++ = 0x20;
+      break;
+    default:
+      *p++ = *s;
+    }
+  }
+  if (p != publicId && p[-1] == 0x20)
+    --p;
+  *p = XML_T('\0');
+}
+
+static DTD *
+dtdCreate(const XML_Memory_Handling_Suite *ms)
+{
+  DTD *p = (DTD *)ms->malloc_fcn(sizeof(DTD));
+  if (p == NULL)
+    return p;
+  poolInit(&(p->pool), ms);
+  poolInit(&(p->entityValuePool), ms);
+  hashTableInit(&(p->generalEntities), ms);
+  hashTableInit(&(p->elementTypes), ms);
+  hashTableInit(&(p->attributeIds), ms);
+  hashTableInit(&(p->prefixes), ms);
+#ifdef XML_DTD
+  p->paramEntityRead = XML_FALSE;
+  hashTableInit(&(p->paramEntities), ms);
+#endif /* XML_DTD */
+  p->defaultPrefix.name = NULL;
+  p->defaultPrefix.binding = NULL;
+
+  p->in_eldecl = XML_FALSE;
+  p->scaffIndex = NULL;
+  p->scaffold = NULL;
+  p->scaffLevel = 0;
+  p->scaffSize = 0;
+  p->scaffCount = 0;
+  p->contentStringLen = 0;
+
+  p->keepProcessing = XML_TRUE;
+  p->hasParamEntityRefs = XML_FALSE;
+  p->standalone = XML_FALSE;
+  return p;
+}
+
+static void
+dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms)
+{
+  HASH_TABLE_ITER iter;
+  hashTableIterInit(&iter, &(p->elementTypes));
+  for (;;) {
+    ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+    if (!e)
+      break;
+    if (e->allocDefaultAtts != 0)
+      ms->free_fcn(e->defaultAtts);
+  }
+  hashTableClear(&(p->generalEntities));
+#ifdef XML_DTD
+  p->paramEntityRead = XML_FALSE;
+  hashTableClear(&(p->paramEntities));
+#endif /* XML_DTD */
+  hashTableClear(&(p->elementTypes));
+  hashTableClear(&(p->attributeIds));
+  hashTableClear(&(p->prefixes));
+  poolClear(&(p->pool));
+  poolClear(&(p->entityValuePool));
+  p->defaultPrefix.name = NULL;
+  p->defaultPrefix.binding = NULL;
+
+  p->in_eldecl = XML_FALSE;
+
+  ms->free_fcn(p->scaffIndex);
+  p->scaffIndex = NULL;
+  ms->free_fcn(p->scaffold);
+  p->scaffold = NULL;
+
+  p->scaffLevel = 0;
+  p->scaffSize = 0;
+  p->scaffCount = 0;
+  p->contentStringLen = 0;
+
+  p->keepProcessing = XML_TRUE;
+  p->hasParamEntityRefs = XML_FALSE;
+  p->standalone = XML_FALSE;
+}
+
+static void
+dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms)
+{
+  HASH_TABLE_ITER iter;
+  hashTableIterInit(&iter, &(p->elementTypes));
+  for (;;) {
+    ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+    if (!e)
+      break;
+    if (e->allocDefaultAtts != 0)
+      ms->free_fcn(e->defaultAtts);
+  }
+  hashTableDestroy(&(p->generalEntities));
+#ifdef XML_DTD
+  hashTableDestroy(&(p->paramEntities));
+#endif /* XML_DTD */
+  hashTableDestroy(&(p->elementTypes));
+  hashTableDestroy(&(p->attributeIds));
+  hashTableDestroy(&(p->prefixes));
+  poolDestroy(&(p->pool));
+  poolDestroy(&(p->entityValuePool));
+  if (isDocEntity) {
+    ms->free_fcn(p->scaffIndex);
+    ms->free_fcn(p->scaffold);
+  }
+  ms->free_fcn(p);
+}
+
+/* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise.
+   The new DTD has already been initialized.
+*/
+static int
+dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
+{
+  HASH_TABLE_ITER iter;
+
+  /* Copy the prefix table. */
+
+  hashTableIterInit(&iter, &(oldDtd->prefixes));
+  for (;;) {
+    const XML_Char *name;
+    const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter);
+    if (!oldP)
+      break;
+    name = poolCopyString(&(newDtd->pool), oldP->name);
+    if (!name)
+      return 0;
+    if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX)))
+      return 0;
+  }
+
+  hashTableIterInit(&iter, &(oldDtd->attributeIds));
+
+  /* Copy the attribute id table. */
+
+  for (;;) {
+    ATTRIBUTE_ID *newA;
+    const XML_Char *name;
+    const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter);
+
+    if (!oldA)
+      break;
+    /* Remember to allocate the scratch byte before the name. */
+    if (!poolAppendChar(&(newDtd->pool), XML_T('\0')))
+      return 0;
+    name = poolCopyString(&(newDtd->pool), oldA->name);
+    if (!name)
+      return 0;
+    ++name;
+    newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name,
+                                  sizeof(ATTRIBUTE_ID));
+    if (!newA)
+      return 0;
+    newA->maybeTokenized = oldA->maybeTokenized;
+    if (oldA->prefix) {
+      newA->xmlns = oldA->xmlns;
+      if (oldA->prefix == &oldDtd->defaultPrefix)
+        newA->prefix = &newDtd->defaultPrefix;
+      else
+        newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
+                                        oldA->prefix->name, 0);
+    }
+  }
+
+  /* Copy the element type table. */
+
+  hashTableIterInit(&iter, &(oldDtd->elementTypes));
+
+  for (;;) {
+    int i;
+    ELEMENT_TYPE *newE;
+    const XML_Char *name;
+    const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+    if (!oldE)
+      break;
+    name = poolCopyString(&(newDtd->pool), oldE->name);
+    if (!name)
+      return 0;
+    newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name,
+                                  sizeof(ELEMENT_TYPE));
+    if (!newE)
+      return 0;
+    if (oldE->nDefaultAtts) {
+      newE->defaultAtts = (DEFAULT_ATTRIBUTE *)
+          ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
+      if (!newE->defaultAtts) {
+        ms->free_fcn(newE);
+        return 0;
+      }
+    }
+    if (oldE->idAtt)
+      newE->idAtt = (ATTRIBUTE_ID *)
+          lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0);
+    newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts;
+    if (oldE->prefix)
+      newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
+                                      oldE->prefix->name, 0);
+    for (i = 0; i < newE->nDefaultAtts; i++) {
+      newE->defaultAtts[i].id = (ATTRIBUTE_ID *)
+          lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
+      newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata;
+      if (oldE->defaultAtts[i].value) {
+        newE->defaultAtts[i].value
+            = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value);
+        if (!newE->defaultAtts[i].value)
+          return 0;
+      }
+      else
+        newE->defaultAtts[i].value = NULL;
+    }
+  }
+
+  /* Copy the entity tables. */
+  if (!copyEntityTable(oldParser,
+                       &(newDtd->generalEntities),
+                       &(newDtd->pool),
+                       &(oldDtd->generalEntities)))
+      return 0;
+
+#ifdef XML_DTD
+  if (!copyEntityTable(oldParser,
+                       &(newDtd->paramEntities),
+                       &(newDtd->pool),
+                       &(oldDtd->paramEntities)))
+      return 0;
+  newDtd->paramEntityRead = oldDtd->paramEntityRead;
+#endif /* XML_DTD */
+
+  newDtd->keepProcessing = oldDtd->keepProcessing;
+  newDtd->hasParamEntityRefs = oldDtd->hasParamEntityRefs;
+  newDtd->standalone = oldDtd->standalone;
+
+  /* Don't want deep copying for scaffolding */
+  newDtd->in_eldecl = oldDtd->in_eldecl;
+  newDtd->scaffold = oldDtd->scaffold;
+  newDtd->contentStringLen = oldDtd->contentStringLen;
+  newDtd->scaffSize = oldDtd->scaffSize;
+  newDtd->scaffLevel = oldDtd->scaffLevel;
+  newDtd->scaffIndex = oldDtd->scaffIndex;
+
+  return 1;
+}  /* End dtdCopy */
+
+static int
+copyEntityTable(XML_Parser oldParser,
+                HASH_TABLE *newTable,
+                STRING_POOL *newPool,
+                const HASH_TABLE *oldTable)
+{
+  HASH_TABLE_ITER iter;
+  const XML_Char *cachedOldBase = NULL;
+  const XML_Char *cachedNewBase = NULL;
+
+  hashTableIterInit(&iter, oldTable);
+
+  for (;;) {
+    ENTITY *newE;
+    const XML_Char *name;
+    const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter);
+    if (!oldE)
+      break;
+    name = poolCopyString(newPool, oldE->name);
+    if (!name)
+      return 0;
+    newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY));
+    if (!newE)
+      return 0;
+    if (oldE->systemId) {
+      const XML_Char *tem = poolCopyString(newPool, oldE->systemId);
+      if (!tem)
+        return 0;
+      newE->systemId = tem;
+      if (oldE->base) {
+        if (oldE->base == cachedOldBase)
+          newE->base = cachedNewBase;
+        else {
+          cachedOldBase = oldE->base;
+          tem = poolCopyString(newPool, cachedOldBase);
+          if (!tem)
+            return 0;
+          cachedNewBase = newE->base = tem;
+        }
+      }
+      if (oldE->publicId) {
+        tem = poolCopyString(newPool, oldE->publicId);
+        if (!tem)
+          return 0;
+        newE->publicId = tem;
+      }
+    }
+    else {
+      const XML_Char *tem = poolCopyStringN(newPool, oldE->textPtr,
+                                            oldE->textLen);
+      if (!tem)
+        return 0;
+      newE->textPtr = tem;
+      newE->textLen = oldE->textLen;
+    }
+    if (oldE->notation) {
+      const XML_Char *tem = poolCopyString(newPool, oldE->notation);
+      if (!tem)
+        return 0;
+      newE->notation = tem;
+    }
+    newE->is_param = oldE->is_param;
+    newE->is_internal = oldE->is_internal;
+  }
+  return 1;
+}
+
+#define INIT_POWER 6
+
+static XML_Bool FASTCALL
+keyeq(KEY s1, KEY s2)
+{
+  for (; *s1 == *s2; s1++, s2++)
+    if (*s1 == 0)
+      return XML_TRUE;
+  return XML_FALSE;
+}
+
+static unsigned long FASTCALL
+hash(XML_Parser parser, KEY s)
+{
+  unsigned long h = hash_secret_salt;
+  while (*s)
+    h = CHAR_HASH(h, *s++);
+  return h;
+}
+
+static NAMED *
+lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize)
+{
+  size_t i;
+  if (table->size == 0) {
+    size_t tsize;
+    if (!createSize)
+      return NULL;
+    table->power = INIT_POWER;
+    /* table->size is a power of 2 */
+    table->size = (size_t)1 << INIT_POWER;
+    tsize = table->size * sizeof(NAMED *);
+    table->v = (NAMED **)table->mem->malloc_fcn(tsize);
+    if (!table->v) {
+      table->size = 0;
+      return NULL;
+    }
+    memset(table->v, 0, tsize);
+    i = hash(parser, name) & ((unsigned long)table->size - 1);
+  }
+  else {
+    unsigned long h = hash(parser, name);
+    unsigned long mask = (unsigned long)table->size - 1;
+    unsigned char step = 0;
+    i = h & mask;
+    while (table->v[i]) {
+      if (keyeq(name, table->v[i]->name))
+        return table->v[i];
+      if (!step)
+        step = PROBE_STEP(h, mask, table->power);
+      i < step ? (i += table->size - step) : (i -= step);
+    }
+    if (!createSize)
+      return NULL;
+
+    /* check for overflow (table is half full) */
+    if (table->used >> (table->power - 1)) {
+      unsigned char newPower = table->power + 1;
+      size_t newSize = (size_t)1 << newPower;
+      unsigned long newMask = (unsigned long)newSize - 1;
+      size_t tsize = newSize * sizeof(NAMED *);
+      NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize);
+      if (!newV)
+        return NULL;
+      memset(newV, 0, tsize);
+      for (i = 0; i < table->size; i++)
+        if (table->v[i]) {
+          unsigned long newHash = hash(parser, table->v[i]->name);
+          size_t j = newHash & newMask;
+          step = 0;
+          while (newV[j]) {
+            if (!step)
+              step = PROBE_STEP(newHash, newMask, newPower);
+            j < step ? (j += newSize - step) : (j -= step);
+          }
+          newV[j] = table->v[i];
+        }
+      table->mem->free_fcn(table->v);
+      table->v = newV;
+      table->power = newPower;
+      table->size = newSize;
+      i = h & newMask;
+      step = 0;
+      while (table->v[i]) {
+        if (!step)
+          step = PROBE_STEP(h, newMask, newPower);
+        i < step ? (i += newSize - step) : (i -= step);
+      }
+    }
+  }
+  table->v[i] = (NAMED *)table->mem->malloc_fcn(createSize);
+  if (!table->v[i])
+    return NULL;
+  memset(table->v[i], 0, createSize);
+  table->v[i]->name = name;
+  (table->used)++;
+  return table->v[i];
+}
+
+static void FASTCALL
+hashTableClear(HASH_TABLE *table)
+{
+  size_t i;
+  for (i = 0; i < table->size; i++) {
+    table->mem->free_fcn(table->v[i]);
+    table->v[i] = NULL;
+  }
+  table->used = 0;
+}
+
+static void FASTCALL
+hashTableDestroy(HASH_TABLE *table)
+{
+  size_t i;
+  for (i = 0; i < table->size; i++)
+    table->mem->free_fcn(table->v[i]);
+  table->mem->free_fcn(table->v);
+}
+
+static void FASTCALL
+hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms)
+{
+  p->power = 0;
+  p->size = 0;
+  p->used = 0;
+  p->v = NULL;
+  p->mem = ms;
+}
+
+static void FASTCALL
+hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table)
+{
+  iter->p = table->v;
+  iter->end = iter->p + table->size;
+}
+
+static NAMED * FASTCALL
+hashTableIterNext(HASH_TABLE_ITER *iter)
+{
+  while (iter->p != iter->end) {
+    NAMED *tem = *(iter->p)++;
+    if (tem)
+      return tem;
+  }
+  return NULL;
+}
+
+static void FASTCALL
+poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms)
+{
+  pool->blocks = NULL;
+  pool->freeBlocks = NULL;
+  pool->start = NULL;
+  pool->ptr = NULL;
+  pool->end = NULL;
+  pool->mem = ms;
+}
+
+static void FASTCALL
+poolClear(STRING_POOL *pool)
+{
+  if (!pool->freeBlocks)
+    pool->freeBlocks = pool->blocks;
+  else {
+    BLOCK *p = pool->blocks;
+    while (p) {
+      BLOCK *tem = p->next;
+      p->next = pool->freeBlocks;
+      pool->freeBlocks = p;
+      p = tem;
+    }
+  }
+  pool->blocks = NULL;
+  pool->start = NULL;
+  pool->ptr = NULL;
+  pool->end = NULL;
+}
+
+static void FASTCALL
+poolDestroy(STRING_POOL *pool)
+{
+  BLOCK *p = pool->blocks;
+  while (p) {
+    BLOCK *tem = p->next;
+    pool->mem->free_fcn(p);
+    p = tem;
+  }
+  p = pool->freeBlocks;
+  while (p) {
+    BLOCK *tem = p->next;
+    pool->mem->free_fcn(p);
+    p = tem;
+  }
+}
+
+static XML_Char *
+poolAppend(STRING_POOL *pool, const ENCODING *enc,
+           const char *ptr, const char *end)
+{
+  if (!pool->ptr && !poolGrow(pool))
+    return NULL;
+  for (;;) {
+    XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end);
+    if (ptr == end)
+      break;
+    if (!poolGrow(pool))
+      return NULL;
+  }
+  return pool->start;
+}
+
+static const XML_Char * FASTCALL
+poolCopyString(STRING_POOL *pool, const XML_Char *s)
+{
+  do {
+    if (!poolAppendChar(pool, *s))
+      return NULL;
+  } while (*s++);
+  s = pool->start;
+  poolFinish(pool);
+  return s;
+}
+
+static const XML_Char *
+poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n)
+{
+  if (!pool->ptr && !poolGrow(pool))
+    return NULL;
+  for (; n > 0; --n, s++) {
+    if (!poolAppendChar(pool, *s))
+      return NULL;
+  }
+  s = pool->start;
+  poolFinish(pool);
+  return s;
+}
+
+static const XML_Char * FASTCALL
+poolAppendString(STRING_POOL *pool, const XML_Char *s)
+{
+  while (*s) {
+    if (!poolAppendChar(pool, *s))
+      return NULL;
+    s++;
+  }
+  return pool->start;
+}
+
+static XML_Char *
+poolStoreString(STRING_POOL *pool, const ENCODING *enc,
+                const char *ptr, const char *end)
+{
+  if (!poolAppend(pool, enc, ptr, end))
+    return NULL;
+  if (pool->ptr == pool->end && !poolGrow(pool))
+    return NULL;
+  *(pool->ptr)++ = 0;
+  return pool->start;
+}
+
+static XML_Bool FASTCALL
+poolGrow(STRING_POOL *pool)
+{
+  if (pool->freeBlocks) {
+    if (pool->start == 0) {
+      pool->blocks = pool->freeBlocks;
+      pool->freeBlocks = pool->freeBlocks->next;
+      pool->blocks->next = NULL;
+      pool->start = pool->blocks->s;
+      pool->end = pool->start + pool->blocks->size;
+      pool->ptr = pool->start;
+      return XML_TRUE;
+    }
+    if (pool->end - pool->start < pool->freeBlocks->size) {
+      BLOCK *tem = pool->freeBlocks->next;
+      pool->freeBlocks->next = pool->blocks;
+      pool->blocks = pool->freeBlocks;
+      pool->freeBlocks = tem;
+      memcpy(pool->blocks->s, pool->start,
+             (pool->end - pool->start) * sizeof(XML_Char));
+      pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
+      pool->start = pool->blocks->s;
+      pool->end = pool->start + pool->blocks->size;
+      return XML_TRUE;
+    }
+  }
+  if (pool->blocks && pool->start == pool->blocks->s) {
+    int blockSize = (int)(pool->end - pool->start)*2;
+    BLOCK *temp = (BLOCK *)
+      pool->mem->realloc_fcn(pool->blocks,
+                             (offsetof(BLOCK, s)
+                              + blockSize * sizeof(XML_Char)));
+    if (temp == NULL)
+      return XML_FALSE;
+    pool->blocks = temp;
+    pool->blocks->size = blockSize;
+    pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
+    pool->start = pool->blocks->s;
+    pool->end = pool->start + blockSize;
+  }
+  else {
+    BLOCK *tem;
+    int blockSize = (int)(pool->end - pool->start);
+    if (blockSize < INIT_BLOCK_SIZE)
+      blockSize = INIT_BLOCK_SIZE;
+    else
+      blockSize *= 2;
+    tem = (BLOCK *)pool->mem->malloc_fcn(offsetof(BLOCK, s)
+                                        + blockSize * sizeof(XML_Char));
+    if (!tem)
+      return XML_FALSE;
+    tem->size = blockSize;
+    tem->next = pool->blocks;
+    pool->blocks = tem;
+    if (pool->ptr != pool->start)
+      memcpy(tem->s, pool->start,
+             (pool->ptr - pool->start) * sizeof(XML_Char));
+    pool->ptr = tem->s + (pool->ptr - pool->start);
+    pool->start = tem->s;
+    pool->end = tem->s + blockSize;
+  }
+  return XML_TRUE;
+}
+
+static int FASTCALL
+nextScaffoldPart(XML_Parser parser)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  CONTENT_SCAFFOLD * me;
+  int next;
+
+  if (!dtd->scaffIndex) {
+    dtd->scaffIndex = (int *)MALLOC(groupSize * sizeof(int));
+    if (!dtd->scaffIndex)
+      return -1;
+    dtd->scaffIndex[0] = 0;
+  }
+
+  if (dtd->scaffCount >= dtd->scaffSize) {
+    CONTENT_SCAFFOLD *temp;
+    if (dtd->scaffold) {
+      temp = (CONTENT_SCAFFOLD *)
+        REALLOC(dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
+      if (temp == NULL)
+        return -1;
+      dtd->scaffSize *= 2;
+    }
+    else {
+      temp = (CONTENT_SCAFFOLD *)MALLOC(INIT_SCAFFOLD_ELEMENTS
+                                        * sizeof(CONTENT_SCAFFOLD));
+      if (temp == NULL)
+        return -1;
+      dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS;
+    }
+    dtd->scaffold = temp;
+  }
+  next = dtd->scaffCount++;
+  me = &dtd->scaffold[next];
+  if (dtd->scaffLevel) {
+    CONTENT_SCAFFOLD *parent = &dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel-1]];
+    if (parent->lastchild) {
+      dtd->scaffold[parent->lastchild].nextsib = next;
+    }
+    if (!parent->childcnt)
+      parent->firstchild = next;
+    parent->lastchild = next;
+    parent->childcnt++;
+  }
+  me->firstchild = me->lastchild = me->childcnt = me->nextsib = 0;
+  return next;
+}
+
+static void
+build_node(XML_Parser parser,
+           int src_node,
+           XML_Content *dest,
+           XML_Content **contpos,
+           XML_Char **strpos)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  dest->type = dtd->scaffold[src_node].type;
+  dest->quant = dtd->scaffold[src_node].quant;
+  if (dest->type == XML_CTYPE_NAME) {
+    const XML_Char *src;
+    dest->name = *strpos;
+    src = dtd->scaffold[src_node].name;
+    for (;;) {
+      *(*strpos)++ = *src;
+      if (!*src)
+        break;
+      src++;
+    }
+    dest->numchildren = 0;
+    dest->children = NULL;
+  }
+  else {
+    unsigned int i;
+    int cn;
+    dest->numchildren = dtd->scaffold[src_node].childcnt;
+    dest->children = *contpos;
+    *contpos += dest->numchildren;
+    for (i = 0, cn = dtd->scaffold[src_node].firstchild;
+         i < dest->numchildren;
+         i++, cn = dtd->scaffold[cn].nextsib) {
+      build_node(parser, cn, &(dest->children[i]), contpos, strpos);
+    }
+    dest->name = NULL;
+  }
+}
+
+static XML_Content *
+build_model (XML_Parser parser)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  XML_Content *ret;
+  XML_Content *cpos;
+  XML_Char * str;
+  int allocsize = (dtd->scaffCount * sizeof(XML_Content)
+                   + (dtd->contentStringLen * sizeof(XML_Char)));
+
+  ret = (XML_Content *)MALLOC(allocsize);
+  if (!ret)
+    return NULL;
+
+  str =  (XML_Char *) (&ret[dtd->scaffCount]);
+  cpos = &ret[1];
+
+  build_node(parser, 0, ret, &cpos, &str);
+  return ret;
+}
+
+static ELEMENT_TYPE *
+getElementType(XML_Parser parser,
+               const ENCODING *enc,
+               const char *ptr,
+               const char *end)
+{
+  DTD * const dtd = _dtd;  /* save one level of indirection */
+  const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end);
+  ELEMENT_TYPE *ret;
+
+  if (!name)
+    return NULL;
+  ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE));
+  if (!ret)
+    return NULL;
+  if (ret->name != name)
+    poolDiscard(&dtd->pool);
+  else {
+    poolFinish(&dtd->pool);
+    if (!setElementTypePrefix(parser, ret))
+      return NULL;
+  }
+  return ret;
+}
diff --git a/third_party/harfbuzz-ng/harfbuzz.gyp b/third_party/harfbuzz-ng/harfbuzz.gyp
index cd58e64..f381e743 100644
--- a/third_party/harfbuzz-ng/harfbuzz.gyp
+++ b/third_party/harfbuzz-ng/harfbuzz.gyp
@@ -7,18 +7,6 @@
     '../../build/win_precompile.gypi',
   ],
   'variables': {
-    'variables': {
-      'conditions': [
-        ['sysroot!=""', {
-          'pkg-config': '<(chroot_cmd) ../../build/linux/pkg-config-wrapper "<(sysroot)" "<(target_arch)" "<(system_libdir)"',
-        }, {
-          'pkg-config': 'pkg-config'
-        }],
-      ],
-    },
-
-    'pkg-config': '<(pkg-config)',
-
     'conditions': [
       ['OS=="linux" and (buildtype!="Official" or chromeos==1) and embedded==0', {
         # Since version 1.31.0, pangoft2 which we depend on pulls in harfbuzz
@@ -30,12 +18,6 @@
       }, {
         'use_system_harfbuzz': 0,
       }],
-      ['OS=="linux" and target_arch=="arm" and chromeos==0', {
-        # Override use_system_harfbuzz for ARM cross compiling so system
-        # harfbuzz is not used because the corresponding package is not
-        # available.
-        'use_system_harfbuzz': 0,
-      }],
     ],
   },
   'conditions': [
diff --git a/third_party/libexif/libexif.gyp b/third_party/libexif/libexif.gyp
index 2d8b242..2ef3c2ba 100644
--- a/third_party/libexif/libexif.gyp
+++ b/third_party/libexif/libexif.gyp
@@ -114,17 +114,6 @@
         },
       ],
     }, { # 'use_system_libexif!=0
-      'conditions': [
-        ['sysroot!=""', {
-          'variables': {
-            'pkg-config': '../../build/linux/pkg-config-wrapper "<(sysroot)" "<(target_arch)" "<(system_libdir)"',
-          },
-        }, {
-          'variables': {
-            'pkg-config': 'pkg-config'
-          },
-        }],
-      ],
       'targets': [
         {
           'target_name': 'libexif',
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium
index 9d975ee0..8998b97 100644
--- a/third_party/libjingle/README.chromium
+++ b/third_party/libjingle/README.chromium
@@ -1,7 +1,7 @@
 Name: libjingle
 URL: http://code.google.com/p/webrtc/
 Version: unknown
-Revision: 9354
+Revision: 9384
 License: BSD
 License File: source/talk/COPYING
 Security Critical: yes
diff --git a/third_party/liblouis/liblouis_nacl.gyp b/third_party/liblouis/liblouis_nacl.gyp
index 478252af..924b5ca 100644
--- a/third_party/liblouis/liblouis_nacl.gyp
+++ b/third_party/liblouis/liblouis_nacl.gyp
@@ -41,8 +41,12 @@
             'build_newlib': 1,
           },
           'compile_flags': [
-            '-Wno-switch',
-            '-Wno-unused-but-set-variable',
+            # Needed for target_arch=mipsel
+            # src/liblouis/compileTranslationTable.c:1414
+            '-Wno-tautological-compare',
+            # Needed for target_arch=mipsel
+            # src/liblouis/logging.c:58
+            '-Wno-non-literal-null-conversion',
           ],
           'include_dirs': [
             'overrides/liblouis',
diff --git a/third_party/mojo/src/mojo/edk/system/raw_channel_win.cc b/third_party/mojo/src/mojo/edk/system/raw_channel_win.cc
index cd9bfdf5..1553b73 100644
--- a/third_party/mojo/src/mojo/edk/system/raw_channel_win.cc
+++ b/third_party/mojo/src/mojo/edk/system/raw_channel_win.cc
@@ -105,7 +105,7 @@
     bool pending_write_no_lock() const;
     base::MessageLoopForIO::IOContext* write_context_no_lock();
     // Instructs the object to wait for an |OnIOCompleted()| notification.
-    void OnPendingWriteStartedNoLock();
+    void OnPendingWriteStartedNoLock(size_t platform_handles_written);
 
     // |base::MessageLoopForIO::IOHandler| implementation:
     // Must be called on the I/O thread. It could be called before or after
@@ -155,6 +155,7 @@
     // object is still attached to the owner, and only on the I/O thread
     // afterwards.
     bool pending_write_;
+    size_t platform_handles_written_;
     base::MessageLoopForIO::IOContext write_context_;
 
     DISALLOW_COPY_AND_ASSIGN(RawChannelIOHandler);
@@ -190,7 +191,8 @@
       owner_(owner),
       suppress_self_destruct_(false),
       pending_read_(false),
-      pending_write_(false) {
+      pending_write_(false),
+      platform_handles_written_(0) {
   memset(&read_context_.overlapped, 0, sizeof(read_context_.overlapped));
   read_context_.handler = this;
   memset(&write_context_.overlapped, 0, sizeof(write_context_.overlapped));
@@ -236,11 +238,13 @@
   return &write_context_;
 }
 
-void RawChannelWin::RawChannelIOHandler::OnPendingWriteStartedNoLock() {
+void RawChannelWin::RawChannelIOHandler::OnPendingWriteStartedNoLock(
+    size_t platform_handles_written) {
   DCHECK(owner_);
   owner_->write_lock().AssertAcquired();
   DCHECK(!pending_write_);
   pending_write_ = true;
+  platform_handles_written_ = platform_handles_written;
 }
 
 void RawChannelWin::RawChannelIOHandler::OnIOCompleted(
@@ -339,7 +343,12 @@
 
   // Note: |OnWriteCompleted()| may detach us from |owner_|.
   if (error == ERROR_SUCCESS) {
-    owner_->OnWriteCompleted(IO_SUCCEEDED, 0, bytes_written);
+    // Reset |platform_handles_written_| before calling |OnWriteCompleted()|
+    // since that function may call back to this class and set it again.
+    size_t local_platform_handles_written_ = platform_handles_written_;
+    platform_handles_written_ = 0;
+    owner_->OnWriteCompleted(IO_SUCCEEDED, local_platform_handles_written_,
+                             bytes_written);
   } else if (error == ERROR_BROKEN_PIPE) {
     owner_->OnWriteCompleted(IO_FAILED_SHUTDOWN, 0, 0);
   } else {
@@ -537,7 +546,7 @@
   // packet. If we do get one for errors, |RawChannelIOHandler::OnIOCompleted()|
   // will crash so we will learn about it.
 
-  io_handler_->OnPendingWriteStartedNoLock();
+  io_handler_->OnPendingWriteStartedNoLock(num_platform_handles);
   return IO_PENDING;
 }
 
@@ -547,7 +556,6 @@
   DCHECK(io_handler_);
   DCHECK(!io_handler_->pending_write_no_lock());
 
-  // TODO(vtl): Do something with |platform_handles_written|.
   size_t platform_handles_written = 0;
   size_t bytes_written = 0;
   IOResult io_result = WriteNoLock(&platform_handles_written, &bytes_written);
@@ -555,7 +563,7 @@
     DCHECK(skip_completion_port_on_success_);
 
     // We have finished writing successfully. Queue a notification manually.
-    io_handler_->OnPendingWriteStartedNoLock();
+    io_handler_->OnPendingWriteStartedNoLock(platform_handles_written);
     // |io_handler_| won't go away before that task is run, so it is safe to use
     // |base::Unretained()|.
     message_loop_for_io()->PostTask(
diff --git a/third_party/usrsctp/BUILD.gn b/third_party/usrsctp/BUILD.gn
index 3e3cabb..7627c95 100644
--- a/third_party/usrsctp/BUILD.gn
+++ b/third_party/usrsctp/BUILD.gn
@@ -116,6 +116,7 @@
       "WINVER=0x0502",
       "_WIN32_WINNT=0x0502",
     ]
+    configs -= [ "//build/config/win:winver" ]
   } else {
     defines += [ "NON_WINDOWS_DEFINE" ]
   }
diff --git a/tools/android/forwarder2/BUILD.gn b/tools/android/forwarder2/BUILD.gn
index 67690d43..fbc9097 100644
--- a/tools/android/forwarder2/BUILD.gn
+++ b/tools/android/forwarder2/BUILD.gn
@@ -53,6 +53,9 @@
   create_native_executable_dist("device_forwarder_prepare_dist") {
     dist_dir = "$root_build_dir/forwarder_dist"
     binary = "$root_build_dir/exe.stripped/device_forwarder"
+    deps = [
+      ":device_forwarder",
+    ]
   }
 }
 
diff --git a/tools/android/md5sum/BUILD.gn b/tools/android/md5sum/BUILD.gn
index 6f80ba6..0f52040 100644
--- a/tools/android/md5sum/BUILD.gn
+++ b/tools/android/md5sum/BUILD.gn
@@ -39,6 +39,9 @@
   create_native_executable_dist("md5sum_prepare_dist") {
     dist_dir = "$root_build_dir/md5sum_dist"
     binary = "$root_build_dir/exe.stripped/md5sum_bin"
+    deps = [
+      ":md5sum_bin",
+    ]
   }
 } else {
   # GYP: //tools/android/md5sum/md5sum.gyp:md5sum_bin_host
diff --git a/tools/checklicenses/checklicenses.py b/tools/checklicenses/checklicenses.py
index 8a5b25b..ab2c98d 100755
--- a/tools/checklicenses/checklicenses.py
+++ b/tools/checklicenses/checklicenses.py
@@ -187,6 +187,9 @@
     'third_party/devscripts': [
         'GPL (v2 or later)',
     ],
+    'third_party/trace-viewer/third_party/devscripts': [
+        'GPL (v2 or later)',
+    ],
     'third_party/expat/files/lib': [  # http://crbug.com/98121
         'UNKNOWN',
     ],
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py b/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py
index 2ba302b..ba9d018 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_benchmark.py
@@ -104,9 +104,9 @@
   tag = 'safebrowsing_on'
   test = measurements.ChromeProxySafebrowsingOn
 
-  # Override CreateUserStorySet so that we can instantiate SafebrowsingPageSet
+  # Override CreateStorySet so that we can instantiate SafebrowsingPageSet
   # with a non default param.
-  def CreateUserStorySet(self, options):
+  def CreateStorySet(self, options):
     del options  # unused
     return pagesets.SafebrowsingPageSet(expect_timeout=True)
 
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/bypass.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/bypass.py
index 360367c..243c346f 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/bypass.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/bypass.py
@@ -10,7 +10,6 @@
 
   def __init__(self, url, page_set):
     super(BypassPage, self).__init__(url=url, page_set=page_set)
-    self.archive_data_file = '../data/chrome_proxy_bypass.json'
 
 
 class BypassPageSet(page_set_module.PageSet):
@@ -18,11 +17,10 @@
   """ Chrome proxy test sites """
 
   def __init__(self):
-    super(BypassPageSet, self).__init__(
-      archive_data_file='../data/chrome_proxy_bypass.json')
+    super(BypassPageSet, self).__init__()
 
     urls_list = [
-      'http://aws1.mdw.la/bypass/',
+      'http://check.googlezip.net/block',
     ]
 
     for url in urls_list:
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/client_type.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/client_type.py
index bcd68b5..7350822 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/client_type.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/client_type.py
@@ -33,7 +33,7 @@
     # of the following pages, since there's no way to get the client type value
     # from a request that was bypassed.
     self.AddUserStory(ClientTypePage(
-        url='http://aws1.mdw.la/fw',
+        url='http://check.googlezip.net/test.html',
         page_set=self,
         bypass_for_client_type='none'))
 
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/corsbypass.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/corsbypass.py
index 4fc42bc..c59ededc 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/corsbypass.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/corsbypass.py
@@ -10,7 +10,6 @@
 
   def __init__(self, url, page_set):
     super(CorsBypassPage, self).__init__(url=url, page_set=page_set)
-    self.archive_data_file = '../data/chrome_proxy_bypass.json'
 
 
 class CorsBypassPageSet(page_set_module.PageSet):
@@ -18,8 +17,7 @@
   """ Chrome proxy test sites """
 
   def __init__(self):
-    super(CorsBypassPageSet, self).__init__(
-      archive_data_file='../data/chrome_proxy_bypass.json')
+    super(CorsBypassPageSet, self).__init__()
 
     urls_list = [
       'http://aws1.mdw.la/test/cors/',
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_bypass.json b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_bypass.json
deleted file mode 100644
index c423c2d..0000000
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_bypass.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.", 
-    "archives": {
-        "chrome_proxy_bypass_000.wpr": [
-            "http://aws1.mdw.la/bypass/", 
-            "http://aws1.mdw.la/piatek/bypass-demo"
-        ]
-    }
-}
\ No newline at end of file
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_bypass_000.wpr.sha1 b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_bypass_000.wpr.sha1
deleted file mode 100644
index b9a9f39..0000000
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_bypass_000.wpr.sha1
+++ /dev/null
@@ -1 +0,0 @@
-ff4418fccf62dd0f9ca0b738917d836964dde801
\ No newline at end of file
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_safebrowsing.json b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_safebrowsing.json
deleted file mode 100644
index 729ff78f..0000000
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_safebrowsing.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.", 
-    "archives": {
-        "chrome_proxy_safebrowsing_000.wpr": [
-            "http://www.ianfette.org/"
-        ]
-    }
-}
\ No newline at end of file
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_safebrowsing_000.wpr.sha1 b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_safebrowsing_000.wpr.sha1
deleted file mode 100644
index b9a9f39..0000000
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_safebrowsing_000.wpr.sha1
+++ /dev/null
@@ -1 +0,0 @@
-ff4418fccf62dd0f9ca0b738917d836964dde801
\ No newline at end of file
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_smoke.json b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_smoke.json
deleted file mode 100644
index 9bd0690..0000000
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_smoke.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.", 
-    "archives": {
-        "chrome_proxy_smoke_000.wpr": [
-            "header validation", 
-            "compression: image", 
-            "bypass", 
-            "compression: javascript", 
-            "compression: css", 
-            "safebrowsing"
-        ]
-    }
-}
\ No newline at end of file
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_smoke_000.wpr.sha1 b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_smoke_000.wpr.sha1
deleted file mode 100644
index b9a9f39..0000000
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_smoke_000.wpr.sha1
+++ /dev/null
@@ -1 +0,0 @@
-ff4418fccf62dd0f9ca0b738917d836964dde801
\ No newline at end of file
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_synthetic.json b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_synthetic.json
deleted file mode 100644
index af3151c..0000000
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_synthetic.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.", 
-    "archives": {
-        "chrome_proxy_synthetic_000.wpr": [
-            "http://aws1.mdw.la/fw", 
-            "http://aws1.mdw.la/static"
-        ]
-    }
-}
\ No newline at end of file
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_synthetic_000.wpr.sha1 b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_synthetic_000.wpr.sha1
deleted file mode 100644
index b9a9f39..0000000
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/data/chrome_proxy_synthetic_000.wpr.sha1
+++ /dev/null
@@ -1 +0,0 @@
-ff4418fccf62dd0f9ca0b738917d836964dde801
\ No newline at end of file
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/http_to_direct_fallback.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/http_to_direct_fallback.py
index e33b287..8a105eb 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/http_to_direct_fallback.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/http_to_direct_fallback.py
@@ -19,7 +19,7 @@
 
     urls_list = [
       'http://check.googlezip.net/fallback',
-      'http://aws1.mdw.la/bypass',
+      'http://check.googlezip.net/block',
     ]
 
     for url in urls_list:
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/lo_fi.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/lo_fi.py
index 431098f..0fd578d 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/lo_fi.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/lo_fi.py
@@ -23,7 +23,7 @@
     super(LoFiPageSet, self).__init__()
 
     urls_list = [
-      'http://aws1.mdw.la/fw/buddy.jpg',
+      'http://check.googlezip.net/image.png',
     ]
 
     for url in urls_list:
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/safebrowsing.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/safebrowsing.py
index 219b65a..9047ae6 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/safebrowsing.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/safebrowsing.py
@@ -17,7 +17,6 @@
 
   def __init__(self, url, page_set, expect_timeout):
     super(SafebrowsingPage, self).__init__(url=url, page_set=page_set)
-    self.archive_data_file = '../data/chrome_proxy_safebrowsing.json'
     self._expect_timeout = expect_timeout
 
   def RunNavigateSteps(self, action_runner):
@@ -35,8 +34,7 @@
   """ Chrome proxy test sites """
 
   def __init__(self, expect_timeout=False):
-    super(SafebrowsingPageSet, self).__init__(
-      archive_data_file='../data/chrome_proxy_safebrowsing.json')
+    super(SafebrowsingPageSet, self).__init__()
 
     self.AddUserStory(
         SafebrowsingPage('http://www.ianfette.org/', self, expect_timeout))
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/smoke.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/smoke.py
index 49de585..2e675919 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/smoke.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/smoke.py
@@ -10,7 +10,6 @@
 
   def __init__(self, url, page_set, name=''):
     super(SmokePage, self).__init__(url=url, page_set=page_set, name=name)
-    self.archive_data_file = '../data/chrome_proxy_smoke.json'
 
 
 class Page1(SmokePage):
@@ -21,7 +20,7 @@
 
   def __init__(self, page_set):
     super(Page1, self).__init__(
-      url='http://aws1.mdw.la/fw/',
+      url='http://check.googlezip.net/test.html',
       page_set=page_set,
       name='header validation')
 
@@ -47,7 +46,7 @@
 
   def __init__(self, page_set):
     super(Page3, self).__init__(
-      url='http://aws1.mdw.la/bypass/',
+      url='http://check.googlezip.net/block',
       page_set=page_set,
       name='bypass')
 
@@ -84,8 +83,7 @@
   """ Chrome proxy test sites """
 
   def __init__(self):
-    super(SmokePageSet, self).__init__(
-      archive_data_file='../data/chrome_proxy_smoke.json')
+    super(SmokePageSet, self).__init__()
 
     self.AddUserStory(Page1(self))
     self.AddUserStory(Page2(self))
diff --git a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/synthetic.py b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/synthetic.py
index e38da89..0b169094 100644
--- a/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/synthetic.py
+++ b/tools/chrome_proxy/integration_tests/chrome_proxy_pagesets/synthetic.py
@@ -10,7 +10,6 @@
 
   def __init__(self, url, page_set):
     super(SyntheticPage, self).__init__(url=url, page_set=page_set)
-    self.archive_data_file = '../data/chrome_proxy_synthetic.json'
 
 
 class SyntheticPageSet(page_set_module.PageSet):
@@ -18,11 +17,10 @@
   """ Chrome proxy synthetic test pages. """
 
   def __init__(self):
-    super(SyntheticPageSet, self).__init__(
-      archive_data_file='../data/chrome_proxy_synthetic.json')
+    super(SyntheticPageSet, self).__init__()
 
     urls_list = [
-      'http://aws1.mdw.la/fw',
+      'http://check.googlezip.net/test.html',
       'http://aws1.mdw.la/static'
     ]
 
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
index f8a7a84..4805bc64 100644
--- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
+++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
@@ -71,6 +71,9 @@
 const char kOwnPtrToGCManagedClassNote[] =
     "[blink-gc] OwnPtr field %0 to a GC managed class declared here:";
 
+const char kMemberToGCUnmanagedClassNote[] =
+    "[blink-gc] Member field %0 to non-GC managed class declared here:";
+
 const char kStackAllocatedFieldNote[] =
     "[blink-gc] Stack-allocated field %0 declared here:";
 
@@ -851,6 +854,7 @@
     kRawPtrToGCManagedWarning,
     kRefPtrToGCManaged,
     kOwnPtrToGCManaged,
+    kMemberToGCUnmanaged,
     kMemberInUnmanaged,
     kPtrFromHeapToStack,
     kGCDerivedPartObject
@@ -909,6 +913,23 @@
       return;
     }
 
+    // If in a stack allocated context, be fairly insistent that T in Member<T>
+    // is GC allocated, as stack allocated objects do not have a trace()
+    // that separately verifies the validity of Member<T>.
+    //
+    // Notice that an error is only reported if T's definition is in scope;
+    // we do not require that it must be brought into scope as that would
+    // prevent declarations of mutually dependent class types.
+    //
+    // (Note: Member<>'s constructor will at run-time verify that the
+    // pointer it wraps is indeed heap allocated.)
+    if (stack_allocated_host_ && Parent() && Parent()->IsMember() &&
+        edge->value()->HasDefinition() && !edge->value()->IsGCAllocated()) {
+      invalid_fields_.push_back(std::make_pair(current_,
+                                               kMemberToGCUnmanaged));
+      return;
+    }
+
     if (!Parent() || !edge->value()->IsGCAllocated())
       return;
 
@@ -1059,6 +1080,8 @@
         DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote);
     diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
         DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote);
+    diag_member_to_gc_unmanaged_class_note_ = diagnostic_.getCustomDiagID(
+        DiagnosticsEngine::Note, kMemberToGCUnmanagedClassNote);
     diag_stack_allocated_field_note_ = diagnostic_.getCustomDiagID(
         DiagnosticsEngine::Note, kStackAllocatedFieldNote);
     diag_member_in_unmanaged_class_note_ = diagnostic_.getCustomDiagID(
@@ -1832,6 +1855,8 @@
         error = diag_ref_ptr_to_gc_managed_class_note_;
       } else if (it->second == CheckFieldsVisitor::kOwnPtrToGCManaged) {
         error = diag_own_ptr_to_gc_managed_class_note_;
+      } else if (it->second == CheckFieldsVisitor::kMemberToGCUnmanaged) {
+        error = diag_member_to_gc_unmanaged_class_note_;
       } else if (it->second == CheckFieldsVisitor::kMemberInUnmanaged) {
         error = diag_member_in_unmanaged_class_note_;
       } else if (it->second == CheckFieldsVisitor::kPtrFromHeapToStack) {
@@ -2108,10 +2133,10 @@
 
   unsigned diag_base_requires_tracing_note_;
   unsigned diag_field_requires_tracing_note_;
-  unsigned diag_field_illegally_traced_note_;
   unsigned diag_raw_ptr_to_gc_managed_class_note_;
   unsigned diag_ref_ptr_to_gc_managed_class_note_;
   unsigned diag_own_ptr_to_gc_managed_class_note_;
+  unsigned diag_member_to_gc_unmanaged_class_note_;
   unsigned diag_stack_allocated_field_note_;
   unsigned diag_member_in_unmanaged_class_note_;
   unsigned diag_part_object_to_gc_derived_class_note_;
diff --git a/tools/clang/blink_gc_plugin/RecordInfo.cpp b/tools/clang/blink_gc_plugin/RecordInfo.cpp
index 6e591a54..37495943 100644
--- a/tools/clang/blink_gc_plugin/RecordInfo.cpp
+++ b/tools/clang/blink_gc_plugin/RecordInfo.cpp
@@ -186,6 +186,10 @@
   return is_eagerly_finalized_;
 }
 
+bool RecordInfo::HasDefinition() {
+  return record_->hasDefinition();
+}
+
 RecordInfo* RecordCache::Lookup(CXXRecordDecl* record) {
   // Ignore classes annotated with the GC_PLUGIN_IGNORE macro.
   if (!record || Config::IsIgnoreAnnotated(record))
diff --git a/tools/clang/blink_gc_plugin/RecordInfo.h b/tools/clang/blink_gc_plugin/RecordInfo.h
index f351db8..e59c0b70 100644
--- a/tools/clang/blink_gc_plugin/RecordInfo.h
+++ b/tools/clang/blink_gc_plugin/RecordInfo.h
@@ -96,6 +96,8 @@
   bool IsGCMixinInstance();
   bool IsEagerlyFinalized();
 
+  bool HasDefinition();
+
   clang::CXXMethodDecl* DeclaresNewOperator();
 
   bool RequiresTraceMethod();
diff --git a/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.cpp b/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.cpp
index 79cbce77..b6bbfd2 100644
--- a/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.cpp
+++ b/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.cpp
@@ -9,8 +9,10 @@
 HeapObject::~HeapObject()
 {
     // Valid access to fields.
-    if (m_ref->foo() && !m_obj)
+    if (m_ref->foo() && !m_obj) {
         m_objs.size();
+        m_part.obj();
+    }
 
     // Invalid access to fields.
     bar(m_obj);
@@ -22,6 +24,12 @@
 {
     visitor->trace(m_obj);
     visitor->trace(m_objs);
+    visitor->trace(m_part);
+}
+
+void PartOther::trace(Visitor* visitor)
+{
+    visitor->trace(m_obj);
 }
 
 }
diff --git a/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.h b/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.h
index 232eb082..4c72156 100644
--- a/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.h
+++ b/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.h
@@ -14,6 +14,19 @@
     bool foo() { return true; }
 };
 
+class HeapObject;
+
+class PartOther {
+    ALLOW_ONLY_INLINE_ALLOCATION();
+public:
+    void trace(Visitor*);
+
+    HeapObject* obj() { return m_obj; }
+
+private:
+    Member<HeapObject> m_obj;
+};
+
 class HeapObject : public GarbageCollectedFinalized<HeapObject> {
 public:
     ~HeapObject();
@@ -24,6 +37,7 @@
     RefPtr<Other> m_ref;
     Member<HeapObject> m_obj;
     Vector<Member<HeapObject> > m_objs;
+    PartOther m_part;
 };
 
 }
diff --git a/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.txt b/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.txt
index 0746b01..0470b51 100644
--- a/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.txt
+++ b/tools/clang/blink_gc_plugin/tests/destructor_access_finalized_field.txt
@@ -1,19 +1,19 @@
-destructor_access_finalized_field.cpp:16:9: warning: [blink-gc] Finalizer '~HeapObject' accesses potentially finalized field 'm_obj'.
+destructor_access_finalized_field.cpp:18:9: warning: [blink-gc] Finalizer '~HeapObject' accesses potentially finalized field 'm_obj'.
     bar(m_obj);
         ^
-./destructor_access_finalized_field.h:25:5: note: [blink-gc] Potentially finalized field 'm_obj' declared here:
+./destructor_access_finalized_field.h:38:5: note: [blink-gc] Potentially finalized field 'm_obj' declared here:
     Member<HeapObject> m_obj;
     ^
-destructor_access_finalized_field.cpp:17:5: warning: [blink-gc] Finalizer '~HeapObject' accesses potentially finalized field 'm_obj'.
+destructor_access_finalized_field.cpp:19:5: warning: [blink-gc] Finalizer '~HeapObject' accesses potentially finalized field 'm_obj'.
     m_obj->foo();
     ^
-./destructor_access_finalized_field.h:25:5: note: [blink-gc] Potentially finalized field 'm_obj' declared here:
+./destructor_access_finalized_field.h:38:5: note: [blink-gc] Potentially finalized field 'm_obj' declared here:
     Member<HeapObject> m_obj;
     ^
-destructor_access_finalized_field.cpp:18:5: warning: [blink-gc] Finalizer '~HeapObject' accesses potentially finalized field 'm_objs'.
+destructor_access_finalized_field.cpp:20:5: warning: [blink-gc] Finalizer '~HeapObject' accesses potentially finalized field 'm_objs'.
     m_objs[0];
     ^
-./destructor_access_finalized_field.h:26:5: note: [blink-gc] Potentially finalized field 'm_objs' declared here:
+./destructor_access_finalized_field.h:39:5: note: [blink-gc] Potentially finalized field 'm_objs' declared here:
     Vector<Member<HeapObject> > m_objs;
     ^
 3 warnings generated.
diff --git a/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.h b/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.h
index 0dcacc55..5a59c7e 100644
--- a/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.h
+++ b/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.h
@@ -23,6 +23,8 @@
     STACK_ALLOCATED();
 private:
     Member<HeapObject> m_obj; // OK
+    Member<OffHeapObject> m_memberOff; // NOT OK
+    HeapVector<Member<OffHeapObject>> m_heapVectorMemberOff; // NOT OK
 };
 
 class PartObject {
diff --git a/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.txt b/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.txt
index 6aada91..9d5f2388 100644
--- a/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.txt
+++ b/tools/clang/blink_gc_plugin/tests/member_in_offheap_class.txt
@@ -5,4 +5,13 @@
 ./member_in_offheap_class.h:18:5: note: [blink-gc] Member field 'm_obj' in unmanaged class declared here:
     Member<HeapObject> m_obj; // Must not contain Member.
     ^
-1 warning generated.
+./member_in_offheap_class.h:22:1: warning: [blink-gc] Class 'StackObject' contains invalid fields.
+class StackObject {
+^
+./member_in_offheap_class.h:26:5: note: [blink-gc] Member field 'm_memberOff' to non-GC managed class declared here:
+    Member<OffHeapObject> m_memberOff; // NOT OK
+    ^
+./member_in_offheap_class.h:27:5: note: [blink-gc] Member field 'm_heapVectorMemberOff' to non-GC managed class declared here:
+    HeapVector<Member<OffHeapObject>> m_heapVectorMemberOff; // NOT OK
+    ^
+2 warnings generated.
diff --git a/tools/cr/cr/actions/gn.py b/tools/cr/cr/actions/gn.py
index a79aa81f..fcd40c7 100644
--- a/tools/cr/cr/actions/gn.py
+++ b/tools/cr/cr/actions/gn.py
@@ -78,6 +78,11 @@
     for key, value in args.items():
       arg_lines.append('%s = %s' % (key, value))
 
+    try:
+      os.makedirs(out_path)
+    except OSError:
+      if not os.path.isdir(out_path):
+        raise
     with open(args_file, 'w') as f:
       f.write('\n'.join(arg_lines) + '\n')
 
diff --git a/tools/gn/action_values.cc b/tools/gn/action_values.cc
index 2215167..ede8020 100644
--- a/tools/gn/action_values.cc
+++ b/tools/gn/action_values.cc
@@ -4,6 +4,7 @@
 
 #include "tools/gn/action_values.h"
 
+#include "tools/gn/settings.h"
 #include "tools/gn/substitution_writer.h"
 #include "tools/gn/target.h"
 
diff --git a/tools/gn/build_settings.cc b/tools/gn/build_settings.cc
index 3ffb8283..63ff3584 100644
--- a/tools/gn/build_settings.cc
+++ b/tools/gn/build_settings.cc
@@ -7,7 +7,8 @@
 #include "base/files/file_util.h"
 #include "tools/gn/filesystem_utils.h"
 
-BuildSettings::BuildSettings() {
+BuildSettings::BuildSettings()
+    : check_for_bad_items_(true) {
 }
 
 BuildSettings::BuildSettings(const BuildSettings& other)
@@ -17,7 +18,8 @@
       python_path_(other.python_path_),
       build_config_file_(other.build_config_file_),
       build_dir_(other.build_dir_),
-      build_args_(other.build_args_) {
+      build_args_(other.build_args_),
+      check_for_bad_items_(true) {
 }
 
 BuildSettings::~BuildSettings() {
diff --git a/tools/gn/build_settings.h b/tools/gn/build_settings.h
index a9752f1..f64d5b7 100644
--- a/tools/gn/build_settings.h
+++ b/tools/gn/build_settings.h
@@ -94,6 +94,18 @@
     exec_script_whitelist_ = list.Pass();
   }
 
+  // When set (the default), code should perform normal validation of inputs
+  // and structures, like undefined or possibly incorrectly used things. For
+  // some interrogation commands, we don't care about this and actually want
+  // to allow the user to check the structure of the build to solve their
+  // problem, and these checks are undesirable.
+  bool check_for_bad_items() const {
+    return check_for_bad_items_;
+  }
+  void set_check_for_bad_items(bool c) {
+    check_for_bad_items_ = c;
+  }
+
  private:
   base::FilePath root_path_;
   std::string root_path_utf8_;
@@ -109,6 +121,8 @@
 
   scoped_ptr<std::set<SourceFile>> exec_script_whitelist_;
 
+  bool check_for_bad_items_;
+
   BuildSettings& operator=(const BuildSettings& other);  // Disallow.
 };
 
diff --git a/tools/gn/command_args.cc b/tools/gn/command_args.cc
index 7210ef3..c4c16bb 100644
--- a/tools/gn/command_args.cc
+++ b/tools/gn/command_args.cc
@@ -114,7 +114,7 @@
 
 int ListArgs(const std::string& build_dir) {
   Setup* setup = new Setup;
-  setup->set_check_for_bad_items(false);
+  setup->build_settings().set_check_for_bad_items(false);
   if (!setup->DoSetup(build_dir, false) || !setup->Run())
     return 1;
 
@@ -227,7 +227,7 @@
     // Scope the setup. We only use it for some basic state. We'll do the
     // "real" build below in the gen command.
     Setup setup;
-    setup.set_check_for_bad_items(false);
+    setup.build_settings().set_check_for_bad_items(false);
     // Don't fill build arguments. We're about to edit the file which supplies
     // these in the first place.
     setup.set_fill_arguments(false);
diff --git a/tools/gn/command_desc.cc b/tools/gn/command_desc.cc
index efb0b06..48fa31ab 100644
--- a/tools/gn/command_desc.cc
+++ b/tools/gn/command_desc.cc
@@ -617,6 +617,7 @@
 
   // Deliberately leaked to avoid expensive process teardown.
   Setup* setup = new Setup;
+  setup->build_settings().set_check_for_bad_items(false);
   if (!setup->DoSetup(args[0], false))
     return 1;
   if (!setup->Run())
diff --git a/tools/gn/command_gen.cc b/tools/gn/command_gen.cc
index 76f1f36f..eceb8df 100644
--- a/tools/gn/command_gen.cc
+++ b/tools/gn/command_gen.cc
@@ -6,6 +6,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "base/timer/elapsed_timer.h"
 #include "tools/gn/build_settings.h"
 #include "tools/gn/commands.h"
@@ -44,6 +45,89 @@
   }
 }
 
+// Returns a pointer to the target with the given file as an output, or null
+// if no targets generate the file. This is brute force since this is an
+// error condition and performance shouldn't matter.
+const Target* FindTargetThatGeneratesFile(const Builder* builder,
+                                          const SourceFile& file) {
+  std::vector<const Target*> targets = builder->GetAllResolvedTargets();
+  if (targets.empty())
+    return nullptr;
+
+  OutputFile output_file(targets[0]->settings()->build_settings(), file);
+  for (const Target* target : targets) {
+    for (const auto& cur_output : target->computed_outputs()) {
+      if (cur_output == output_file)
+        return target;
+    }
+  }
+  return nullptr;
+}
+
+// Prints an error that the given file was present as a source or input in
+// the given target(s) but was not generated by any of its dependencies.
+void PrintInvalidGeneratedInput(const Builder* builder,
+                                const SourceFile& file,
+                                const std::vector<const Target*>& targets) {
+  std::string err;
+
+  const std::string target_str = targets.size() > 1 ? "targets" : "target";
+  err += "The file:\n";
+  err += "  " + file.value() + "\n";
+  err += "is listed as an input or source for the " + target_str + ":\n";
+  for (const Target* target : targets)
+    err += "  " + target->label().GetUserVisibleName(false) + "\n";
+
+  const Target* generator = FindTargetThatGeneratesFile(builder, file);
+  if (generator) {
+    err += "but this file was not generated by any dependencies of the " +
+        target_str + ". The target\nthat generates the file is:\n  ";
+    err += generator->label().GetUserVisibleName(false);
+  } else {
+    err += "but no targets in the build generate that file.";
+  }
+
+  Err(Location(), "Input to " + target_str + " not generated by a dependency.",
+      err).PrintToStdout();
+}
+
+bool CheckForInvalidGeneratedInputs(Setup* setup) {
+  std::multimap<SourceFile, const Target*> unknown_inputs =
+      g_scheduler->GetUnknownGeneratedInputs();
+  if (unknown_inputs.empty())
+    return true;  // No bad files.
+
+  int errors_found = 0;
+  auto cur = unknown_inputs.begin();
+  while (cur != unknown_inputs.end()) {
+    errors_found++;
+    auto end_of_range = unknown_inputs.upper_bound(cur->first);
+
+    // Package the values more conveniently for printing.
+    SourceFile bad_input = cur->first;
+    std::vector<const Target*> targets;
+    while (cur != end_of_range)
+      targets.push_back((cur++)->second);
+
+    PrintInvalidGeneratedInput(setup->builder(), bad_input, targets);
+    OutputString("\n");
+  }
+
+  OutputString(
+      "If you have generated inputs, there needs to be a dependency path "
+      "between the\ntwo targets in addition to just listing the files. For "
+      "indirect dependencies,\nthe intermediate ones must be public_deps. "
+      "data_deps don't count since they're\nonly runtime dependencies. If "
+      "you think a dependency chain exists, it might be\nbecause the chain "
+      "is private. Try \"gn path\" to analyze.\n");
+
+  if (errors_found > 1) {
+    OutputString(base::StringPrintf("\n%d generated input errors found.\n",
+                                    errors_found), DECORATION_YELLOW);
+  }
+  return false;
+}
+
 }  // namespace
 
 const char kGen[] = "gen";
@@ -107,6 +191,9 @@
     return 1;
   }
 
+  if (!CheckForInvalidGeneratedInputs(setup))
+    return 1;
+
   base::TimeDelta elapsed_time = timer.Elapsed();
 
   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kQuiet)) {
diff --git a/tools/gn/command_ls.cc b/tools/gn/command_ls.cc
index ed4aaca..eddb51c3 100644
--- a/tools/gn/command_ls.cc
+++ b/tools/gn/command_ls.cc
@@ -76,6 +76,7 @@
   }
 
   Setup* setup = new Setup;
+  setup->build_settings().set_check_for_bad_items(false);
   if (!setup->DoSetup(args[0], false) || !setup->Run())
     return 1;
 
diff --git a/tools/gn/command_refs.cc b/tools/gn/command_refs.cc
index 9c89114..a97e9a7 100644
--- a/tools/gn/command_refs.cc
+++ b/tools/gn/command_refs.cc
@@ -141,6 +141,13 @@
     if (cur_file == file.value())
       return true;
   }
+
+  std::vector<SourceFile> outputs;
+  target->action_values().GetOutputsAsSourceFiles(target, &outputs);
+  for (const auto& cur_file : outputs) {
+    if (cur_file == file)
+      return true;
+  }
   return false;
 }
 
@@ -286,9 +293,9 @@
     "     \"gn help label_pattern\" for details.\n"
     "\n"
     "   - File name: The result will be which targets list the given file in\n"
-    "     its \"inputs\", \"sources\", \"public\", or \"data\". Any input\n"
-    "     that does not contain wildcards and does not match a target or a\n"
-    "     config will be treated as a file.\n"
+    "     its \"inputs\", \"sources\", \"public\", \"data\", or \"outputs\".\n"
+    "     Any input that does not contain wildcards and does not match a\n"
+    "     target or a config will be treated as a file.\n"
     "\n"
     "   - Response file: If the input starts with an \"@\", it will be\n"
     "     interpreted as a path to a file containing a list of labels or\n"
@@ -391,7 +398,7 @@
   bool all_toolchains = cmdline->HasSwitch("all-toolchains");
 
   Setup* setup = new Setup;
-  setup->set_check_for_bad_items(false);
+  setup->build_settings().set_check_for_bad_items(false);
   if (!setup->DoSetup(args[0], false) || !setup->Run())
     return 1;
 
diff --git a/tools/gn/filesystem_utils.cc b/tools/gn/filesystem_utils.cc
index 7495b05c..325cfc6 100644
--- a/tools/gn/filesystem_utils.cc
+++ b/tools/gn/filesystem_utils.cc
@@ -310,14 +310,18 @@
   return base::StringPiece(&dir_string[0], end);
 }
 
-bool EnsureStringIsInOutputDir(const SourceDir& dir,
+bool IsStringInOutputDir(const SourceDir& output_dir, const std::string& str) {
+  // This check will be wrong for all proper prefixes "e.g. "/output" will
+  // match "/out" but we don't really care since this is just a sanity check.
+  const std::string& dir_str = output_dir.value();
+  return str.compare(0, dir_str.length(), dir_str) == 0;
+}
+
+bool EnsureStringIsInOutputDir(const SourceDir& output_dir,
                                const std::string& str,
                                const ParseNode* origin,
                                Err* err) {
-  // This check will be wrong for all proper prefixes "e.g. "/output" will
-  // match "/out" but we don't really care since this is just a sanity check.
-  const std::string& dir_str = dir.value();
-  if (str.compare(0, dir_str.length(), dir_str) == 0)
+  if (IsStringInOutputDir(output_dir, str))
     return true;  // Output directory is hardcoded.
 
   *err = Err(origin, "File is not inside output directory.",
diff --git a/tools/gn/filesystem_utils.h b/tools/gn/filesystem_utils.h
index 52352c6..4f258e1 100644
--- a/tools/gn/filesystem_utils.h
+++ b/tools/gn/filesystem_utils.h
@@ -82,16 +82,20 @@
 // empty substring if none. For example "//foo/bar/" -> "bar".
 base::StringPiece FindLastDirComponent(const SourceDir& dir);
 
+// Returns true if the given string is in the given output dir. This is pretty
+// stupid and doesn't handle "." and "..", etc., it is designed for a sanity
+// check to keep people from writing output files to the source directory
+// accidentally.
+bool IsStringInOutputDir(const SourceDir& output_dir, const std::string& str);
+
 // Verifies that the given string references a file inside of the given
-// directory. This is pretty stupid and doesn't handle "." and "..", etc.,
-// it is designed for a sanity check to keep people from writing output files
-// to the source directory accidentally.
+// directory. This just uses IsStringInOutputDir above.
 //
 // The origin will be blamed in the error.
 //
 // If the file isn't in the dir, returns false and sets the error. Otherwise
 // returns true and leaves the error untouched.
-bool EnsureStringIsInOutputDir(const SourceDir& dir,
+bool EnsureStringIsInOutputDir(const SourceDir& output_dir,
                                const std::string& str,
                                const ParseNode* origin,
                                Err* err);
diff --git a/tools/gn/function_write_file.cc b/tools/gn/function_write_file.cc
index 8a6fee3..45387a3 100644
--- a/tools/gn/function_write_file.cc
+++ b/tools/gn/function_write_file.cc
@@ -21,14 +21,18 @@
 namespace {
 
 // On Windows, provide a custom implementation of base::WriteFile. Sometimes
-// the base version would fail, and this alternate implementation provides
-// additional logging. See http://crbug.com/468437
+// the base version fails, especially on the bots. The guess is that Windows
+// Defender or other antivirus programs still have the file open (after
+// checking for the read) when the write happens immediately after. This
+// version opens with FILE_SHARE_READ (normally not what you want when
+// replacing the entire contents of the file) which lets us continue even if
+// another program has the file open for reading. See http://crbug.com/468437
 #if defined(OS_WIN)
 int DoWriteFile(const base::FilePath& filename, const char* data, int size) {
   base::win::ScopedHandle file(::CreateFile(
       filename.value().c_str(),
       GENERIC_WRITE,
-      FILE_SHARE_READ,  // Not present in the base version, speculative fix.
+      FILE_SHARE_READ,
       NULL,
       CREATE_ALWAYS,
       0,
@@ -109,6 +113,7 @@
           scope->settings()->build_settings()->build_dir(),
           source_file.value(), args[0].origin(), err))
     return Value();
+  g_scheduler->AddWrittenFile(source_file);  // Track that we wrote this file.
 
   // Compute output.
   std::ostringstream contents;
diff --git a/tools/gn/function_write_file_unittest.cc b/tools/gn/function_write_file_unittest.cc
index 90bfa4c..8212e9919 100644
--- a/tools/gn/function_write_file_unittest.cc
+++ b/tools/gn/function_write_file_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "tools/gn/functions.h"
+#include "tools/gn/scheduler.h"
 #include "tools/gn/test_with_scope.h"
 
 namespace {
@@ -31,6 +32,7 @@
 }  // namespace
 
 TEST(WriteFile, WithData) {
+  Scheduler scheduler;
   TestWithScope setup;
 
   // Make a real directory for writing the files.
diff --git a/tools/gn/scheduler.cc b/tools/gn/scheduler.cc
index 488149b..622019e 100644
--- a/tools/gn/scheduler.cc
+++ b/tools/gn/scheduler.cc
@@ -108,6 +108,39 @@
   return gen_dependencies_;
 }
 
+void Scheduler::AddWrittenFile(const SourceFile& file) {
+  base::AutoLock lock(lock_);
+  written_files_.push_back(file);
+}
+
+void Scheduler::AddUnknownGeneratedInput(const Target* target,
+                                         const SourceFile& file) {
+  base::AutoLock lock(lock_);
+  unknown_generated_inputs_.insert(std::make_pair(file, target));
+}
+
+std::multimap<SourceFile, const Target*>
+    Scheduler::GetUnknownGeneratedInputs() const {
+  base::AutoLock lock(lock_);
+
+  // Remove all unknown inputs that were written files. These are OK as inputs
+  // to build steps since they were written as a side-effect of running GN.
+  //
+  // It's assumed that this function is called once during cleanup to check for
+  // errors, so performing this work in the lock doesn't matter.
+  std::multimap<SourceFile, const Target*> filtered = unknown_generated_inputs_;
+  for (const SourceFile& file : written_files_)
+    filtered.erase(file);
+
+  return filtered;
+}
+
+void Scheduler::ClearUnknownGeneratedInputsAndWrittenFiles() {
+  base::AutoLock lock(lock_);
+  unknown_generated_inputs_.clear();
+  written_files_.clear();
+}
+
 void Scheduler::IncrementWorkCount() {
   base::AtomicRefCountInc(&work_count_);
 }
diff --git a/tools/gn/scheduler.h b/tools/gn/scheduler.h
index 912ca7e..4375f63 100644
--- a/tools/gn/scheduler.h
+++ b/tools/gn/scheduler.h
@@ -5,6 +5,8 @@
 #ifndef TOOLS_GN_SCHEDULER_H_
 #define TOOLS_GN_SCHEDULER_H_
 
+#include <map>
+
 #include "base/atomic_ref_count.h"
 #include "base/basictypes.h"
 #include "base/files/file_path.h"
@@ -47,9 +49,33 @@
   // TODO(brettw) this is global rather than per-BuildSettings. If we
   // start using >1 build settings, then we probably want this to take a
   // BuildSettings object so we know the depdency on a per-build basis.
+  // If moved, most of the Add/Get functions below should move as well.
   void AddGenDependency(const base::FilePath& file);
   std::vector<base::FilePath> GetGenDependencies() const;
 
+  // Tracks calls to write_file for resolving with the unknown generated
+  // inputs (see AddUnknownGeneratedInput below).
+  void AddWrittenFile(const SourceFile& file);
+
+  // Unknown generated inputs are files that a target declares as an input
+  // in the output directory, but which aren't generated by any dependency.
+  //
+  // Some of these files will be files written by write_file and will be
+  // GenDependencies (see AddWrittenFile above). There are OK and include
+  // things like response files for scripts. Others cases will be ones where
+  // the file is generated by a target that's not a dependency.
+  //
+  // In order to distinguish these two cases, the checking for these input
+  // files needs to be done after all targets are complete. This also has the
+  // nice side effect that if a target generates the file we can find it and
+  // tell the user which dependency is missing.
+  //
+  // The result returned by GetUnknownGeneratedInputs will not count any files
+  // that were written by write_file during execution.
+  void AddUnknownGeneratedInput(const Target* target, const SourceFile& file);
+  std::multimap<SourceFile, const Target*> GetUnknownGeneratedInputs() const;
+  void ClearUnknownGeneratedInputsAndWrittenFiles();  // For testing.
+
   // We maintain a count of the things we need to do that works like a
   // refcount. When this reaches 0, the program exits.
   void IncrementWorkCount();
@@ -84,8 +110,10 @@
   // loop.
   bool has_been_shutdown_;
 
-  // Additional input dependencies. Protected by the lock.
+  // Protected by the lock. See the corresponding Add/Get functions above.
   std::vector<base::FilePath> gen_dependencies_;
+  std::vector<SourceFile> written_files_;
+  std::multimap<SourceFile, const Target*> unknown_generated_inputs_;
 
   DISALLOW_COPY_AND_ASSIGN(Scheduler);
 };
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc
index 79c46e79..aa8e8f0b 100644
--- a/tools/gn/setup.cc
+++ b/tools/gn/setup.cc
@@ -157,8 +157,6 @@
       loader_(new LoaderImpl(&build_settings_)),
       builder_(new Builder(loader_.get())),
       root_build_file_("//BUILD.gn"),
-      check_for_bad_items_(true),
-      check_for_unused_overrides_(true),
       check_public_headers_(false),
       dotfile_settings_(&build_settings_, std::string()),
       dotfile_scope_(&dotfile_settings_),
@@ -234,14 +232,12 @@
 
 bool Setup::RunPostMessageLoop() {
   Err err;
-  if (check_for_bad_items_) {
+  if (build_settings_.check_for_bad_items()) {
     if (!builder_->CheckForBadItems(&err)) {
       err.PrintToStdout();
       return false;
     }
-  }
 
-  if (check_for_unused_overrides_) {
     if (!build_settings_.build_args().VerifyAllOverridesUsed(&err)) {
       // TODO(brettw) implement a system of warnings. Until we have a better
       // system, print the error but don't return failure.
diff --git a/tools/gn/setup.h b/tools/gn/setup.h
index 2e028e33..9c873679 100644
--- a/tools/gn/setup.h
+++ b/tools/gn/setup.h
@@ -68,16 +68,6 @@
   // want to rely on them being valid.
   void set_fill_arguments(bool fa) { fill_arguments_ = fa; }
 
-  // When true (the default), Run() will check for unresolved dependencies and
-  // cycles upon completion. When false, such errors will be ignored.
-  void set_check_for_bad_items(bool s) { check_for_bad_items_ = s; }
-
-  // When true (the default), RunPostMessageLoop will check for overrides that
-  // were specified but not used. When false, such errors will be ignored.
-  void set_check_for_unused_overrides(bool s) {
-    check_for_unused_overrides_ = s;
-  }
-
   // After a successful run, setting this will additionally cause the public
   // headers to be checked. Defaults to false.
   void set_check_public_headers(bool s) {
@@ -142,8 +132,6 @@
 
   SourceFile root_build_file_;
 
-  bool check_for_bad_items_;
-  bool check_for_unused_overrides_;
   bool check_public_headers_;
 
   // See getter for info.
diff --git a/tools/gn/target.cc b/tools/gn/target.cc
index 40c8a21..2ea28594 100644
--- a/tools/gn/target.cc
+++ b/tools/gn/target.cc
@@ -60,6 +60,47 @@
                  "Use source sets for intermediate targets instead.");
 }
 
+// Set check_private_deps to true for the first invocation since a target
+// can see all of its dependencies. For recursive invocations this will be set
+// to false to follow only public dependency paths.
+//
+// Pass a pointer to an empty set for the first invocation. This will be used
+// to avoid duplicate checking.
+bool EnsureFileIsGeneratedByDependency(const Target* target,
+                                       const OutputFile& file,
+                                       bool check_private_deps,
+                                       std::set<const Target*>* seen_targets) {
+  if (seen_targets->find(target) != seen_targets->end())
+    return false;  // Already checked this one and it's not found.
+  seen_targets->insert(target);
+
+  // Assume that we have relatively few generated inputs so brute-force
+  // searching here is OK. If this becomes a bottleneck, consider storing
+  // computed_outputs as a hash set.
+  for (const OutputFile& cur : target->computed_outputs()) {
+    if (file == cur)
+      return true;
+  }
+
+  // Check all public dependencies (don't do data ones since those are
+  // runtime-only).
+  for (const auto& pair : target->public_deps()) {
+    if (EnsureFileIsGeneratedByDependency(pair.ptr, file, false,
+                                          seen_targets))
+      return true;  // Found a path.
+  }
+
+  // Only check private deps if requested.
+  if (check_private_deps) {
+    for (const auto& pair : target->private_deps()) {
+      if (EnsureFileIsGeneratedByDependency(pair.ptr, file, false,
+                                            seen_targets))
+        return true;  // Found a path.
+    }
+  }
+  return false;
+}
+
 }  // namespace
 
 Target::Target(const Settings* settings, const Label& label)
@@ -132,12 +173,15 @@
 
   FillOutputFiles();
 
-  if (!CheckVisibility(err))
-    return false;
-  if (!CheckTestonly(err))
-    return false;
-  if (!CheckNoNestedStaticLibs(err))
-    return false;
+  if (settings()->build_settings()->check_for_bad_items()) {
+    if (!CheckVisibility(err))
+      return false;
+    if (!CheckTestonly(err))
+      return false;
+    if (!CheckNoNestedStaticLibs(err))
+      return false;
+    CheckSourcesGenerated();
+  }
 
   return true;
 }
@@ -304,6 +348,7 @@
 
 void Target::FillOutputFiles() {
   const Tool* tool = toolchain_->GetToolForTargetFinalOutput(this);
+  bool check_tool_outputs = false;
   switch (output_type_) {
     case GROUP:
     case SOURCE_SET:
@@ -322,6 +367,7 @@
       // Executables don't get linked to, but the first output is used for
       // dependency management.
       CHECK_GE(tool->outputs().list().size(), 1u);
+      check_tool_outputs = true;
       dependency_output_file_ =
           SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
               this, tool, tool->outputs().list()[0]);
@@ -330,12 +376,14 @@
       // Static libraries both have dependencies and linking going off of the
       // first output.
       CHECK(tool->outputs().list().size() >= 1);
+      check_tool_outputs = true;
       link_output_file_ = dependency_output_file_ =
           SubstitutionWriter::ApplyPatternToLinkerAsOutputFile(
               this, tool, tool->outputs().list()[0]);
       break;
     case SHARED_LIBRARY:
       CHECK(tool->outputs().list().size() >= 1);
+      check_tool_outputs = true;
       if (tool->link_output().empty() && tool->depend_output().empty()) {
         // Default behavior, use the first output file for both.
         link_output_file_ = dependency_output_file_ =
@@ -359,6 +407,26 @@
     default:
       NOTREACHED();
   }
+
+  // Count all outputs from this tool as something generated by this target.
+  if (check_tool_outputs) {
+    SubstitutionWriter::ApplyListToLinkerAsOutputFile(
+        this, tool, tool->outputs(), &computed_outputs_);
+
+    // Output names aren't canonicalized in the same way that source files
+    // are. For example, the tool outputs often use
+    // {{some_var}}/{{output_name}} which expands to "./foo", but this won't
+    // match "foo" which is what we'll compute when converting a SourceFile to
+    // an OutputFile.
+    for (auto& out : computed_outputs_)
+      NormalizePath(&out.value());
+  }
+
+  // Also count anything the target has declared to be an output.
+  std::vector<SourceFile> outputs_as_sources;
+  action_values_.GetOutputsAsSourceFiles(this, &outputs_as_sources);
+  for (const SourceFile& out : outputs_as_sources)
+    computed_outputs_.push_back(OutputFile(settings()->build_settings(), out));
 }
 
 bool Target::CheckVisibility(Err* err) const {
@@ -409,3 +477,30 @@
   }
   return true;
 }
+
+void Target::CheckSourcesGenerated() const {
+  // Checks that any inputs or sources to this target that are in the build
+  // directory are generated by a target that this one transitively depends on
+  // in some way. We already guarantee that all generated files are written
+  // to the build dir.
+  //
+  // See Scheduler::AddUnknownGeneratedInput's declaration for more.
+  for (const SourceFile& file : sources_)
+    CheckSourceGenerated(file);
+  for (const SourceFile& file : inputs_)
+    CheckSourceGenerated(file);
+}
+
+void Target::CheckSourceGenerated(const SourceFile& source) const {
+  if (!IsStringInOutputDir(settings()->build_settings()->build_dir(),
+                           source.value()))
+    return;  // Not in output dir, this is OK.
+
+  // Tell the scheduler about unknown files. This will be noted for later so
+  // the list of files written by the GN build itself (often response files)
+  // can be filtered out of this list.
+  OutputFile out_file(settings()->build_settings(), source);
+  std::set<const Target*> seen_targets;
+  if (!EnsureFileIsGeneratedByDependency(this, out_file, true, &seen_targets))
+    g_scheduler->AddUnknownGeneratedInput(this, source);
+}
diff --git a/tools/gn/target.h b/tools/gn/target.h
index 00500489..58319f1 100644
--- a/tools/gn/target.h
+++ b/tools/gn/target.h
@@ -221,6 +221,16 @@
   // frequently by unit tests which become needlessly verbose.
   bool SetToolchain(const Toolchain* toolchain, Err* err = nullptr);
 
+  // Once this target has been resolved, all outputs from the target will be
+  // listed here. This will include things listed in the "outputs" for an
+  // action or a copy step, and the output library or executable file(s) from
+  // binary targets.
+  //
+  // It will NOT include stamp files and object files.
+  const std::vector<OutputFile>& computed_outputs() const {
+    return computed_outputs_;
+  }
+
   // Returns outputs from this target. The link output file is the one that
   // other targets link to when they depend on this target. This will only be
   // valid for libraries and will be empty for all other target types.
@@ -260,6 +270,8 @@
   bool CheckVisibility(Err* err) const;
   bool CheckTestonly(Err* err) const;
   bool CheckNoNestedStaticLibs(Err* err) const;
+  void CheckSourcesGenerated() const;
+  void CheckSourceGenerated(const SourceFile& source) const;
 
   OutputType output_type_;
   std::string output_name_;
@@ -304,7 +316,8 @@
   // Toolchain used by this target. Null until target is resolved.
   const Toolchain* toolchain_;
 
-  // Output files. Null until the target is resolved.
+  // Output files. Empty until the target is resolved.
+  std::vector<OutputFile> computed_outputs_;
   OutputFile link_output_file_;
   OutputFile dependency_output_file_;
 
diff --git a/tools/gn/target_unittest.cc b/tools/gn/target_unittest.cc
index 020d4322..48fb84c 100644
--- a/tools/gn/target_unittest.cc
+++ b/tools/gn/target_unittest.cc
@@ -5,11 +5,30 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "tools/gn/build_settings.h"
 #include "tools/gn/config.h"
+#include "tools/gn/scheduler.h"
 #include "tools/gn/settings.h"
 #include "tools/gn/target.h"
 #include "tools/gn/test_with_scope.h"
 #include "tools/gn/toolchain.h"
 
+namespace {
+
+// Asserts that the current global scheduler has a single unknown generated
+// file with the given name from the given target.
+void AssertSchedulerHasOneUnknownFileMatching(const Target* target,
+                                              const SourceFile& file) {
+  auto unknown = g_scheduler->GetUnknownGeneratedInputs();
+  ASSERT_EQ(1u, unknown.size());  // Should be one unknown file.
+  auto found = unknown.find(file);
+  ASSERT_TRUE(found != unknown.end()) << file.value();
+  EXPECT_TRUE(target == found->second)
+      << "Target doesn't match. Expected\n  "
+      << target->label().GetUserVisibleName(false)
+      << "\nBut got\n  " << found->second->label().GetUserVisibleName(false);
+}
+
+}  // namespace
+
 // Tests that lib[_dir]s are inherited across deps boundaries for static
 // libraries but not executables.
 TEST(Target, LibInheritance) {
@@ -20,12 +39,9 @@
   const SourceDir libdir("/foo_dir/");
 
   // Leaf target with ldflags set.
-  Target z(setup.settings(), Label(SourceDir("//foo/"), "z"));
-  z.set_output_type(Target::STATIC_LIBRARY);
+  TestTarget z(setup, "//foo:z", Target::STATIC_LIBRARY);
   z.config_values().libs().push_back(lib);
   z.config_values().lib_dirs().push_back(libdir);
-  z.visibility().SetPublic();
-  z.SetToolchain(setup.toolchain());
   ASSERT_TRUE(z.OnResolved(&err));
 
   // All lib[_dir]s should be set when target is resolved.
@@ -38,13 +54,10 @@
   // and its own. Its own flag should be before the inherited one.
   const std::string second_lib("bar");
   const SourceDir second_libdir("/bar_dir/");
-  Target shared(setup.settings(), Label(SourceDir("//foo/"), "shared"));
-  shared.set_output_type(Target::SHARED_LIBRARY);
+  TestTarget shared(setup, "//foo:shared", Target::SHARED_LIBRARY);
   shared.config_values().libs().push_back(second_lib);
   shared.config_values().lib_dirs().push_back(second_libdir);
   shared.private_deps().push_back(LabelTargetPair(&z));
-  shared.visibility().SetPublic();
-  shared.SetToolchain(setup.toolchain());
   ASSERT_TRUE(shared.OnResolved(&err));
 
   ASSERT_EQ(2u, shared.all_libs().size());
@@ -55,10 +68,8 @@
   EXPECT_EQ(libdir, shared.all_lib_dirs()[1]);
 
   // Executable target shouldn't get either by depending on shared.
-  Target exec(setup.settings(), Label(SourceDir("//foo/"), "exec"));
-  exec.set_output_type(Target::EXECUTABLE);
+  TestTarget exec(setup, "//foo:exec", Target::EXECUTABLE);
   exec.private_deps().push_back(LabelTargetPair(&shared));
-  exec.SetToolchain(setup.toolchain());
   ASSERT_TRUE(exec.OnResolved(&err));
   EXPECT_EQ(0u, exec.all_libs().size());
   EXPECT_EQ(0u, exec.all_lib_dirs().size());
@@ -71,18 +82,9 @@
   Err err;
 
   // Set up a dependency chain of a -> b -> c
-  Target a(setup.settings(), Label(SourceDir("//foo/"), "a"));
-  a.set_output_type(Target::EXECUTABLE);
-  a.visibility().SetPublic();
-  a.SetToolchain(setup.toolchain());
-  Target b(setup.settings(), Label(SourceDir("//foo/"), "b"));
-  b.set_output_type(Target::STATIC_LIBRARY);
-  b.visibility().SetPublic();
-  b.SetToolchain(setup.toolchain());
-  Target c(setup.settings(), Label(SourceDir("//foo/"), "c"));
-  c.set_output_type(Target::STATIC_LIBRARY);
-  c.visibility().SetPublic();
-  c.SetToolchain(setup.toolchain());
+  TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
+  TestTarget b(setup, "//foo:b", Target::STATIC_LIBRARY);
+  TestTarget c(setup, "//foo:c", Target::STATIC_LIBRARY);
   a.private_deps().push_back(LabelTargetPair(&b));
   b.private_deps().push_back(LabelTargetPair(&c));
 
@@ -115,14 +117,8 @@
   EXPECT_EQ(&all, a.all_dependent_configs()[0].ptr);
 
   // Making an an alternate A and B with B forwarding the direct dependents.
-  Target a_fwd(setup.settings(), Label(SourceDir("//foo/"), "a_fwd"));
-  a_fwd.set_output_type(Target::EXECUTABLE);
-  a_fwd.visibility().SetPublic();
-  a_fwd.SetToolchain(setup.toolchain());
-  Target b_fwd(setup.settings(), Label(SourceDir("//foo/"), "b_fwd"));
-  b_fwd.set_output_type(Target::STATIC_LIBRARY);
-  b_fwd.SetToolchain(setup.toolchain());
-  b_fwd.visibility().SetPublic();
+  TestTarget a_fwd(setup, "//foo:a_fwd", Target::EXECUTABLE);
+  TestTarget b_fwd(setup, "//foo:b_fwd", Target::STATIC_LIBRARY);
   a_fwd.private_deps().push_back(LabelTargetPair(&b_fwd));
   b_fwd.private_deps().push_back(LabelTargetPair(&c));
   b_fwd.forward_dependent_configs().push_back(LabelTargetPair(&c));
@@ -144,22 +140,10 @@
 
   // Create a dependency chain:
   //   A (executable) -> B (shared lib) -> C (static lib) -> D (source set)
-  Target a(setup.settings(), Label(SourceDir("//foo/"), "a"));
-  a.set_output_type(Target::EXECUTABLE);
-  a.visibility().SetPublic();
-  a.SetToolchain(setup.toolchain());
-  Target b(setup.settings(), Label(SourceDir("//foo/"), "b"));
-  b.set_output_type(Target::SHARED_LIBRARY);
-  b.visibility().SetPublic();
-  b.SetToolchain(setup.toolchain());
-  Target c(setup.settings(), Label(SourceDir("//foo/"), "c"));
-  c.set_output_type(Target::STATIC_LIBRARY);
-  c.visibility().SetPublic();
-  c.SetToolchain(setup.toolchain());
-  Target d(setup.settings(), Label(SourceDir("//foo/"), "d"));
-  d.set_output_type(Target::SOURCE_SET);
-  d.visibility().SetPublic();
-  d.SetToolchain(setup.toolchain());
+  TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
+  TestTarget b(setup, "//foo:b", Target::SHARED_LIBRARY);
+  TestTarget c(setup, "//foo:c", Target::STATIC_LIBRARY);
+  TestTarget d(setup, "//foo:d", Target::SOURCE_SET);
   a.private_deps().push_back(LabelTargetPair(&b));
   b.private_deps().push_back(LabelTargetPair(&c));
   c.private_deps().push_back(LabelTargetPair(&d));
@@ -193,19 +177,10 @@
 
   // Create a dependency chain:
   //   A (executable) -> B (complete static lib) -> C (source set)
-  Target a(setup.settings(), Label(SourceDir("//foo/"), "a"));
-  a.set_output_type(Target::EXECUTABLE);
-  a.visibility().SetPublic();
-  a.SetToolchain(setup.toolchain());
-  Target b(setup.settings(), Label(SourceDir("//foo/"), "b"));
-  b.set_output_type(Target::STATIC_LIBRARY);
-  b.visibility().SetPublic();
+  TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
+  TestTarget b(setup, "//foo:b", Target::STATIC_LIBRARY);
   b.set_complete_static_lib(true);
-  b.SetToolchain(setup.toolchain());
-  Target c(setup.settings(), Label(SourceDir("//foo/"), "c"));
-  c.set_output_type(Target::SOURCE_SET);
-  c.visibility().SetPublic();
-  c.SetToolchain(setup.toolchain());
+  TestTarget c(setup, "//foo:c", Target::SOURCE_SET);
   a.public_deps().push_back(LabelTargetPair(&b));
   b.public_deps().push_back(LabelTargetPair(&c));
 
@@ -231,15 +206,9 @@
 
   // Create a dependency chain:
   //   A (complete static lib) -> B (static lib)
-  Target a(setup.settings(), Label(SourceDir("//foo/"), "a"));
-  a.set_output_type(Target::STATIC_LIBRARY);
-  a.visibility().SetPublic();
+  TestTarget a(setup, "//foo:a", Target::STATIC_LIBRARY);
   a.set_complete_static_lib(true);
-  a.SetToolchain(setup.toolchain());
-  Target b(setup.settings(), Label(SourceDir("//foo/"), "b"));
-  b.set_output_type(Target::STATIC_LIBRARY);
-  b.visibility().SetPublic();
-  b.SetToolchain(setup.toolchain());
+  TestTarget b(setup, "//foo:b", Target::STATIC_LIBRARY);
 
   a.public_deps().push_back(LabelTargetPair(&b));
   ASSERT_TRUE(b.OnResolved(&err));
@@ -252,19 +221,10 @@
 
   // Create a dependency chain:
   //   A (complete static lib) -> B (source set) -> C (static lib)
-  Target a(setup.settings(), Label(SourceDir("//foo/"), "a"));
-  a.set_output_type(Target::STATIC_LIBRARY);
-  a.visibility().SetPublic();
+  TestTarget a(setup, "//foo:a", Target::STATIC_LIBRARY);
   a.set_complete_static_lib(true);
-  a.SetToolchain(setup.toolchain());
-  Target b(setup.settings(), Label(SourceDir("//foo/"), "b"));
-  b.set_output_type(Target::SOURCE_SET);
-  b.visibility().SetPublic();
-  b.SetToolchain(setup.toolchain());
-  Target c(setup.settings(), Label(SourceDir("//foo/"), "c"));
-  c.set_output_type(Target::STATIC_LIBRARY);
-  c.visibility().SetPublic();
-  c.SetToolchain(setup.toolchain());
+  TestTarget b(setup, "//foo:b", Target::SOURCE_SET);
+  TestTarget c(setup, "//foo:c", Target::STATIC_LIBRARY);
 
   a.public_deps().push_back(LabelTargetPair(&b));
   b.public_deps().push_back(LabelTargetPair(&c));
@@ -280,37 +240,29 @@
 
   // Basic target with no prefix (executable type tool in the TestWithScope has
   // no prefix) or output name.
-  Target basic(setup.settings(), Label(SourceDir("//foo/"), "bar"));
-  basic.set_output_type(Target::EXECUTABLE);
-  basic.SetToolchain(setup.toolchain());
+  TestTarget basic(setup, "//foo:bar", Target::EXECUTABLE);
   ASSERT_TRUE(basic.OnResolved(&err));
   EXPECT_EQ("bar", basic.GetComputedOutputName(false));
   EXPECT_EQ("bar", basic.GetComputedOutputName(true));
 
   // Target with no prefix but an output name.
-  Target with_name(setup.settings(), Label(SourceDir("//foo/"), "bar"));
-  with_name.set_output_type(Target::EXECUTABLE);
+  TestTarget with_name(setup, "//foo:bar", Target::EXECUTABLE);
   with_name.set_output_name("myoutput");
-  with_name.SetToolchain(setup.toolchain());
   ASSERT_TRUE(with_name.OnResolved(&err));
   EXPECT_EQ("myoutput", with_name.GetComputedOutputName(false));
   EXPECT_EQ("myoutput", with_name.GetComputedOutputName(true));
 
   // Target with a "lib" prefix (the static library tool in the TestWithScope
   // should specify a "lib" output prefix).
-  Target with_prefix(setup.settings(), Label(SourceDir("//foo/"), "bar"));
-  with_prefix.set_output_type(Target::STATIC_LIBRARY);
-  with_prefix.SetToolchain(setup.toolchain());
+  TestTarget with_prefix(setup, "//foo:bar", Target::STATIC_LIBRARY);
   ASSERT_TRUE(with_prefix.OnResolved(&err));
   EXPECT_EQ("bar", with_prefix.GetComputedOutputName(false));
   EXPECT_EQ("libbar", with_prefix.GetComputedOutputName(true));
 
   // Target with a "lib" prefix that already has it applied. The prefix should
   // not duplicate something already in the target name.
-  Target dup_prefix(setup.settings(), Label(SourceDir("//foo/"), "bar"));
-  dup_prefix.set_output_type(Target::STATIC_LIBRARY);
+  TestTarget dup_prefix(setup, "//foo:bar", Target::STATIC_LIBRARY);
   dup_prefix.set_output_name("libbar");
-  dup_prefix.SetToolchain(setup.toolchain());
   ASSERT_TRUE(dup_prefix.OnResolved(&err));
   EXPECT_EQ("libbar", dup_prefix.GetComputedOutputName(false));
   EXPECT_EQ("libbar", dup_prefix.GetComputedOutputName(true));
@@ -321,20 +273,16 @@
   TestWithScope setup;
   Err err;
 
-  Target b(setup.settings(), Label(SourceDir("//private/"), "b"));
-  b.set_output_type(Target::STATIC_LIBRARY);
-  b.SetToolchain(setup.toolchain());
+  TestTarget b(setup, "//private:b", Target::STATIC_LIBRARY);
   b.visibility().SetPrivate(b.label().dir());
   ASSERT_TRUE(b.OnResolved(&err));
 
   // Make a target depending on "b". The dependency must have an origin to mark
   // it as user-set so we check visibility. This check should fail.
-  Target a(setup.settings(), Label(SourceDir("//app/"), "a"));
-  a.set_output_type(Target::EXECUTABLE);
+  TestTarget a(setup, "//app:a", Target::EXECUTABLE);
   a.private_deps().push_back(LabelTargetPair(&b));
   IdentifierNode origin;  // Dummy origin.
   a.private_deps()[0].origin = &origin;
-  a.SetToolchain(setup.toolchain());
   ASSERT_FALSE(a.OnResolved(&err));
 }
 
@@ -343,20 +291,15 @@
   TestWithScope setup;
   Err err;
 
-  Target b(setup.settings(), Label(SourceDir("//public/"), "b"));
-  b.set_output_type(Target::STATIC_LIBRARY);
-  b.SetToolchain(setup.toolchain());
-  b.visibility().SetPublic();
+  TestTarget b(setup, "//public:b", Target::STATIC_LIBRARY);
   ASSERT_TRUE(b.OnResolved(&err));
 
   // Make a target depending on "b". The dependency must have an origin to mark
   // it as user-set so we check visibility. This check should fail.
-  Target a(setup.settings(), Label(SourceDir("//app/"), "a"));
-  a.set_output_type(Target::EXECUTABLE);
+  TestTarget a(setup, "//app:a", Target::EXECUTABLE);
   a.data_deps().push_back(LabelTargetPair(&b));
   IdentifierNode origin;  // Dummy origin.
   a.data_deps()[0].origin = &origin;
-  a.SetToolchain(setup.toolchain());
   ASSERT_TRUE(a.OnResolved(&err)) << err.help_text();
 }
 
@@ -370,27 +313,20 @@
 
   // B has private visibility. This lets the group see it since the group is in
   // the same directory.
-  Target b(setup.settings(), Label(SourceDir("//private/"), "b"));
-  b.set_output_type(Target::STATIC_LIBRARY);
-  b.SetToolchain(setup.toolchain());
+  TestTarget b(setup, "//private:b", Target::STATIC_LIBRARY);
   b.visibility().SetPrivate(b.label().dir());
   ASSERT_TRUE(b.OnResolved(&err));
 
   // The group has public visibility and depends on b.
-  Target g(setup.settings(), Label(SourceDir("//private/"), "g"));
-  g.set_output_type(Target::GROUP);
-  g.SetToolchain(setup.toolchain());
+  TestTarget g(setup, "//public:g", Target::GROUP);
   g.private_deps().push_back(LabelTargetPair(&b));
   g.private_deps()[0].origin = &origin;
-  g.visibility().SetPublic();
   ASSERT_TRUE(b.OnResolved(&err));
 
   // Make a target depending on "g". This should succeed.
-  Target a(setup.settings(), Label(SourceDir("//app/"), "a"));
-  a.set_output_type(Target::EXECUTABLE);
+  TestTarget a(setup, "//app:a", Target::EXECUTABLE);
   a.private_deps().push_back(LabelTargetPair(&g));
   a.private_deps()[0].origin = &origin;
-  a.SetToolchain(setup.toolchain());
   ASSERT_TRUE(a.OnResolved(&err));
 }
 
@@ -402,27 +338,20 @@
   Err err;
 
   // "testlib" is a test-only library.
-  Target testlib(setup.settings(), Label(SourceDir("//test/"), "testlib"));
+  TestTarget testlib(setup, "//test:testlib", Target::STATIC_LIBRARY);
   testlib.set_testonly(true);
-  testlib.set_output_type(Target::STATIC_LIBRARY);
-  testlib.visibility().SetPublic();
-  testlib.SetToolchain(setup.toolchain());
   ASSERT_TRUE(testlib.OnResolved(&err));
 
   // "test" is a test-only executable depending on testlib, this is OK.
-  Target test(setup.settings(), Label(SourceDir("//test/"), "test"));
+  TestTarget test(setup, "//test:test", Target::EXECUTABLE);
   test.set_testonly(true);
-  test.set_output_type(Target::EXECUTABLE);
   test.private_deps().push_back(LabelTargetPair(&testlib));
-  test.SetToolchain(setup.toolchain());
   ASSERT_TRUE(test.OnResolved(&err));
 
   // "product" is a non-test depending on testlib. This should fail.
-  Target product(setup.settings(), Label(SourceDir("//app/"), "product"));
+  TestTarget product(setup, "//app:product", Target::EXECUTABLE);
   product.set_testonly(false);
-  product.set_output_type(Target::EXECUTABLE);
   product.private_deps().push_back(LabelTargetPair(&testlib));
-  product.SetToolchain(setup.toolchain());
   ASSERT_FALSE(product.OnResolved(&err));
 }
 
@@ -434,46 +363,31 @@
   Config pub_config(setup.settings(), pub_config_label);
 
   // This is the destination target that has a public config.
-  Target dest(setup.settings(), Label(SourceDir("//a/"), "a"));
-  dest.set_output_type(Target::SOURCE_SET);
-  dest.visibility().SetPublic();
-  dest.SetToolchain(setup.toolchain());
+  TestTarget dest(setup, "//a:a", Target::SOURCE_SET);
   dest.public_configs().push_back(LabelConfigPair(&pub_config));
   ASSERT_TRUE(dest.OnResolved(&err));
 
   // This target has a public dependency on dest.
-  Target pub(setup.settings(), Label(SourceDir("//a/"), "pub"));
-  pub.set_output_type(Target::SOURCE_SET);
-  pub.visibility().SetPublic();
-  pub.SetToolchain(setup.toolchain());
+  TestTarget pub(setup, "//a:pub", Target::SOURCE_SET);
   pub.public_deps().push_back(LabelTargetPair(&dest));
   ASSERT_TRUE(pub.OnResolved(&err));
 
   // Depending on the target with the public dependency should forward dest's
   // to the current target.
-  Target dep_on_pub(setup.settings(), Label(SourceDir("//a/"), "dop"));
-  dep_on_pub.set_output_type(Target::SOURCE_SET);
-  dep_on_pub.visibility().SetPublic();
-  dep_on_pub.SetToolchain(setup.toolchain());
+  TestTarget dep_on_pub(setup, "//a:dop", Target::SOURCE_SET);
   dep_on_pub.private_deps().push_back(LabelTargetPair(&pub));
   ASSERT_TRUE(dep_on_pub.OnResolved(&err));
   ASSERT_EQ(1u, dep_on_pub.configs().size());
   EXPECT_EQ(&pub_config, dep_on_pub.configs()[0].ptr);
 
   // This target has a private dependency on dest for forwards configs.
-  Target forward(setup.settings(), Label(SourceDir("//a/"), "f"));
-  forward.set_output_type(Target::SOURCE_SET);
-  forward.visibility().SetPublic();
-  forward.SetToolchain(setup.toolchain());
+  TestTarget forward(setup, "//a:f", Target::SOURCE_SET);
   forward.private_deps().push_back(LabelTargetPair(&dest));
   forward.forward_dependent_configs().push_back(LabelTargetPair(&dest));
   ASSERT_TRUE(forward.OnResolved(&err));
 
   // Depending on the forward target should apply the config.
-  Target dep_on_forward(setup.settings(), Label(SourceDir("//a/"), "dof"));
-  dep_on_forward.set_output_type(Target::SOURCE_SET);
-  dep_on_forward.visibility().SetPublic();
-  dep_on_forward.SetToolchain(setup.toolchain());
+  TestTarget dep_on_forward(setup, "//a:dof", Target::SOURCE_SET);
   dep_on_forward.private_deps().push_back(LabelTargetPair(&forward));
   ASSERT_TRUE(dep_on_forward.OnResolved(&err));
   ASSERT_EQ(1u, dep_on_forward.configs().size());
@@ -524,26 +438,17 @@
   Err err;
 
   // Create two leaf shared libraries.
-  Target pub(setup.settings(), Label(SourceDir("//foo/"), "pub"));
-  pub.set_output_type(Target::SHARED_LIBRARY);
-  pub.visibility().SetPublic();
-  pub.SetToolchain(setup.toolchain());
+  TestTarget pub(setup, "//foo:pub", Target::SHARED_LIBRARY);
   ASSERT_TRUE(pub.OnResolved(&err));
 
-  Target priv(setup.settings(), Label(SourceDir("//foo/"), "priv"));
-  priv.set_output_type(Target::SHARED_LIBRARY);
-  priv.visibility().SetPublic();
-  priv.SetToolchain(setup.toolchain());
+  TestTarget priv(setup, "//foo:priv", Target::SHARED_LIBRARY);
   ASSERT_TRUE(priv.OnResolved(&err));
 
   // Intermediate shared library with the leaf shared libraries as
   // dependencies, one public, one private.
-  Target inter(setup.settings(), Label(SourceDir("//foo/"), "inter"));
-  inter.set_output_type(Target::SHARED_LIBRARY);
-  inter.visibility().SetPublic();
+  TestTarget inter(setup, "//foo:inter", Target::SHARED_LIBRARY);
   inter.public_deps().push_back(LabelTargetPair(&pub));
   inter.private_deps().push_back(LabelTargetPair(&priv));
-  inter.SetToolchain(setup.toolchain());
   ASSERT_TRUE(inter.OnResolved(&err));
 
   // The intermediate shared library should have both "pub" and "priv" in its
@@ -555,11 +460,8 @@
   EXPECT_EQ(&priv, inter_inherited[1]);
 
   // Make a toplevel executable target depending on the intermediate one.
-  Target exe(setup.settings(), Label(SourceDir("//foo/"), "exe"));
-  exe.set_output_type(Target::SHARED_LIBRARY);
-  exe.visibility().SetPublic();
+  TestTarget exe(setup, "//foo:exe", Target::SHARED_LIBRARY);
   exe.private_deps().push_back(LabelTargetPair(&inter));
-  exe.SetToolchain(setup.toolchain());
   ASSERT_TRUE(exe.OnResolved(&err));
 
   // The exe's inherited libraries should be "inter" (because it depended
@@ -570,3 +472,89 @@
   EXPECT_EQ(&inter, exe_inherited[0]);
   EXPECT_EQ(&pub, exe_inherited[1]);
 }
+
+TEST(Target, GeneratedInputs) {
+  Scheduler scheduler;
+  TestWithScope setup;
+  Err err;
+
+  SourceFile generated_file("//out/Debug/generated.cc");
+
+  // This target has a generated input and no dependency makes it.
+  TestTarget non_existent_generator(setup, "//foo:non_existent_generator",
+                                    Target::EXECUTABLE);
+  non_existent_generator.sources().push_back(generated_file);
+  EXPECT_TRUE(non_existent_generator.OnResolved(&err)) << err.message();
+  AssertSchedulerHasOneUnknownFileMatching(&non_existent_generator,
+                                           generated_file);
+  scheduler.ClearUnknownGeneratedInputsAndWrittenFiles();
+
+  // Make a target that generates the file.
+  TestTarget generator(setup, "//foo:generator", Target::ACTION);
+  generator.action_values().outputs() =
+      SubstitutionList::MakeForTest(generated_file.value().c_str());
+  err = Err();
+  EXPECT_TRUE(generator.OnResolved(&err)) << err.message();
+
+  // A target that depends on the generator that uses the file as a source
+  // should be OK. This uses a private dep (will be used later).
+  TestTarget existent_generator(setup, "//foo:existent_generator",
+                                Target::SHARED_LIBRARY);
+  existent_generator.sources().push_back(generated_file);
+  existent_generator.private_deps().push_back(LabelTargetPair(&generator));
+  EXPECT_TRUE(existent_generator.OnResolved(&err)) << err.message();
+  EXPECT_TRUE(scheduler.GetUnknownGeneratedInputs().empty());
+
+  // A target that depends on the previous one should *not* be allowed to
+  // use the generated file, because existent_generator used private deps.
+  // This is:
+  //    indirect_private --> existent_generator --[private]--> generator
+  TestTarget indirect_private(setup, "//foo:indirect_private",
+                              Target::EXECUTABLE);
+  indirect_private.sources().push_back(generated_file);
+  indirect_private.public_deps().push_back(
+      LabelTargetPair(&existent_generator));
+  EXPECT_TRUE(indirect_private.OnResolved(&err));
+  AssertSchedulerHasOneUnknownFileMatching(&indirect_private, generated_file);
+  scheduler.ClearUnknownGeneratedInputsAndWrittenFiles();
+
+  // Now make a chain like the above but with all public deps, it should be OK.
+  TestTarget existent_public(setup, "//foo:existent_public",
+                             Target::SHARED_LIBRARY);
+  existent_public.public_deps().push_back(LabelTargetPair(&generator));
+  EXPECT_TRUE(existent_public.OnResolved(&err)) << err.message();
+  TestTarget indirect_public(setup, "//foo:indirect_public",
+                             Target::EXECUTABLE);
+  indirect_public.sources().push_back(generated_file);
+  indirect_public.public_deps().push_back(LabelTargetPair(&existent_public));
+  EXPECT_TRUE(indirect_public.OnResolved(&err)) << err.message();
+  EXPECT_TRUE(scheduler.GetUnknownGeneratedInputs().empty());
+}
+
+// This is sort of a Scheduler test, but is related to the above test more.
+TEST(Target, WriteFileGeneratedInputs) {
+  Scheduler scheduler;
+  TestWithScope setup;
+  Err err;
+
+  SourceFile generated_file("//out/Debug/generated.data");
+
+  // This target has a generated input and no dependency makes it.
+  TestTarget non_existent_generator(setup, "//foo:non_existent_generator",
+                                    Target::EXECUTABLE);
+  non_existent_generator.sources().push_back(generated_file);
+  EXPECT_TRUE(non_existent_generator.OnResolved(&err));
+  AssertSchedulerHasOneUnknownFileMatching(&non_existent_generator,
+                                           generated_file);
+  scheduler.ClearUnknownGeneratedInputsAndWrittenFiles();
+
+  // This target has a generated file and we've decared we write it.
+  TestTarget existent_generator(setup, "//foo:existent_generator",
+                                Target::EXECUTABLE);
+  existent_generator.sources().push_back(generated_file);
+  EXPECT_TRUE(existent_generator.OnResolved(&err));
+  scheduler.AddWrittenFile(generated_file);
+
+  // Should be OK.
+  EXPECT_TRUE(scheduler.GetUnknownGeneratedInputs().empty());
+}
diff --git a/tools/gn/test_with_scope.cc b/tools/gn/test_with_scope.cc
index 62849afb..847af62e 100644
--- a/tools/gn/test_with_scope.cc
+++ b/tools/gn/test_with_scope.cc
@@ -39,6 +39,14 @@
 TestWithScope::~TestWithScope() {
 }
 
+Label TestWithScope::ParseLabel(const std::string& str) const {
+  Err err;
+  Label result = Label::Resolve(SourceDir("//"), toolchain_.label(),
+                                Value(nullptr, str), &err);
+  CHECK(!err.has_error());
+  return result;
+}
+
 // static
 void TestWithScope::SetupToolchain(Toolchain* toolchain) {
   Err err;
@@ -139,3 +147,15 @@
 
 TestParseInput::~TestParseInput() {
 }
+
+TestTarget::TestTarget(TestWithScope& setup,
+                       const std::string& label_string,
+                       Target::OutputType type)
+    : Target(setup.settings(), setup.ParseLabel(label_string)) {
+  visibility().SetPublic();
+  set_output_type(type);
+  SetToolchain(setup.toolchain());
+}
+
+TestTarget::~TestTarget() {
+}
diff --git a/tools/gn/test_with_scope.h b/tools/gn/test_with_scope.h
index 26b082f..79c6a08b 100644
--- a/tools/gn/test_with_scope.h
+++ b/tools/gn/test_with_scope.h
@@ -14,6 +14,7 @@
 #include "tools/gn/parse_tree.h"
 #include "tools/gn/scope.h"
 #include "tools/gn/settings.h"
+#include "tools/gn/target.h"
 #include "tools/gn/token.h"
 #include "tools/gn/toolchain.h"
 #include "tools/gn/value.h"
@@ -35,6 +36,10 @@
   // threadsafe so don't write tests that call print from multiple threads.
   std::string& print_output() { return print_output_; }
 
+  // Parse the given string into a label in the default toolchain. This will
+  // assert if the label isn't valid (this is intended for hardcoded labels).
+  Label ParseLabel(const std::string& str) const;
+
   // Fills in the tools for the given toolchain with reasonable default values.
   // The toolchain in this object will be automatically set up with this
   // function, it is exposed to allow tests to get the same functionality for
@@ -82,4 +87,15 @@
   DISALLOW_COPY_AND_ASSIGN(TestParseInput);
 };
 
+// Shortcut for creating targets for tests that take the test setup, a pretty-
+// style label, and a target type and sets everything up. The target will
+// default to public visibility.
+class TestTarget : public Target {
+ public:
+  TestTarget(TestWithScope& setup,
+             const std::string& label_string,
+             Target::OutputType type);
+  ~TestTarget() override;
+};
+
 #endif  // TOOLS_GN_TEST_WITH_SCOPE_H_
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index 20fc28b..79f7601 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -219,37 +219,37 @@
     "includes": [28110],
   },
   "components/chrome_apps/chrome_apps_resources.grd": {
-    "includes": [28250],
+    "includes": [28290],
   },
   "ui/login/login_resources.grd": {
-    "includes": [28300],
-  },
-  "ui/oobe/oobe_resources.grd": {
     "includes": [28310],
   },
+  "ui/oobe/oobe_resources.grd": {
+    "includes": [28320],
+  },
   "chrome/browser/resources/translate_internals_resources.grd": {
-    "includes": [28500],
+    "includes": [28510],
   },
   "chrome/browser/resources/sync_file_system_internals_resources.grd": {
-    "includes": [29000],
+    "includes": [29010],
   },
   "chrome/app/address_input_strings.grd": {
-    "messages": [29100],
+    "messages": [29110],
   },
   "remoting/resources/remoting_strings.grd": {
-    "messages": [29550],
+    "messages": [29560],
   },
   "components/components_strings.grd": {
-    "messages": [30000],
+    "messages": [30010],
   },
   "components/resources/components_resources.grd": {
-    "includes": [30250],
+    "includes": [30260],
   },
   "components/resources/components_scaled_resources.grd": {
-    "structures": [30300],
+    "structures": [30310],
   },
   "components/resources/enhanced_bookmarks/enhanced_bookmarks_resources.grd": {
-    "includes": [30330],
+    "includes": [30340],
   },
   "third_party/WebKit/public/blink_resources.grd": {
     "includes": [30350],
diff --git a/tools/idl_parser/idl_lexer_test.py b/tools/idl_parser/idl_lexer_test.py
index 8b20da8..f8d8bb9a 100755
--- a/tools/idl_parser/idl_lexer_test.py
+++ b/tools/idl_parser/idl_lexer_test.py
@@ -3,11 +3,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import os
 import unittest
 
 from idl_lexer import IDLLexer
 from idl_ppapi_lexer import IDLPPAPILexer
 
+
 #
 # FileToTokens
 #
@@ -32,9 +34,10 @@
 class WebIDLLexer(unittest.TestCase):
   def setUp(self):
     self.lexer = IDLLexer()
+    cur_dir = os.path.dirname(os.path.realpath(__file__))
     self.filenames = [
-        'test_lexer/values.in',
-        'test_lexer/keywords.in'
+        os.path.join(cur_dir, 'test_lexer/values.in'),
+        os.path.join(cur_dir, 'test_lexer/keywords.in')
     ]
 
   #
@@ -89,9 +92,10 @@
 class PepperIDLLexer(WebIDLLexer):
   def setUp(self):
     self.lexer = IDLPPAPILexer()
+    cur_dir = os.path.dirname(os.path.realpath(__file__))
     self.filenames = [
-        'test_lexer/values_ppapi.in',
-        'test_lexer/keywords_ppapi.in'
+        os.path.join(cur_dir, 'test_lexer/values_ppapi.in'),
+        os.path.join(cur_dir, 'test_lexer/keywords_ppapi.in')
     ]
 
 
diff --git a/tools/idl_parser/run_tests.py b/tools/idl_parser/run_tests.py
index cf26759..878f17e 100755
--- a/tools/idl_parser/run_tests.py
+++ b/tools/idl_parser/run_tests.py
@@ -4,14 +4,16 @@
 # found in the LICENSE file.
 
 import glob
+import os
 import sys
 import unittest
 
 if __name__ == '__main__':
   suite = unittest.TestSuite()
-  for testname in glob.glob('*_test.py'):
+  cur_dir = os.path.dirname(os.path.realpath(__file__))
+  for testname in glob.glob(os.path.join(cur_dir, '*_test.py')):
     print 'Adding Test: ' + testname
-    module = __import__(testname[:-3])
+    module = __import__(os.path.basename(testname)[:-3])
     suite.addTests(unittest.defaultTestLoader.loadTestsFromModule(module))
   result = unittest.TextTestRunner(verbosity=2).run(suite)
   if result.wasSuccessful():
diff --git a/tools/luci-go/linux64/isolate.sha1 b/tools/luci-go/linux64/isolate.sha1
index cf4e635..9b64657 100644
--- a/tools/luci-go/linux64/isolate.sha1
+++ b/tools/luci-go/linux64/isolate.sha1
@@ -1 +1 @@
-8959df3af5347809e7eaf97a32e8622674d7a040
+e7a0e93c9a560cee05a375f2254d17cf8c9653e6
diff --git a/tools/luci-go/mac64/isolate.sha1 b/tools/luci-go/mac64/isolate.sha1
index 3648a6a..3dfe274 100644
--- a/tools/luci-go/mac64/isolate.sha1
+++ b/tools/luci-go/mac64/isolate.sha1
@@ -1 +1 @@
-52f5814f33474eea9074d828cd91a32b19594159
+6e7b095ba535219cbbb62f35e35037bb848e9ea4
diff --git a/tools/luci-go/win64/isolate.exe.sha1 b/tools/luci-go/win64/isolate.exe.sha1
index 9d1d9c2e..84d10005 100644
--- a/tools/luci-go/win64/isolate.exe.sha1
+++ b/tools/luci-go/win64/isolate.exe.sha1
@@ -1 +1 @@
-e533b3cb3d7015847d8a95d891898892cad2c5c4
+7eeb09411ce562805d5b1d4f570b124d14f21aaa
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index 3ba5943..0c3d4469 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -16,6 +16,7 @@
 import json
 import os
 import pipes
+import pprint
 import shlex
 import shutil
 import sys
@@ -75,7 +76,7 @@
                             help='analyze whether changes to a set of files '
                                  'will cause a set of binaries to be rebuilt.')
     AddCommonOptions(subp)
-    subp.add_argument('path', type=str, nargs=1,
+    subp.add_argument('path', nargs=1,
                       help='path build was generated into.')
     subp.add_argument('input_path', nargs=1,
                       help='path to a file containing the input arguments '
@@ -88,10 +89,23 @@
     subp = subps.add_parser('gen',
                             help='generate a new set of build files')
     AddCommonOptions(subp)
-    subp.add_argument('path', type=str, nargs=1,
+    subp.add_argument('path', nargs=1,
                       help='path to generate build into')
     subp.set_defaults(func=self.CmdGen)
 
+    subp = subps.add_parser('isolate',
+                            help='build isolates')
+    AddCommonOptions(subp)
+    subp.add_argument('path', nargs=1,
+                      help='path build was generated into.')
+    subp.add_argument('input_path', nargs=1,
+                      help='path to a file containing the input arguments '
+                           'as a JSON object.')
+    subp.add_argument('output_path', nargs=1,
+                      help='path to a file containing the output arguments '
+                           'as a JSON object.')
+    subp.set_defaults(func=self.CmdIsolate)
+
     subp = subps.add_parser('lookup',
                             help='look up the command for a given config or '
                                  'builder')
@@ -129,6 +143,17 @@
 
     raise MBErr('Unknown meta-build type "%s"' % vals['type'])
 
+  def CmdIsolate(self):
+    vals = self.GetConfig()
+    if vals['type'] == 'gn':
+      return self.RunGNIsolate(vals)
+    if vals['type'] == 'gyp':
+      # For GYP builds the .isolate files are checked in and the
+      # .isolate.gen.json files are generated during the compile,
+      # so there is no work to do here.
+      return 0
+    raise MBErr('Unknown meta-build type "%s"' % vals['type'])
+
   def CmdLookup(self):
     vals = self.GetConfig()
     if vals['type'] == 'gn':
@@ -367,6 +392,123 @@
 
     return ret
 
+  def RunGNIsolate(self, vals):
+    build_path = self.args.path[0]
+    inp = self.ReadInputJSON(['targets'])
+    if self.args.verbose:
+      self.Print()
+      self.Print('isolate input:')
+      self.PrintJSON(inp)
+      self.Print()
+    output_path = self.args.output_path[0]
+
+    for target in inp['targets']:
+      runtime_deps_path = self.ToAbsPath(build_path, target + '.runtime_deps')
+
+      if not self.Exists(runtime_deps_path):
+        self.WriteFailureAndRaise('"%s" does not exist' % runtime_deps_path,
+                                  output_path)
+
+      command, extra_files = self.GetIsolateCommand(target, vals)
+
+      runtime_deps = self.ReadFile(runtime_deps_path).splitlines()
+
+
+      isolate_path = self.ToAbsPath(build_path, target + '.isolate')
+      self.WriteFile(isolate_path,
+        pprint.pformat({
+          'variables': {
+            'command': command,
+            'files': sorted(runtime_deps + extra_files),
+            'read_only': 1,
+          }
+        }) + '\n')
+
+      self.WriteJSON(
+        {
+          'args': [
+            '--isolated',
+            self.ToSrcRelPath('%s/%s.isolated' % (build_path, target)),
+            '--isolate',
+            self.ToSrcRelPath('%s/%s.isolate' % (build_path, target)),
+          ],
+          'dir': self.chromium_src_dir,
+          'version': 1,
+        },
+        isolate_path + '.gen.json',
+      )
+
+    return 0
+
+  def GetIsolateCommand(self, target, vals):
+    output_path = self.args.output_path[0]
+
+    extra_files = []
+
+    # TODO(dpranke): We should probably pull this from
+    # the test list info in //testing/buildbot/*.json,
+    # and assert that the test has can_use_on_swarming_builders: True,
+    # but we hardcode it here for now.
+    test_type = {}.get(target, 'gtest_test')
+
+    # This needs to mirror the settings in //build/config/ui.gni:
+    # use_x11 = is_linux && !use_ozone.
+    # TODO(dpranke): Figure out how to keep this in sync better.
+    use_x11 = (sys.platform == 'linux2' and
+               not 'target_os="android"' in vals['gn_args'] and
+               not 'use_ozone=true' in vals['gn_args'])
+
+    asan = 'is_asan=true' in vals['gn_args']
+    msan = 'is_msan=true' in vals['gn_args']
+    tsan = 'is_tsan=true' in vals['gn_args']
+
+    executable_suffix = '.exe' if sys.platform == 'win32' else ''
+
+    if test_type == 'gtest_test':
+      extra_files.append('../../testing/test_env.py')
+
+      if use_x11:
+        # TODO(dpranke): Figure out some way to figure out which
+        # test steps really need xvfb.
+        extra_files.append('xdisplaycheck')
+        extra_files.append('../../testing/xvfb.py')
+
+        cmdline = [
+          '../../testing/xvfb.py',
+          '.',
+          './' + str(target),
+          '--brave-new-test-launcher',
+          '--test-launcher-bot-mode',
+          '--asan=%d' % asan,
+          '--msan=%d' % msan,
+          '--tsan=%d' % tsan,
+        ]
+      else:
+        cmdline = [
+          '../../testing/test_env.py',
+          '.',
+          './' + str(target) + executable_suffix,
+          '--brave-new-test-launcher',
+          '--test-launcher-bot-mode',
+          '--asan=%d' % asan,
+          '--msan=%d' % msan,
+          '--tsan=%d' % tsan,
+        ]
+    else:
+      # TODO(dpranke): Handle script_tests and other types of
+      # swarmed tests.
+      self.WriteFailureAndRaise('unknown test type "%s" for %s' %
+                                (test_type, target),
+                                output_path)
+
+
+    return cmdline, extra_files
+
+  def ToAbsPath(self, build_path, relpath):
+    return os.path.join(self.chromium_src_dir,
+                        self.ToSrcRelPath(build_path),
+                        relpath)
+
   def ToSrcRelPath(self, path):
     """Returns a relative path from the top of the repo."""
     # TODO: Support normal paths in addition to source-absolute paths.
@@ -401,7 +543,7 @@
     return cmd
 
   def RunGNAnalyze(self, _vals):
-    inp = self.GetAnalyzeInput()
+    inp = self.ReadInputJSON(['files', 'targets'])
     if self.args.verbose:
       self.Print()
       self.Print('analyze input:')
@@ -480,7 +622,7 @@
 
     return 0
 
-  def GetAnalyzeInput(self):
+  def ReadInputJSON(self, required_keys):
     path = self.args.input_path[0]
     output_path = self.args.output_path[0]
     if not self.Exists(path):
@@ -491,12 +633,11 @@
     except Exception as e:
       self.WriteFailureAndRaise('Failed to read JSON input from "%s": %s' %
                                 (path, e), output_path)
-    if not 'files' in inp:
-      self.WriteFailureAndRaise('input file is missing a "files" key',
-                                output_path)
-    if not 'targets' in inp:
-      self.WriteFailureAndRaise('input file is missing a "targets" key',
-                                output_path)
+
+    for k in required_keys:
+      if not k in inp:
+        self.WriteFailureAndRaise('input file is missing a "%s" key' % k,
+                                  output_path)
 
     return inp
 
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 1ec74f9a..aab60a8c 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -21,6 +21,7 @@
     'dev_gyp_debug': ['gyp', 'debug', 'shared', 'full_symbols'],
     'dev_gn_release': ['gn', 'release', 'shared'],
     'dev_gyp_release': ['gyp', 'release', 'shared'],
+    'gn_linux_upload': ['gn_linux_upload'],
     'gn_release_bot': ['gn', 'release_bot'],
     'gn_release_bot_x86': ['gn', 'release_bot', 'x86'],
     'gn_release_trybot': ['gn', 'release_trybot'],
@@ -89,6 +90,16 @@
       'gyp_defines': 'fastbuild=0',
     },
 
+    'gn_linux_upload': {
+      'type': 'gn',
+
+      # We don't want to require a runtime dependency on glib in the
+      # GN binary; ideally we could just turn glib off, but that doesn't
+      # actually work, so we need to pretend to be doing an ozone build
+      # in order for the flag to actually take effect.
+      'gn_args': 'use_ozone=true use_glib=false',
+    },
+
     'gn': {'type': 'gn'},
 
     'goma': {
@@ -158,6 +169,7 @@
     'chromium.win': {
       'Win x64 GN': 'gn_release_bot',
       'Win x64 GN (dbg)': 'gn_debug_bot',
+      'Win8 Aura': 'gn_release_bot_x86',
       'Win8 GN': 'gn_release_bot_x86',
       'Win8 GN (dbg)': 'gn_debug_bot_x86',
     },
@@ -194,9 +206,7 @@
       'linux_chromium_gn_chromeos_dbg': 'chromeos_gn_debug_bot',
       'linux_chromium_gn_dbg': 'gn_debug_bot',
       'linux_chromium_gn_rel': 'gn_release_trybot',
-      'linux_chromium_gn_upload': 'gn_release_bot',
-      'linux_chromium_gn_upload_x64': 'gn_release_bot', # TODO(dpranke): Remove me.
-      'linux_chromium_gn_upload_x86': 'gn_release_bot_x86', # TODO(dpranke): Remove me.
+      'linux_chromium_gn_upload': 'gn_linux_upload',
     },
     'tryserver.chromium.mac': {
       'mac_chromium_gn_dbg': 'gn_debug_static_bot',
@@ -206,6 +216,7 @@
     'tryserver.chromium.win': {
       'win_chromium_gn_x64_dbg': 'gn_debug_static_bot',
       'win_chromium_gn_x64_rel': 'gn_release_trybot',
+      'win8_chromium_rel': 'gn_release_trybot_x86',
       'win8_chromium_gn_dbg': 'gn_debug_static_bot_x86',
       'win8_chromium_gn_rel': 'gn_release_trybot_x86',
       'win8_chromium_gn_upload': 'gn_release_bot',
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 0756e628..c23dc08 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -61,6 +61,9 @@
 When 'ordering="prefix"' is present in the histogram_suffixes tag, the suffix
 will be inserted after the first dot separator of the affected-histogram name.
 Therefore, the affected-histogram name has to have at least one dot in it.
+
+Goolgers: There are also a small number of private internal histograms found at
+http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
 -->
 
 <histogram-configuration>
@@ -2563,6 +2566,15 @@
   <summary>Count of renderer process kills grouped by type.</summary>
 </histogram>
 
+<histogram name="BrowserRenderProcessHost.ChildKills.OOM" enum="RendererType">
+  <owner>oshima@chromium.org</owner>
+  <summary>
+    Out of BrowserRenderProcessHost.ChildKills, numer of kills due to SIGKILL,
+    which is a strong signal of out of memory on ChromeOS, grouped by renderer
+    type.
+  </summary>
+</histogram>
+
 <histogram name="BrowserRenderProcessHost.DisconnectedAlive"
     enum="RendererType">
   <owner>wfh@chromium.org</owner>
@@ -3022,6 +3034,14 @@
   <summary>Count of child process kills grouped by process type.</summary>
 </histogram>
 
+<histogram name="ChildProcess.Killed2.OOM" enum="ProcessType2">
+  <owner>oshima@chromium.org</owner>
+  <summary>
+    Out of ChildProcess.Killled, number of kills due to SIGKILL, which is a
+    strong signal of out of memory on ChromeOS, grouped by process type.
+  </summary>
+</histogram>
+
 <histogram name="ChildProcess.KilledByExtensionAPI">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <summary>
@@ -4403,6 +4423,33 @@
   </summary>
 </histogram>
 
+<histogram name="CustomTabs.PredictionStatus" enum="PredictionStatus">
+  <owner>lizeb@chromium.org</owner>
+  <summary>
+    For Custom Tabs, records whether mayLaunchUrl() has been called, and if so,
+    whether the call was later matched by a URL launch.
+  </summary>
+</histogram>
+
+<histogram name="CustomTabs.PredictionToLaunch" units="ms">
+  <owner>lizeb@chromium.org</owner>
+  <summary>
+    When a URL prediction succeeds, time in ms between the prediction and the
+    actual launch.
+  </summary>
+</histogram>
+
+<histogram name="DataReductionProxy.AutoLoFiRequestHeaderState"
+    enum="DataReductionProxyAutoLoFiRequestHeaderState">
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    Counts the changes in the state of Lo-Fi request header (q=low) being added
+    to the Chrome proxy request header. Counters are incremented when a main
+    frame URL request is handled by Data Reduction Proxy and session was in Auto
+    Lo-Fi enabled field trial.
+  </summary>
+</histogram>
+
 <histogram name="DataReductionProxy.BlockTypeFallback"
     enum="DataReductionProxyBypassType">
   <owner>bengr@chromium.org</owner>
@@ -4648,6 +4695,20 @@
   </summary>
 </histogram>
 
+<histogram name="DataReductionProxy.LoFi.UIAction"
+    enum="DataReductionProxyLoFiUIAction">
+  <owner>bengr@chromium.org</owner>
+  <owner>megjablon@chromium.org</owner>
+  <summary>
+    Samples of user interactions with the Lo-Fi snackbar and context menu
+    option. These samples include:
+
+    Displays and clicks on the &quot;Load images&quot; snackbar. Displays and
+    clicks on the &quot;Load image&quot; context menu option. Count of pages
+    where the user has clicked &quot;Load image&quot; at least once
+  </summary>
+</histogram>
+
 <histogram name="DataReductionProxy.MissingViaHeader.Bytes" units="bytes">
   <owner>bengr@chromium.org</owner>
   <owner>sclittle@chromium.org</owner>
@@ -13739,6 +13800,26 @@
   </summary>
 </histogram>
 
+<histogram name="InstanceID.DeleteToken.CompleteTime" units="milliseconds">
+  <owner>jianli@chromium.org</owner>
+  <summary>
+    Length of time taken to complete the DeleteToken request successfully. If
+    the request is retried multiple times, the length of time is counted for the
+    last successful retry.
+  </summary>
+</histogram>
+
+<histogram name="InstanceID.DeleteToken.RequestStatus"
+    enum="GCMUnregistrationRequestStatus">
+  <owner>juyik@chromium.org</owner>
+  <summary>Status code of the outcome of DeleteToken request.</summary>
+</histogram>
+
+<histogram name="InstanceID.DeleteToken.RetryCount">
+  <owner>jianli@chromium.org</owner>
+  <summary>Number of retries before DeleteToken succeeds.</summary>
+</histogram>
+
 <histogram name="InstanceID.Enabled" enum="BooleanEnabled">
   <owner>jianli@chromium.org</owner>
   <summary>
@@ -13747,6 +13828,40 @@
   </summary>
 </histogram>
 
+<histogram name="InstanceID.GetToken.CompleteTime" units="milliseconds">
+  <owner>jianli@chromium.org</owner>
+  <summary>
+    Length of time taken to complete the GetToken request successfully. If the
+    request is retried multiple times, the length of time is counted for the
+    last successful retry.
+  </summary>
+</histogram>
+
+<histogram name="InstanceID.GetToken.RequestStatus"
+    enum="GCMUnregistrationRequestStatus">
+  <owner>juyik@chromium.org</owner>
+  <summary>Status code of the outcome of GetToken request.</summary>
+</histogram>
+
+<histogram name="InstanceID.GetToken.RetryCount">
+  <owner>jianli@chromium.org</owner>
+  <summary>Number of retries before GetToken succeeds.</summary>
+</histogram>
+
+<histogram name="InstanceID.RestoredIDCount">
+  <owner>jianli@chromium.org</owner>
+  <summary>
+    Number of Instance IDs restored from the persistent store at startup.
+  </summary>
+</histogram>
+
+<histogram name="InstanceID.RestoredTokenCount">
+  <owner>jianli@chromium.org</owner>
+  <summary>
+    Number of InstanceID tokens restored from the persistent store at startup.
+  </summary>
+</histogram>
+
 <histogram name="Instant.InstantControllerEvent" enum="InstantControllerEvent">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <summary>
@@ -15764,6 +15879,11 @@
 </histogram>
 
 <histogram name="Media.VideoCapture.FramesReceived" enum="BooleanReceived">
+  <obsolete>
+    Deprecated as of 10/2014 in issue 422822. Replaced by
+    Media.VideoCaptureManager.Event and the two new values 3 and 4 in the enum
+    VideoCaptureEvent.
+  </obsolete>
   <owner>grunell@chromium.org</owner>
   <owner>mcasas@chromium.org</owner>
   <summary>
@@ -15816,7 +15936,10 @@
 <histogram name="Media.VideoCaptureManager.Event" enum="VideoCaptureEvent">
   <owner>grunell@chromium.org</owner>
   <owner>mcasas@chromium.org</owner>
-  <summary>Counts video capture event, such as start and stop capture.</summary>
+  <summary>
+    Counts video capture event, such as start and stop capture. Note that the
+    ideal case is 50% start events and 50% normal stop events.
+  </summary>
 </histogram>
 
 <histogram name="Media.VideoCodec" enum="VideoCodec">
@@ -16159,6 +16282,80 @@
   </summary>
 </histogram>
 
+<histogram name="Memory.OOMKill.Contents.MemAllocatedMB" units="MB">
+  <owner>oshima@chromium.org</owner>
+  <summary>
+    System-wide memory allocation right after a renderer was killed by
+    oom-killer, roughly equivalent to the sum of memory allocated with malloc()
+    in userspace plus graphics driver memory.
+  </summary>
+</histogram>
+
+<histogram name="Memory.OOMKill.Contents.MemAvailableMB" units="MB">
+  <owner>oshima@chromium.org</owner>
+  <summary>
+    System-wide file-backed memory plus free memory right after a renderer was
+    killed by oom-killer, which should be smaller than or close to what the
+    kernel uses to trigger low-memory notifications for tab discards. If this is
+    higher than the kernel's threshold for tab discards, renderers may be killed
+    due to reasons other than out-of-memory.
+  </summary>
+</histogram>
+
+<histogram name="Memory.OOMKill.Contents.MemGraphicsMB" units="MB">
+  <owner>oshima@chromium.org</owner>
+  <summary>
+    Graphics driver (GEM object) memory right after a renderer was killed by
+    oom-killer.
+  </summary>
+</histogram>
+
+<histogram name="Memory.OOMKill.Contents.MemShmemMB" units="MB">
+  <owner>oshima@chromium.org</owner>
+  <summary>
+    System-wide shared memory right after a renderer was killed by oom-killer.
+    Used primarily for shared buffers in the graphics system. Tracked because
+    it's a historical source of leaks on Chrome OS.
+  </summary>
+</histogram>
+
+<histogram name="Memory.OOMKill.Extensions.MemAllocatedMB" units="MB">
+  <owner>oshima@chromium.org</owner>
+  <summary>
+    System-wide memory allocation right after a renderer was killed by
+    oom-killer, roughly equivalent to the sum of memory allocated with malloc()
+    in userspace plus graphics driver memory.
+  </summary>
+</histogram>
+
+<histogram name="Memory.OOMKill.Extensions.MemAvailableMB" units="MB">
+  <owner>oshima@chromium.org</owner>
+  <summary>
+    System-wide file-backed memory plus free memory right after a renderer was
+    killed by oom-killer, which should be smaller than or close to what the
+    kernel uses to trigger low-memory notifications for tab discards. If this is
+    higher than the kernel's threshold for tab discards, renderers may be killed
+    due to reasons other than out-of-memory.
+  </summary>
+</histogram>
+
+<histogram name="Memory.OOMKill.Extensions.MemGraphicsMB" units="MB">
+  <owner>oshima@chromium.org</owner>
+  <summary>
+    Graphics driver (GEM object) memory right after a renderer was killed by
+    oom-killer.
+  </summary>
+</histogram>
+
+<histogram name="Memory.OOMKill.Extensions.MemShmemMB" units="MB">
+  <owner>oshima@chromium.org</owner>
+  <summary>
+    System-wide shared memory right after a renderer was killed by oom-killer.
+    Used primarily for shared buffers in the graphics system. Tracked because
+    it's a historical source of leaks on Chrome OS.
+  </summary>
+</histogram>
+
 <histogram name="Memory.OtherProcessCount">
   <owner>hajimehoshi@chromium.org</owner>
   <owner>kenjibaheux@google.com</owner>
@@ -19388,6 +19585,28 @@
   </summary>
 </histogram>
 
+<histogram name="Net.DailyUserVisibleSavingsPercent_DataRedictionProxyEnabled"
+    units="Percent">
+  <owner>kundaji@chromium.org</owner>
+  <owner>bengr@chromium.org</owner>
+  <summary>
+    The percentage of data savings in past
+    |DataReductionProxy::kNumDaysInHistorySummary| days. This number is
+    displayed to users as their data savings.
+  </summary>
+</histogram>
+
+<histogram name="Net.DailyUserVisibleSavingsSize_DataRedictionProxyEnabled"
+    units="KB">
+  <owner>kundaji@chromium.org</owner>
+  <owner>bengr@chromium.org</owner>
+  <summary>
+    The total data saved in KB in past
+    |DataReductionProxy::kNumDaysInHistorySummary| days. This number is used to
+    compute the data savings displayed to the user.
+  </summary>
+</histogram>
+
 <histogram name="Net.DhcpWpadCancelTime" units="milliseconds">
   <obsolete>
     Removed in Chrome 39.
@@ -27025,6 +27244,17 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordManager.EmptyUsernames.PasswordFieldCount">
+  <owner>msramek@chromium.org</owner>
+  <owner>vasilii@chromium.org</owner>
+  <summary>
+    The number of password fields for password forms that do not have a username
+    field. This is recorded every time such a password form is successfully
+    parsed. Note that the parsing is attempted when the form is encountered (i.e
+    when the document is loaded) and also when it is submitted.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.EmptyUsernames.TextAndPasswordFieldCount">
   <owner>msramek@chromium.org</owner>
   <owner>vasilii@chromium.org</owner>
@@ -37497,6 +37727,10 @@
 
 <histogram name="SharedMemory.TimeSpentMakingAnonymousMemory"
     units="milliseconds">
+  <obsolete>
+    Deprecated 2015-06 because the Finch experiment SharedMemoryCreateStrategy
+    has finished running.
+  </obsolete>
   <owner>erikchen@chromium.org</owner>
   <summary>
     The time spent making a new region of shared, anonymous memory. This metric
@@ -43723,12 +43957,26 @@
   <owner>jamescook@chromium.org</owner>
   <summary>
     Cumulative number of times a tab was killed with a &quot;He's dead,
-    Jim!&quot; page, which is usually due to the kernel out-of-memory killer
-    running, recorded once per tab kill event.  For example, a user who loses 3
-    tabs will record a count in the 1 bin, 2 bin, and 3 bin.  Thus each bin N is
-    the number of sessions where users experienced N or more kill events.  The
-    user may not have actually seen the sad tab page, as it might have been an
-    inactive tab.  Compare to Tabs.SadTab.KillDisplayed.
+    Jim!&quot; page, which is usually due to the renderer being killed, recorded
+    once per tab kill event.  For example, a user who loses 3 tabs will record a
+    count in the 1 bin, 2 bin, and 3 bin.  Thus each bin N is the number of
+    sessions where users experienced N or more kill events.  The user may not
+    have actually seen the sad tab page, as it might have been an inactive tab.
+    Compare to Tabs.SadTab.KillDisplayed. This can happen due to out of memory,
+    malformed IPC messages, or a SIGINT/TERM/KILL signal sent by a user.
+  </summary>
+</histogram>
+
+<histogram name="Tabs.SadTab.KillCreated.OOM">
+  <owner>oshima@chromium.org</owner>
+  <summary>
+    Cumulative number of times a tab was killed with a &quot;He's dead,
+    Jim!&quot; page due to the kernel out-of-memory killer, recorded once per
+    tab kill event.  For example, a user who loses 3 tabs will record a count in
+    the 1 bin, 2 bin, and 3 bin.  Thus each bin N is the number of sessions
+    where users experienced N or more kill events.  The user may not have
+    actually seen the sad tab page, as it might have been an inactive tab.
+    Compare to Tabs.SadTab.KillDisplayed.
   </summary>
 </histogram>
 
@@ -43743,6 +43991,18 @@
   </summary>
 </histogram>
 
+<histogram name="Tabs.SadTab.KillDisplayed.OOM">
+  <owner>oshima@chromium.org</owner>
+  <summary>
+    Cumulative number of times a tab was killed with a &quot;He's dead,
+    Jim!&quot; page due to the kernel out-of-memory killer and the user saw the
+    page, recorded once per tab kill event.  For example, a user who loses 3
+    tabs will record a count in the 1 bin, 2 bin, and 3 bin. Thus each bin N is
+    the number of sessions where users experienced N or more kill events.
+    Compare to Tabs.SadTab.CrashCreated.
+  </summary>
+</histogram>
+
 <histogram name="Tabs.SadTab.ReloadCount">
   <owner>jamescook@chromium.org</owner>
   <summary>
@@ -50879,6 +51139,13 @@
   <int value="4" label="Channel is negotiated."/>
 </enum>
 
+<enum name="DataReductionProxyAutoLoFiRequestHeaderState" type="int">
+  <int value="0" label="Empty to Empty"/>
+  <int value="1" label="Empty to Low"/>
+  <int value="2" label="Low to Empty"/>
+  <int value="3" label="Low to Low"/>
+</enum>
+
 <enum name="DataReductionProxyBypassEventType_Deprecated" type="int">
   <int value="0" label="Short bypass"/>
   <int value="1" label="Long bypass"/>
@@ -50910,6 +51177,15 @@
   <int value="10" label="Bypass due to any network error"/>
 </enum>
 
+<enum name="DataReductionProxyLoFiUIAction" type="int">
+  <int value="0" label="'Load images' snackbar shown"/>
+  <int value="1" label="'Load images' snackbar clicked"/>
+  <int value="2" label="'Load image' context menu item shown"/>
+  <int value="3" label="'Load image' context menu item clicked"/>
+  <int value="4"
+      label="Pages where the user has clicked 'Load image' at least once"/>
+</enum>
+
 <enum name="DataReductionProxyNetworkChangeEvent" type="int">
   <int value="0" label="IP Address Change"/>
   <int value="1" label="Proxy disabled on VPN"/>
@@ -58033,6 +58309,7 @@
   <int value="-2063014275" label="enable-web-bluetooth"/>
   <int value="-2047822258" label="enable-avfoundation"/>
   <int value="-2025367104" label="enable-material-design-ntp"/>
+  <int value="-2020721975" label="smart-virtual-keyboard"/>
   <int value="-2020024440" label="scroll-end-effect"/>
   <int value="-2017953534" label="enable-hosted-app-shim-creation"/>
   <int value="-2008272679" label="disable-webrtc-hw-encoding"/>
@@ -58187,6 +58464,7 @@
   <int value="-610411643" label="enable-printer-app-search"/>
   <int value="-604814313" label="enable-pinch"/>
   <int value="-601384286" label="disable-contextual-search"/>
+  <int value="-589096918" label="ash-enable-fullscreen-app-list"/>
   <int value="-579192400" label="disable-input-view"/>
   <int value="-567920515" label="disable-experimental-hotwording"/>
   <int value="-563980787" label="disable-webrtc"/>
@@ -62154,6 +62432,12 @@
   <int value="1" label="The pre-connect triggered host was accessed"/>
 </enum>
 
+<enum name="PredictionStatus" type="int">
+  <int value="0" label="No prediction"/>
+  <int value="1" label="Successful prediction"/>
+  <int value="2" label="Wrong prediction"/>
+</enum>
+
 <enum name="PrefetchStatus" type="int">
   <int value="0" label="undefined"/>
   <int value="1" label="success from cache"/>
@@ -68222,6 +68506,15 @@
   <affected-histogram name="PLT.PT_StartToFinish"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="DataReductionProxy.WithValidOCL.LoFiOn" separator=".">
+  <suffix name="LoFiOn"
+      label="Only page loads through the data reduction proxy with Lo-Fi On
+             are considered."/>
+  <affected-histogram name="Net.HttpContentLengthDifferenceWithValidOCL"/>
+  <affected-histogram name="Net.HttpContentLengthWithValidOCL"/>
+  <affected-histogram name="Net.HttpOriginalContentLengthWithValidOCL"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="DataReductionProxy_AutoLoFi" separator="_">
   <suffix name="DataReductionProxy_AutoLoFiOn"
       label="Only page loads through the data reduction proxy with auto LoFi
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index e423a8b..55e767be 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -176,7 +176,8 @@
     return CreatePageSetFromPath(path, SKIPPED_FILE)
 
 
-@benchmark.Disabled('xp')  # http://crbug.com/488059
+@benchmark.Disabled('xp',  # http://crbug.com/488059
+                    'android')  # http://crbug.com/496707
 class BlinkPerfCanvas(perf_benchmark.PerfBenchmark):
   tag = 'canvas'
   test = _BlinkPerfMeasurement
diff --git a/tools/perf/benchmarks/repaint.py b/tools/perf/benchmarks/repaint.py
index 5d0b6e0..488a42e 100644
--- a/tools/perf/benchmarks/repaint.py
+++ b/tools/perf/benchmarks/repaint.py
@@ -28,7 +28,7 @@
   def Name(cls):
     return 'repaint'
 
-  def CreateUserStorySet(self, options):
+  def CreateStorySet(self, options):
     return page_sets.KeyMobileSitesRepaintPageSet(
         options.mode, options.width, options.height)
 
diff --git a/tools/perf/benchmarks/session_restore.py b/tools/perf/benchmarks/session_restore.py
index 541bd3a..7f629f1 100644
--- a/tools/perf/benchmarks/session_restore.py
+++ b/tools/perf/benchmarks/session_restore.py
@@ -2,9 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import os
-import tempfile
-
 from core import perf_benchmark
 
 from measurements import session_restore
@@ -27,6 +24,8 @@
   page_set = page_sets.Typical25PageSet
   tag = None  # override with 'warm' or 'cold'
 
+  PROFILE_TYPE = 'small_profile'
+
   @classmethod
   def Name(cls):
     return 'session_restore'
@@ -34,39 +33,29 @@
   @classmethod
   def ProcessCommandLineArgs(cls, parser, args):
     super(_SessionRestoreTypical25, cls).ProcessCommandLineArgs(parser, args)
-    profile_type = 'small_profile'
-    if not args.browser_options.profile_dir:
-      output_dir = os.path.join(tempfile.gettempdir(), profile_type)
-      profile_dir = os.path.join(output_dir, profile_type)
-      if not os.path.exists(output_dir):
-        os.makedirs(output_dir)
-
-      # Generate new profiles if profile_dir does not exist. It only exists if
-      # all profiles had been correctly generated in a previous run.
-      if not os.path.exists(profile_dir):
-        new_args = args.Copy()
-        new_args.pageset_repeat = 1
-        new_args.output_dir = output_dir
-        profile_generator.GenerateProfiles(
-            small_profile_extender.SmallProfileExtender,
-            profile_type, new_args)
-      args.browser_options.profile_dir = profile_dir
+    generator = profile_generator.ProfileGenerator(
+        small_profile_extender.SmallProfileExtender, cls.PROFILE_TYPE)
+    out_dir = generator.Run(args)
+    if out_dir:
+      args.browser_options.profile_dir = out_dir
+    else:
+      args.browser_options.dont_override_profile = True
 
   @classmethod
   def ValueCanBeAddedPredicate(cls, _, is_first_result):
     return cls.tag == 'cold' or not is_first_result
 
-  def CreateUserStorySet(self, _):
-    """Return a user story set that only has the first user story.
+  def CreateStorySet(self, _):
+    """Return a story set that only has the first user story.
 
     The session restore measurement skips the navigation step and
     only tests session restore by having the browser start-up.
     The first user story is used to get WPR set up and hold results.
     """
-    user_story_set = self.page_set()
-    for user_story in user_story_set.user_stories[1:]:
-      user_story_set.RemoveUserStory(user_story)
-    return user_story_set
+    story_set = self.page_set()
+    for user_story in story_set.user_stories[1:]:
+      story_set.RemoveUserStory(user_story)
+    return story_set
 
   def CreatePageTest(self, options):
     is_cold = (self.tag == 'cold')
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py
index b68826a..50fea2f 100644
--- a/tools/perf/benchmarks/smoothness.py
+++ b/tools/perf/benchmarks/smoothness.py
@@ -406,6 +406,7 @@
     return 'smoothness.tough_texture_upload_cases'
 
 
+@benchmark.Disabled('reference')  # http://crbug.com/496684
 class SmoothnessToughAdCases(perf_benchmark.PerfBenchmark):
   """Measures rendering statistics while displaying advertisements."""
   test = smoothness.Smoothness
diff --git a/tools/perf/page_sets/key_desktop_move_cases.py b/tools/perf/page_sets/key_desktop_move_cases.py
index 95a48d7..195a4e96d 100644
--- a/tools/perf/page_sets/key_desktop_move_cases.py
+++ b/tools/perf/page_sets/key_desktop_move_cases.py
@@ -84,7 +84,7 @@
 
 class GoogleMapsPage(KeyDesktopMoveCasesPage):
 
-  """ Why: productivity, top google properties; Supports drag gesturee """
+  """ Why: productivity, top google properties; Supports drag gestures """
 
   def __init__(self, page_set):
     super(GoogleMapsPage, self).__init__(
diff --git a/tools/perf/page_sets/tough_ad_cases.py b/tools/perf/page_sets/tough_ad_cases.py
index a691515b..3706bfe 100644
--- a/tools/perf/page_sets/tough_ad_cases.py
+++ b/tools/perf/page_sets/tough_ad_cases.py
@@ -9,7 +9,8 @@
 class SwiffyPage(page_module.Page):
 
   def __init__(self, url, page_set):
-    super(SwiffyPage, self).__init__(url=url, page_set=page_set)
+    super(SwiffyPage, self).__init__(url=url, page_set=page_set,
+                                     make_javascript_deterministic=False)
 
   def RunNavigateSteps(self, action_runner):
     super(SwiffyPage, self).RunNavigateSteps(action_runner)
diff --git a/tools/perf/page_sets/tough_scrolling_cases.py b/tools/perf/page_sets/tough_scrolling_cases.py
index e76b519d..5076a85 100644
--- a/tools/perf/page_sets/tough_scrolling_cases.py
+++ b/tools/perf/page_sets/tough_scrolling_cases.py
@@ -1,24 +1,28 @@
 # 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.
+from telemetry.internal.actions import page_action
 from telemetry.page import page as page_module
 from telemetry.page import page_set as page_set_module
 
 
 class ToughFastScrollingCasesPage(page_module.Page):
 
-  def __init__(self, url, name, speed_in_pixels_per_second, page_set):
+  def __init__(self, url, name, speed_in_pixels_per_second, page_set,
+               synthetic_gesture_source):
     super(ToughFastScrollingCasesPage, self).__init__(
       url=url,
       page_set=page_set,
       name=name)
     self.speed_in_pixels_per_second = speed_in_pixels_per_second
+    self.synthetic_gesture_source = synthetic_gesture_source
 
   def RunPageInteractions(self, action_runner):
     with action_runner.CreateGestureInteraction('ScrollAction'):
       action_runner.ScrollPage(
           direction='down',
-          speed_in_pixels_per_second=self.speed_in_pixels_per_second)
+          speed_in_pixels_per_second=self.speed_in_pixels_per_second,
+          synthetic_gesture_source=self.synthetic_gesture_source)
 
 class ToughScrollingCasesPageSet(page_set_module.PageSet):
 
@@ -31,6 +35,7 @@
 
     fast_scrolling_page_name_list = [
       'text',
+      'text_hover',
       'canvas'
     ]
 
@@ -40,8 +45,12 @@
 
     for name in fast_scrolling_page_name_list:
       for speed in fast_scrolling_speed_list:
+        synthetic_gesture_source = page_action.GESTURE_SOURCE_DEFAULT
+        if "hover" in name:
+          synthetic_gesture_source = page_action.GESTURE_SOURCE_MOUSE
         self.AddUserStory(ToughFastScrollingCasesPage(
           'file://tough_scrolling_cases/' + name + '.html',
           name + '_' + str(speed).zfill(5) + '_pixels_per_second',
           speed,
-          self))
+          self,
+          synthetic_gesture_source))
diff --git a/tools/perf/page_sets/tough_scrolling_cases/text_hover.html b/tools/perf/page_sets/tough_scrolling_cases/text_hover.html
new file mode 100644
index 0000000..7c1649a
--- /dev/null
+++ b/tools/perf/page_sets/tough_scrolling_cases/text_hover.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<head>
+<style>
+h1:hover, h2:hover, p:hover {
+  color:blue;
+  box-shadow: 0px 0px 100px #000;
+}
+</style>
+</head>
+<body>
+<h1>Lorem ipsum dolor</h1><h2>Sit amet vitae</h2><p>Magna sed dolores. Phasellus aliquam suscipit. Molestie rutrum quia. Feugiat laborum sapien. Vehicula dapibus placerat velit et lacus ullamcorper.</p><ol><li>Sapien ultrices phasellus feugiat nec aut.</li><li>Nam risus tellus.</li><li>Et aliquam diam.</li><li>Libero urna eget.</li><li>Lobortis erat pellentesque.</li><li>Deleniti a vestibulum.</li><li>Congue lectus erat nullam.</li></ol><h2>Nec porta feugiat egestas sapien cras</h2><p>Pellentesque suscipit mattis. Cras magna non. Vestibulum lectus rhoncus. At in arcu. Quam bibendum ac. Nullam sed id sed.</p><p>Metus vehicula feugiat. Ante mauris nunc. Nam mauris erat. Metus pellentesque metus. Et est sodales. In in malesuada. Nulla auctor cras adipiscing leo erat id.</p><h2>Dolor vulputate cras</h2><p>Maecenas aliquet arcu. Et lorem fusce. Quis est id pulvinar feugiat auctor. Risus nam ornare. Vestibulum praesent lorem. Fringilla morbi a phasellus.</p><p>Laoreet proin vestibulum. Mi scelerisque semper. Id magna nec non vestibulum condimentum. Omnis suscipit eu. Ut dictum wisi. Ullamco ac eu. Posuere eleifend risus non.</p><h2>Vivamus amet rutrum</h2><p>Ligula dolor ut. Lacus donec porta tellus velit ut. In eu eget. Diam quis magna. In wisi phasellus. Sed arcu lectus leo.</p><p>Donec wisi eget. Venenatis et interdum. Posuere libero quis. Primis lectus proin neque blandit quisque. Eu nibh mi. Felis urna facilisi. Rutrum scelerisque mauris nunc.</p><h2>Dui vivamus urna blandit at quam</h2><p>Eget ut quam. Semper ullamcorper risus. Lorem pretium nunc. Enim dis velit. Litora dolor mollis. Pellentesque fusce ipsum morbi.</p><p>Id velit mauris. Magna ac non. Sapien sociosqu mauris habitant ante dolor. Amet nullam sit. Viverra at aliquet. In magna odio. Urna eros velit neque.</p><h2>Nibh tellus elementum</h2><p>Libero egestas semper. Sed sit voluptates. Phasellus viverra sit. Nec dolor sit. Blandit mi morbi. Mauris nulla tortor pretium eget aptent ipsum.</p><p>Mauris porttitor dui. Diam vehicula tincidunt. Tellus rhoncus molestie. Qui id tincidunt. Integer augue congue. A in enim. Fringilla accumsan pulvinar gravida pede sit sociis.</p><h2>Facilisis laoreet blandit</h2><p>Elit amet massa. Placerat urna nulla. Mollis magna penatibus. Scelerisque non porta. Eu neque quam. Urna nec placerat felis non diam purus.</p><p>Lectus integer dictum. Ut faucibus in. Condimentum commodo sit. Eget justo nec. Eu vestibulum risus. Proin morbi ac. Ultrices et lorem vehicula tortor placerat cursus.</p><h2>Nec risus mollis</h2><p>Velit orci justo. Mollis eleifend aenean. Enim maecenas ante. Lorem sollicitudin sit. Vestibulum sem lorem. Dolor pretium nulla tortor diam placerat ligula.</p><p>Proin rhoncus velit. Nisl pede magna magna venenatis fusce. Nihil nec sollicitudin. Gravida sed est. Urna dictum eros. Tincidunt montes vestibulum. Et nulla tristique quam.</p><h2>Velit ut mi</h2><p>Elit amet sapien. Aliquam ligula nec. Accumsan nulla leo vel eu ac. Sed et blandit. Curabitur conubia eros. Vivamus gravida ridiculus commodo.</p><p>Purus vulputate aptent. Augue vestibulum urna. Viverra ullamcorper turpis. In sodales facilisis. Id urna quam. Donec non bibendum. Volutpat et mattis wisi quis ipsum est.</p><h2>Et quam et</h2><p>Ipsum malesuada quam. Metus eget aliquet sit massa leo. Aliquam veniam venenatis. Nec sagittis euismod. Nunc vitae mollis. Iaculis ut nec enim.</p><p>In wisi pede. Dapibus urna tellus. Ut pede quis. Sit blandit phasellus. Metus interdum nam. Nec convallis ante. Faucibus maecenas enim nulla nunc lorem suscipit.</p><h2>Hac euismod lacinia</h2><p>Luctus nibh pellentesque. Etiam scelerisque phasellus. Sodales ultrices vitae massa mollis sem. Ultrices etiam neque. Integer mauris suscipit. Non nullam dui faucibus.</p><p>Ligula mauris non. Quisque vestibulum eleifend. Nulla massa eros tellus ipsum lorem. Sed vestibulum ac. Malesuada cras nisl. Est molestie dui. Luctus urna hendrerit arcu.</p><h2>Eu libero non</h2><p>Ligula dolor et. Justo nunc faucibus. Purus velit nulla facilisi sollicitudin phasellus. Erat platea sodales. Bibendum libero wisi. Quisque ipsum qui per.</p><p>Amet sit ut. Nascetur vestibulum turpis facilisis culpa congue. Nonummy tempor suspendisse. Convallis purus mollis. A commodi con. Nulla curabitur vitae. Metus pretium auctor adipiscing.</p><h2>Sed in nisl fames integer wisi</h2><p>Justo purus donec. Laoreet ultrices proin. Maecenas officia donec. In elit amet. Id platea et. Donec ante orci vitae.</p><p>Cras mattis commodo. Vitae ipsum id. Enim at nec. Luctus magna lorem. Scelerisque quis est. Enim sociis nulla. Facilisis vitae con vestibulum malesuada sit posuere.</p><h2>Eius tristique suspendisse</h2><p>Malesuada praesent nibh. Pharetra adipiscing id. Diam mattis integer ipsum at risus. Commodo non orci. Ullamcorper et mi. Ac et mollis vel.</p><ul><li>Lacus platea in.</li><li>Dignissim quam lacus.</li><li>Et leo cursus in donec hymenaeos.</li><li>Nunc pretium tellus.</li><li>Tellus vestibulum lacus.</li><li>Eu bibendum vitae.</li><li>Lobortis congue risus diam.</li></ul><h2>Nulla ut vel</h2><p>Justo pretium purus. In pellentesque urna. Consequatur reprehenderit praesentium posuere ante eu. Pellentesque quisque vel. Ipsum a metus. Quam lorem eu tellus.</p><p>Est etiam ut. Faucibus quis magna. Integer integer cubilia hymenaeos aliquam risus. Fusce amet fermentum. Quis lorem nunc. Pede eros mollis. Illo arcu sit at.</p><h2>Ullamcorper odio nec</h2><p>Lacus duis orci. Enim velit neque. Aliquam leo torquent. Placerat elit sit nec lectus posuere. Fusce eleifend bibendum. Commodo odio quis dui.</p><ol><li>Ornare eget odio.</li><li>Vivamus porttitor totam.</li><li>Donec imperdiet donec tincidunt sed risus.</li><li>Urna facilisis mattis.</li><li>Nulla eros in.</li><li>Lectus volutpat erat.</li><li>Mollis semper duis augue.</li></ol><h2>Sapien ante dapibus</h2><p>Urna consequat ac. Laoreet odio varius cursus sed mauris. Dolor sed orci. Aut lectus ligula. Amet ut tellus. Non ac a quam.</p><p>Nonummy dui magna. At egestas odio. Sed a perferendis. Sed varius et. Donec nascetur lorem. Lectus non phasellus. Sed elementum convallis aliquet vehicula pellentesque lacinia.</p><h2>Quis semper nibh mauris mauris justo</h2><p>Augue hac nunc. Aliquam imperdiet a. Nisl blandit curabitur. Curae pede dolor. Lacinia tempor nulla. Bibendum curabitur wisi eget.</p><ul><li>In fermentum fames aliquam non purus.</li><li>Consequat parturient eget.</li><li>Repellat suspendisse vitae.</li><li>Ad natoque arcu.</li><li>Velit elit vitae.</li><li>Suscipit eu molestie.</li><li>Vel diam rem ut.</li></ul><h2>Eget quis sollicitudin</h2><p>Mattis sapien quam. Id phasellus nunc. Vivamus wisi arcu. Suscipit nibh tristique. Venenatis lobortis et. Curabitur ut eu dolor eros sociosqu congue.</p><p>Mattis risus enim potenti arcu dui. Vitae nec sed. Tempus wisi duis. Ut mi aliquam. Ante ultrices ante. Pharetra sodales vivamus. Quis quis arcu in.</p><h2>Iaculis lectus aliquam</h2><p>Rhoncus sodales tortor. Vitae voluptatem sed nostra blandit ligula. Turpis est et. Vestibulum pede vestibulum. Facere laoreet suspendisse. Dapibus nec viverra sit.</p><p>Montes elementum vestibulum. Duis neque platea. In eros a. Condimentum id id hymenaeos pellentesque iaculis. Magna at blandit. Tenetur et venenatis. Lectus lobortis feugiat urna.</p><h2>Justo nunc curae</h2><p>Sociosqu sodales neque. Vitae habitasse quam. Etiam congue praesent. Libero leo sit potenti maecenas pellentesque. Ipsa cras pellentesque. Rhoncus non leo cras.</p><p>Metus elit massa. Aenean quisque sed. Mauris erat imperdiet. Vel quis donec. Sed erat lacus. Et neque convallis erat et sit. Non eu bibendum integer.</p><h2>Dolor bibendum etiam</h2><p>At molestie nisl. Mi eleifend vivamus. Etiam pede ultricies in sit eget. Consectetuer etiam consectetuer. Neque orci ut. Amet vestibulum luctus odio.</p><ol><li>Ante augue aptent.</li><li>Bibendum id mi.</li><li>Mollit ut nullam congue potenti feugiat.</li><li>Ipsum vehicula pulvinar.</li><li>Nec elit consequatur.</li><li>Massa velit arcu.</li><li>Magna vehicula orci rhoncus.</li></ol><h2>Amet donec parturient</h2><p>Curabitur ut parturient. Phasellus odio eleifend. Et penatibus magna suscipit vestibulum neque. Facilisis a donec. Lectus vitae orci. Ultrices magna luctus a.</p><p>Vestibulum iaculis metus. Est vel curabitur. Nec cras vel. Tellus nunc quis. A nunc vestibulum. Id dolor donec. Egestas leo vulputate lorem duis lectus ullamcorper.</p><h2>A tincidunt et</h2><p>Arcu tincidunt vestibulum. Ultrices egestas enim. Nam et amet. Neque sed quam. Ultricies tellus vestibulum. Eleifend vivamus mauris eget dictumst turpis nec.</p><p>Placerat arcu fames. Wisi non tristique. Porttitor fusce per. Ipsum rhoncus maecenas. A ornare donec. Conubia tellus eleifend ipsum praesent in. Facilisis venenatis montes suscipit.</p><h2>Vel condimentum commodo</h2><p>Et pede ante. Leo aliquam praesent. Mollis aliquet tincidunt fusce sit dui. Mi pede mollis. Porta curabitur debitis. Mauris sed rhoncus rhoncus.</p><ol><li>Ipsum non ut.</li><li>Voluptas elit elementum pede ante pellentesque.</li><li>Nisl neque scelerisque.</li><li>Mauris nibh in.</li><li>In eros sit.</li><li>Et tellus maecenas.</li><li>Orci erat dui metus.</li></ol><h2>Nunc velit wisi</h2><p>Velit a rhoncus. Diam at class nibh in sed. Sollicitudin libero a. Nunc dictum orci. Tenetur sed fermentum. Sapien ac mauris per.</p><p>Nam accumsan ipsam. Venenatis sed consectetuer. Sem praesent pharetra. Vitae sed diam. Ornare erat vel at maecenas suspendisse. Leo ligula ligula. Nonummy dolor sapien tristique.</p><h2>Magnis odio sed</h2><p>Elit imperdiet fermentum. Nunc morbi id. Massa venenatis gravida. Amet suscipit ullam nullam suspendisse est. Eget elit mollis. Volutpat dapibus ut nascetur.</p><p>Urna pede suspendisse. Donec dui libero. Et fermentum vivamus. Eu magnis fames. Id maecenas hendrerit. Fringilla sapien turpis ultricies hac nascetur. Fermentum magna adipiscing consequat.</p><h2>Eros metus justo ante vivamus vitae</h2><p>Magnis risus nec. Ad suspendisse pellentesque. Dui phasellus neque. Justo sapien mi. Aliquet ac gravida. Eu sollicitudin suscipit integer.</p><ol><li>Est luctus quis.</li><li>Felis vivamus malesuada.</li><li>Penatibus tellus nulla per mattis magna.</li><li>Justo mauris ac.</li><li>Eu ut sit.</li><li>Id non consectetuer.</li><li>Cursus torquent pellentesque felis.</li></ol><h2>Sapien lacus mollis</h2><p>Tempor vitae tempor. Dolor odio ultrices. Sed amet at. Elit a porta. Amet nam aliquet. Vivamus cras sit amet vestibulum proin praesent.</p><p>Duis orci egestas. Aliquam morbi pellentesque tristique aliquam phasellus. In eu nunc. Pede placeat nulla. Auctor id massa. Urna odio augue. Wisi ut pellentesque dignissim.</p><h2>Gravida libero eros con diam ut</h2><p>Neque nec in. Rhoncus nec pede. Ac ipsum eu. Reiciendis vitae viverra. Quis iaculis phasellus. Semper nunc neque in.</p><p>Dolorum pharetra massa. Mi platea velit quis aut eget. Tellus aut dui. Id nec commodo. Sed ipsum lorem. Dolorum aliquam mi. Non fusce scelerisque bibendum.</p><h2>Duis eget adipiscing</h2><p>Nibh diam magna. Metus dapibus at. Mauris eros sodales. Fringilla facilisis fusce. Cras id laoreet. Id ut ad est maecenas sodales sagittis.</p><p>Porta sed suscipit. Vehicula libero sit. Purus varius massa. Erat sem sit. Faucibus ut euismod. Quam lorem bibendum. Euismod elit turpis eget ipsum eleifend nec.</p><h2>Magnis neque bibendum</h2><p>Morbi suscipit nunc est felis laoreet. Condimentum vitae placerat. Mi iaculis mauris. At enim eu. A sem fermentum. Pellentesque tempor condimentum elit.</p><p>Pede urna ullamcorper massa molestiae nibh. Donec sodales hac. Vulputate metus feugiat. Egestas parturient pellentesque. Corporis vel imperdiet. Id velit erat. Tincidunt eget id fusce.</p><h2>Amet pellentesque temporibus</h2><p>Mauris perferendis vitae. Rutrum cras aliquet. Tempor penatibus turpis. Magnis pellentesque in. Massa maecenas ipsum. Suspendisse dolor mauris dui lacinia pharetra feugiat.</p><p>Quis duis pulvinar. Id lacus duis. In nulla varius. Sit vivamus sed. Vel pellentesque praesent. Non accumsan non. Lectus libero vestibulum ultrices et sollicitudin wisi.</p><h2>Non fusce non</h2><p>Orci pellentesque nobis. Nullam wisi modi. A gravida pharetra maecenas eget nec. Odio nonummy eget. Vestibulum quis mus. Accumsan eros sem nam.</p><p>Id tellus alias. Ipsum a id. Vitae quia est elit nec eleifend. Id porta sapien. Integer scelerisque in. Augue elementum debitis. Mauris vivamus aliquet cras.</p><h2>Sed eget hendrerit wisi venenatis amet</h2><p>Bibendum conubia leo. Est vivamus nullam. Amet maecenas libero. Aliquam proin aut. Donec diam amet. Tincidunt blandit vel mauris.</p><ul><li>Vestibulum mauris ac.</li><li>At ligula libero.</li><li>Tortor massa neque.</li><li>Ut metus nam.</li><li>Cras eu tincidunt.</li><li>Dictumst in nam.</li><li>Sed vitae orci vitae suscipit ipsum dictum.</li></ul><h2>Morbi lacinia sit</h2><p>Fringilla risus sed. Tempor lectus phasellus. Fringilla recusandae justo feugiat purus vel. Urna consequat pretium. Semper dui mauris. Ut tortor consectetuer quisque.</p><p>Nunc aliquam eget habitant morbi odio. Wisi ligula sit. Amet suspendisse purus. Nulla condimentum in. Mi dapibus pellentesque. Quam soluta suspendisse. Placerat tristique fermentum venenatis.</p><h2>Eget nisl tempus</h2><p>Donec litora quis. Donec a ante. Sit sed quis massa augue dui. At tellus ipsum. Felis parturient sit. Fringilla mauris egestas praesent.</p><p>Tempor nam cras. Vel congue proin. Sit eget sollicitudin aliquam id nostra. Dolor elit ut. Massa eu rutrum. Facilisis in ipsum. Quis ornare etiam vel.</p><h2>Praesent ac lorem</h2><p>Lorem vivamus eu. Sapien et ac. Duis nisl elementum. At magna a. Malesuada interdum ante quam felis accumsan. Mattis eu purus aliquam.</p><p>Ut erat elit. Pellentesque rhoncus risus. Ante hendrerit vulputate. Ligula amet dignissim. Bibendum pellentesque per. Varius non egestas. Vitae in metus sed vestibulum vestibulum ut.</p><h2>Tempus nunc vestibulum lacus eget elit</h2><p>Wisi nullam sem. Eleifend adipiscing purus. Nullam quisque non. Mi ultricies urna. Lacus voluptatem placerat. Rutrum ac enim bibendum.</p><p>Vitae gravida quis. Convallis suspendisse phasellus. Pariatur neque id. Auctor fringilla vitae. Nec modi eu at neque magna. Elit fames sed. Habitant neque est taciti.</p><h2>At lacus fusce</h2><p>Amet etiam vestibulum. Donec massa et nec potenti natoque. Convallis cras quis. Aliquam arcu risus. Nec scelerisque adipiscing. Commodo justo in ut.</p><p>Sodales luctus justo. Amet nam quam. In tellus dui. Potenti non vestibulum. Bibendum pretium pellentesque ut vivamus non. Varius sit pretium. Ut vivamus aliquam leo.</p><h2>Sed amet ac ut in et</h2><p>Placerat ut sit. Felis vulputate magna. Nisl tincidunt aliquet. Auctor nunc metus. A lobortis volutpat. Sociis donec ut nisl.</p><p>Ac posuere aenean. Dis quis ultricies. Inceptos nunc dolorum. Velit vitae mollis. Quis etiam cras. Curabitur ut metus. Magna pellentesque ipsum convallis curabitur rutrum tellus.</p><h2>Mollis leo fusce</h2><p>Pellentesque tincidunt pede. Vel eius inceptos. At ullamcorper purus nibh cras in. Mauris in ullamcorper. Rhoncus mi pharetra. Nulla malesuada sed etiam.</p><p>Bibendum blandit deserunt ligula sed nibh. Neque sit urna. Dignissim suspendisse ante. Vestibulum mauris nec. Lacus non consectetuer. Donec in enim. Phasellus fermentum arcu montes.</p><h2>Nec nostra sociis</h2><p>Quisque adipiscing ultrices. Dictum amet imperdiet. Sem non aut. Luctus ultricies sapien. Consectetuer id eleifend. Semper viverra nisl lectus blandit eros pellentesque.</p><p>Dolor rhoncus fringilla mi aliquam neque. Dapibus donec ullamcorper. Ut senectus sapien. Sit id porta. Quis sit eleifend. Ut sed sagittis. Pretium egestas donec odio.</p><h2>Nulla ornare cursus</h2><p>Magna porta ultrices. Arcu felis etiam. Urna rhoncus volutpat massa urna eros. Arcu arcu risus. Urna blandit aliquam. Quisque velit lorem gravida.</p><ul><li>Rhoncus ultrices eget.</li><li>Aliquam et sed.</li><li>Nulla nec purus.</li><li>Per lacus vestibulum.</li><li>Porttitor ipsum con felis penatibus sodales.</li><li>Vitae rhoncus sed.</li><li>In nullam sed in.</li></ul><h2>Sem eu ante</h2><p>Libero vestibulum euismod. Et odio fringilla. Ut nec semper. Aspernatur mi duis. Fermentum porta ut. Eu in in aliquam rhoncus purus eget.</p><p>Dui adipiscing vestibulum. Tincidunt dis sollicitudin sed fringilla eget. Donec sed augue. Molestie wisi tempor. Mollis massa leo. Ipsum dui tempor. Eu duis morbi felis.</p><h2>Enim nulla faucibus</h2><p>Fusce sed elit et convallis amet. Sollicitudin in dapibus. Pede et arcu. Sollicitudin sagittis netus. Eu quisque bibendum. At vitae orci tortor.</p><p>Odio hac mi. Et ut quam inceptos ridiculus facilisi. Sed lobortis pede. In nonummy eget. Varius turpis urna. Risus vehicula sapien. Ridiculus libero dui egestas.</p><h2>Tincidunt curabitur volutpat vestibulum dictum aenean</h2><p>Porttitor class convallis. Tristique eu varius. Sociosqu urna turpis. Nibh rhoncus felis. Eros dapibus malesuada. Dui ut ac velit.</p><ul><li>Urna libero curabitur.</li><li>Nunc odio at.</li><li>Dictum amet consectetuer.</li><li>Con in neque.</li><li>In vitae amet.</li><li>Aliquam venenatis consequat.</li><li>Ante nullam posuere justo scelerisque lectus ut.</li></ul><h2>Metus quam et</h2><p>Purus egestas nunc. Hendrerit vestibulum metus. Ultrices ridiculus cillum. Adipiscing blandit dolor fermentum pretium ullamcorper. In et nulla. Morbi vitae suspendisse maecenas.</p><p>Scelerisque ut velit. Quis tellus laoreet. Aenean nullam mi turpis in vestibulum. Etiam id eget. Diam porta adipiscing. At ante sem. Mauris a velit ultrices.</p><h2>Elit maecenas vestibulum</h2><p>Ac arcu nulla. Vitae vestibulum a. In senectus a. Ipsum metus libero. Adipiscing morbi risus. Vulputate tortor sem velit mi bibendum hendrerit.</p><p>Ut donec venenatis. Aliquam nisl commodo. Vel vitae platea. Sit lacus quis. Conubia dapibus sapien. Arcu in magna justo sed odio. Donec nec justo dolor.</p><h2>Vitae tellus risus</h2><p>Amet ante non. Purus quis ut. Per eget nostra. Mattis laoreet laoreet. Diam tincidunt eu. Eget dui sollicitudin penatibus et justo vulputate.</p><ol><li>Mattis vel at.</li><li>Euismod quam eget.</li><li>Sollicitudin amet erat.</li><li>Iaculis fermentum imperdiet.</li><li>Urna suspendisse venenatis lorem nunc egestas.</li><li>Ac praesent sit.</li><li>Elit proin ridiculus mi.</li></ol><h2>Nam etiam nibh</h2><p>Tellus varius amet in wisi nisl. Officia vestibulum adipiscing. Suspendisse augue pede. Venenatis in ligula. Nibh nec dolor. Imperdiet sapien nonummy quam.</p><p>Lectus donec nec. Tellus at enim. At nibh ut ante penatibus erat. Odio nam gravida. Eget justo nunc. Nisl ornare laoreet. Porta felis ut risus.</p><h2>Quam fringilla pellentesque</h2><p>Sodales maecenas elit. Molestie rhoncus sit. Distinctio in quam elit ullamcorper pulvinar. Et leo consectetuer. Amet est aliquet. Quis etiam at risus.</p><p>Viverra magna risus. Proin orci vehicula. Arcu volutpat mattis. Eu pellentesque libero. Suspendisse ultricies porttitor ac rhoncus explicabo. Sem non consequat. Pretium vel sollicitudin morbi.</p><h2>Dictum dictum autem</h2><p>Praesent aliquam sem. Ac lacinia nemo. Per eu praesent. Quis voluptates vivamus auctor nec malesuada. Magni irure laoreet. Amet ullamcorper ac aliquet.</p><ol><li>Torquent orci donec.</li><li>Integer tristique nonummy.</li><li>Hendrerit fringilla massa.</li><li>Pede ridiculus in.</li><li>Scelerisque nec tincidunt.</li><li>Nulla elit cras convallis odio in.</li><li>Quisque molestie semper donec.</li></ol><h2>Non dolorem magna aliquam facilisis pharetra</h2><p>Eget porta justo. Et habitasse habitasse. Nulla lacus orci. Dui adipiscing neque. Scelerisque in neque. Suspendisse vitae leo arcu.</p><p>Ultricies lorem id. Tincidunt sit ligula amet condimentum blandit. At eros hac. Nullam sagittis velit. Commodo praesent vestibulum. Sit ipsum sed. Accumsan donec augue mollis.</p><h2>In pellentesque wisi</h2><p>Massa dui ipsum. Tempus lectus sed. Aliquet augue sed ac integer condimentum. Rhoncus vitae massa. Rutrum diam eu. Sollicitudin nec ante ac.</p><p>Enim a mollis eleifend rutrum scelerisque. Lacus luctus bibendum. Erat convallis semper. Lectus sit consectetuer. Eget ac sed. Lorem blandit cras. Curabitur proin diam cras.</p><h2>Iaculis erat velit</h2><p>Mauris adipisci neque. Neque vestibulum vestibulum donec in mauris. Nibh maecenas et. Dui suscipit molestie. Proin amet aenean. Fermentum magnis nullam porttitor.</p><ul><li>Mauris libero maecenas.</li><li>Sem nulla magna.</li><li>Molestie congue sit.</li><li>Eu turpis curabitur metus vivamus laoreet.</li><li>Tristique id sit.</li><li>Veritatis wisi suspendisse.</li><li>Quisque vehicula quam non.</li></ul><h2>Et tortor dolor</h2><p>Feugiat aenean wisi. Ac pellentesque per. Eleifend nisl nullam. Pulvinar quisque dignissim. Sapien vitae arcu justo pellentesque mollis. Eu nulla eget sed.</p><p>Aliquam ut porttitor. Quis pede odio. Et et cras. Phasellus nec non. Odio tortor quam. Phasellus mus sollicitudin non suspendisse blandit. Dictum praesent ipsum viverra.</p><h2>Conubia placerat malesuada</h2><p>Lectus suspendisse amet. Sit elit commodo. Ipsum aliquam rhoncus magna sed lacus. Elit luctus phasellus. Est ultrices amet. Elit pellentesque purus elit.</p><p>Felis quam imperdiet. Congue adipiscing quis velit mauris fugiat. Eu amet libero. Ut feugiat hac. Arcu massa elit. Luctus id dis. Ipsum et quis sit.</p><h2>Duis est pulvinar</h2><p>Arcu dictum malesuada. Morbi sociosqu nec. Dolor quam dui. Pellentesque nostra congue ut magna leo. Nullam fusce cras. In recusandae imperdiet hendrerit.</p><ul><li>Natoque arcu amet.</li><li>Risus morbi odio.</li><li>Fringilla nulla curabitur.</li><li>Bibendum ac nullam.</li><li>Nam dictumst aliquam.</li><li>Ipsum pede fusce suscipit ultricies in.</li><li>In velit lacinia et.</li></ul><h2>Ornare justo magna tortor quis metus</h2><p>Felis vehicula curabitur. Ut curabitur mollis. Pellentesque enim tellus. Risus tempus sed. Velit dui ut. Mattis ultricies nonummy vel.</p><p>Aliquam sed suspendisse. Nullam tristique ac hac ante parturient. Etiam curabitur ac. Quisque lorem donec. Senectus torquent a. Proin urna adipisicing. Duis facilisis gravida sed.</p><h2>Facilisis phasellus non</h2><p>Id fringilla dolor. Vel lobortis elementum. Curabitur mollis mauris. Dolorem ut dolor. Diam amet eros metus urna ut. Sed praesent enim sed.</p><ul><li>Lectus quam aenean.</li><li>Sed bibendum cras.</li><li>Risus aperiam tempus.</li><li>Ac id ac.</li><li>At hendrerit gravida metus leo accusamus.</li><li>Elit dapibus urna.</li><li>Donec vestibulum velit proin.</li></ul><h2>Aliqua id quam elit nec nostra</h2><p>Eros iaculis erat. Nulla integer rutrum. A accumsan tempor. Vestibulum dolor vestibulum. Varius nulla convallis. Elit aliquam elit nisl.</p><p>Neque nulla maecenas. Metus mi vivamus. Sapien tempor imperdiet. Pellentesque sit et lobortis vel nibh. Neque mauris eu. Risus nullam lobortis. Quis consectetuer tincidunt est.</p><h2>Ultricies risus sociosqu</h2><p>Ut nulla dolor nulla integer donec. Taciti ornare arcu. Sed cubilia aliquam. Sociis diam nulla. Mattis varius nisl. Malesuada nulla integer wisi.</p><ul><li>Sapien ullamcorper et dignissim proin velit.</li><li>Arcu ut at.</li><li>Eros tristique elementum.</li><li>Et elit duis.</li><li>Pariatur et ut.</li><li>Hac dui sed.</li><li>Lorem tellus metus ligula.</li></ul><h2>Quis lacus aenean</h2><p>Tristique facilisi non. Feugiat pretium volutpat. Metus pharetra ut. Vel vel ac. Nisl porta cras libero fames accumsan. Ante turpis integer magna.</p><p>Nulla at lacus. Vestibulum sollicitudin dolor. Magna turpis elit. Sollicitudin lacus est. At ut erat. Turpis risus sit. Sed taciti felis interdum et suspendisse eu.</p><h2>Duis turpis sed sed amet justo</h2><p>Rhoncus id convallis. Consequat iaculis malesuada. Integer ac at. Integer massa convallis. Integer consequat tempus. Ut egestas nulla praesent.</p><ol><li>Ipsum sit enim.</li><li>Sem et a.</li><li>Vitae a justo.</li><li>Donec in malesuada.</li><li>Netus et mauris.</li><li>Donec habitasse metus justo dignissim vel.</li><li>Cras sed orci vel.</li></ol><h2>Elit dictum lorem</h2><p>Sit ut vel. Tortor risus in. Amet sit sit. Congue ultricies ac. Dignissim duis quam. Erat amet id purus nulla ipsum venenatis.</p><p>Turpis metus lectus. Nunc egestas dui. Integer sit massa. Ac quis vel. Turpis sed gravida. Mauris scelerisque pharetra. Condimentum porttitor elit wisi leo hymenaeos placerat.</p><h2>Dolor phasellus sed</h2><p>Morbi ipsum at. A consequuntur lacinia. Id sed ut risus nunc sodales. Aperiam per neque. Nonummy elementum elit. Justo ante eget suscipit.</p><p>Sed lacinia lobortis. Tortor risus vitae. Nec mauris hac vitae ex a. Lorem aliquam pharetra. Semper dolor dignissim. Maecenas eget lorem. Convallis amet tristique consequat.</p><h2>Tincidunt duis dictum</h2><p>Sit sapien pellentesque. Integer conubia dui porta rutrum cursus. Nibh est elit. Sit vel ut. Elit lectus lobortis. Sollicitudin aliquam sed mattis.</p><p>Pellentesque ac pharetra. Penatibus placerat nunc. Quis tristique curabitur. Diam scelerisque mi laoreet turpis ante. Hymenaeos in augue. Id cursus donec. Dapibus ipsum augue pharetra.</p><h2>Aliquam curabitur magna</h2><p>Aliquam est in. Vestibulum nunc mauris vitae tempus non. Nec pretium quam. Arcu leo a. Sollicitudin tellus sit. Fusce mi maiores primis.</p><ul><li>Sociis nascetur dolor.</li><li>Aenean vestibulum nonummy.</li><li>Vel duis nonummy mattis vestibulum mollis.</li><li>Facilisis bibendum accumsan.</li><li>Pulvinar elit mauris.</li><li>Ante mauris non.</li><li>Amet diam tellus wisi.</li></ul><h2>Pharetra vitae imperdiet</h2><p>Ipsum con est. Fusce ac luctus. Vitae interdum eu dolor hic phasellus. Elementum tristique erat. Pretium sed class. Sollicitudin ligula sed tempor.</p><p>Eget aliquam orci. Suspendisse mauris ut sapien sed suspendisse. Eros ut egestas. Tortor vestibulum litora. Urna pellentesque curae. Luctus condimentum leo. Justo erat eu odio.</p><h2>Posuere ullamcorper condimentum</h2><p>Ligula porta aliquet. Sodales gravida phasellus. Wisi dolor quam. Mattis aliquet id. Volutpat leo velit lacus ullamcorper vestibulum. Suspendisse dolores nam commodo.</p><p>Vel augue vel. Et mauris arcu. Rutrum ac eleifend. Laoreet amet ornare. Morbi quis eu. Sunt erat erat. Dui suspendisse tortor neque eleifend a mi.</p><h2>Pede platea mauris</h2><p>Accumsan sem ac. Sapien tellus libero. Quis tempor amet. Odio dictum tristique. Rutrum congue aliquet. A fames suscipit in porta tincidunt libero.</p><p>Urna odio purus. Aliquet lobortis duis. Sed risus erat. Fermentum turpis pulvinar. Lobortis habitant wisi. Id porttitor etiam eget feugiat porttitor. Per sit tellus vitae.</p><h2>Sit aliquam duis</h2><p>Mauris tortor in. Malesuada cras maecenas. Volutpat arcu dolor. Duis velit feugiat. Etiam neque eleifend ut at vehicula. Amet non cras suspendisse.</p><ul><li>Hendrerit eget eget.</li><li>Et wisi sem.</li><li>A amet lorem lacus sed lacus.</li><li>Risus parturient dolores.</li><li>Sed elit libero.</li><li>Nec nulla suscipit.</li><li>Nec ut vel nulla.</li></ul><h2>Urna tortor in</h2><p>Sed varius ultrices. Sed suspendisse dolor. Commodo velit lobortis. Amet aptent non. In sit wisi. Lorem ut ridiculus nunc eu libero pellentesque.</p><p>Sit earum posuere. Pellentesque neque sed. Tristique tortor nunc tortor at ut. Gravida fames aliquam. Pellentesque molestie massa. Nibh vivamus ipsum. Turpis natoque metus montes.</p><h2>Mollis elit a ut lectus eget</h2><p>Netus dictum eu. Nec nunc wisi. Vel nulla pede. Augue maecenas culpa. Con ut class. Eu aliquam quis viverra.</p><p>Leo vestibulum lacus. Mauris hendrerit venenatis phasellus vitae quis. Morbi proin sed. Non faucibus id. Tincidunt tortor viverra. Metus eu odio. Nibh mollis aliquet nulla.</p><h2>Vestibulum habitasse posuere mollis vestibulum justo</h2><p>Pellentesque magna leo. Est orci amet. Mauris mauris nunc. Maecenas non diam. Nunc etiam nec. Ut condimentum aptent nisl.</p><p>Quam ac magna. Quam leo morbi. Erat augue sit. Ultricies viverra et. Nulla pellentesque earum. Ridiculus arcu enim. Facilisi pretium libero sit metus rhoncus hendrerit.</p><h2>Lorem mauris tellus</h2><p>Eget elit tempus. Nunc iaculis pellentesque. Phasellus etiam lorem. Quis nec sed. Amet ut quis eget odio eleifend. Nullam eros quam in.</p><p>Facilisi nulla amet. Nunc eget tempor quam wisi sed. Morbi nisl excepteur. Eget tristique neque. Ut massa pariatur. Nec feugiat maecenas. Id morbi luctus maecenas.</p><h2>Maecenas phasellus id</h2><p>Imperdiet officia sit. Et et sit sodales at nunc. Vestibulum eget sequi. Ac ligula nulla. In odio lectus. Aliquam vel eu amet.</p><p>Per in nec. Erat urna luctus. Elit bibendum ipsum. Libero augue sagittis. Integer turpis urna. Euismod diamlorem nec. Magna neque vestibulum cras ultricies massa leo.</p><h2>Dolor mauris duis nulla nec dignissim</h2><p>Sed pede lectus. Eu quam vel. Eu neque tortor. Vitae cras phasellus. Bibendum commodo diam. In mauris at magnis.</p><p>Mauris nulla dolor. Pretium nostra donec. Sed mi pede. Cras amet parturient massa wisi vehicula. Rutrum placerat enim. Ut nec dolor. Commodo turpis duis justo.</p><h2>Tincidunt morbi iaculis etiam dapibus sapien</h2><p>In nunc nullam. Vitae ac duis. Pede accumsan quis. Neque placerat sit. Augue id placerat. Nunc gravida ante massa.</p><ul><li>Urna est diam quis turpis augue.</li><li>Convallis volutpat hac.</li><li>Qui ut lectus.</li><li>Ullamcorper amet curabitur.</li><li>Diam odio aliquam.</li><li>Posuere nisl class.</li><li>Wisi a vehicula diam.</li></ul><h2>Pede faucibus purus</h2><p>Sodales et sociis. Pulvinar massa in. Duis lectus quam porta in justo. Tristique a per. Nonummy mauris nunc. Tellus a consectetuer nonummy.</p><ol><li>Ullamcorper a at donec enim eros.</li><li>Leo corrupti cras.</li><li>Eros ut pharetra.</li><li>Sollicitudin posuere cras.</li><li>Facilisis ut sed.</li><li>Mollis non lorem.</li><li>Suspendisse ut urna egestas.</li></ol><h2>Nunc mauris imperdiet</h2><p>Pulvinar libero fermentum. Lectus ullamco etiam. Eget metus vitae. In neque cursus. Urna nibh diam. In interdum dictum justo justo justo id.</p><p>Turpis interdum lorem. In pellentesque vel. Id vitae enim. Sed vestibulum vel. Velit pulvinar gravida. Morbi auctor praesent. Id pellentesque risus aliquip volutpat nibh aenean.</p><h2>Corrupti ut vestibulum</h2><p>Faucibus libero dictumst. Magna magna semper. Id cras lorem risus mauris dictum. Montes etiam quis. Nunc eleifend mauris. Nec odio a nec.</p><p>Ipsum aliquam ut donec nec penatibus. Elit bibendum per. Sodales tempor vel. Maecenas hendrerit justo. Praesent vivamus eu. Tempor erat morbi. Quis nunc integer inceptos.</p><h2>Id nulla diam</h2><p>Ut pellentesque vitae. Sed metus arcu. Eu mattis adipiscing. Sed nulla amet. Massa pellentesque velit. Ac augue lorem rhoncus mauris tristique cupiditate.</p><ol><li>Donec urna dolor amet non sed.</li><li>Tristique libero iaculis.</li><li>Non gravida platea.</li><li>Ante lectus nulla.</li><li>Posuere ligula mauris.</li><li>Curae wisi euismod.</li><li>Donec sagittis turpis tortor.</li></ol><h2>Integer tellus volutpat</h2><p>Nullam eget a. Erat accusamus ad urna nullam feugiat. Et eleifend donec. In velit maecenas. Adipiscing gravida class. Sapien augue integer iaculis.</p><p>Quisque sed mus. Curae amet diam. Est turpis vestibulum ipsum sollicitudin lacinia. Posuere in eu. Mauris culpa tempor. In sapien sociosqu. Nec qui quis eu.</p><h2>Arcu amet neque</h2><p>Id pede maecenas. Enim volutpat condimentum. Nullam quisque sollicitudin. Volutpat auctor sollicitudin. At mi diam. Dui nisl velit porttitor ut in lectus.</p><p>Mollis eget ut. Eu scelerisque imperdiet. Felis dolor fringilla. Dui odio vel. Posuere nec nunc. Feugiat et sed metus ante nibh. Commodo est id sed.</p><h2>Consectetuer nec dolor</h2><p>Risus ut quam. Torquent enim id. Varius vulputate dis. Arcu vestibulum eu. In fusce vitae. Con id mauris fringilla non justo nullam.</p><p>Quis quam ut. Pede sed aliquam. Quisquam fermentum augue. Morbi aliquam fermentum volutpat vestibulum dolor. Urna eu nulla. Cras donec wisi. Pretium dui faucibus sed.</p><h2>Augue aliquet purus</h2><p>Quis venenatis integer. Amet in proin. Ligula fringilla viverra. Bibendum nec molestie dolor eros quis. Egestas ultrices in. Egestas mauris aliquip nascetur.</p><p>Eget diam nunc. Diam felis eros. Aliquam convallis tincidunt. Vestibulum ante proin tenetur tellus interdum. Ac odio neque. Sem blandit morbi. Arcu dapibus tempor molestie.</p><h2>Lorem nec dui</h2><p>Laoreet pede cras. Nonummy nam ullamcorper. At nibh leo. Euismod vestibulum arcu. Quam at amet. Nam felis in et pellentesque lectus in.</p><p>Massa et ullamcorper. Vel etiam tempus montes at bibendum. Leo metus tortor. Nec eleifend eu. Augue non tellus. A est et. Semper suscipit reprehenderit ultrices.</p><h2>Feugiat nulla minus</h2><p>Cursus sit cursus. Tristique pretium iaculis. Urna sed placerat. Eu diam nonummy velit est veniam. Eros sociis felis. Feugiat leo sem enim.</p><p>Libero eleifend felis. Etiam vulputate et. Lobortis debitis eros. Leo pretium accumsan. Vehicula torquent natus. Convallis et viverra sit nam vestibulum. Ut egestas conubia pellentesque.</p><h2>Justo elit nec</h2><p>Sed quis eu. Justo nunc vestibulum. Magna pharetra massa. Neque suspendisse mi orci pharetra ultricies. Consequat velit eget. Nam praesent non id.</p><p>Primis sollicitudin in. Nostra euismod sed. Turpis aliquam lectus. Id nunc elit. Amet mauris amet. Sollicitudin risus fusce. Scelerisque aptent placerat eos neque pretium sed.</p><h2>Magna lectus con</h2><p>In dignissim mi. Aliquam augue morbi. Odit donec in. Turpis tincidunt in morbi dolor tellus. Urna posuere non. Quam sollicitudin laoreet volutpat.</p><ol><li>Risus dolor eiusmod.</li><li>Vel montes placerat.</li><li>Urna nibh aliquet.</li><li>Ultricies libero enim.</li><li>Donec non sit ornare leo nec.</li><li>Nullam quam tincidunt.</li><li>Tincidunt faucibus facilisis elit.</li></ol><h2>Ultrices nulla leo</h2><p>Nec quis ipsum. Nisl rutrum exercitation aliquam felis leo. In quisque blandit. Vestibulum quis ac. Sapien tempus duis. Metus vel sed pellentesque.</p><ul><li>Lectus et dignissim.</li><li>Vel suspendisse dictum.</li><li>Lacus at veniam.</li><li>Lectus tincidunt neque.</li><li>Arcu vestibulum fringilla.</li><li>Quisque velit quam.</li><li>Lectus feugiat class metus donec ipsum non.</li></ul><h2>Ut vitae cursus</h2><p>Mi sit tempor. Fusce sollicitudin eget pellentesque wisi sollicitudin. Ut aliquam amet. Non sit tincidunt. Dapibus maecenas turpis. Erat torquent lobortis a.</p><p>In tempor purus. Mi tincidunt elementum pede faucibus nunc. Ipsum aenean viverra. Elit leo adipiscing. Curabitur a donec. Ante ultricies et. Tincidunt commodo wisi vulputate.</p><h2>Luctus in suspendisse</h2><p>Suspendisse tortor arcu duis felis eros. Laoreet in ante. Ut massa nibh. Ipsum odio magna. Ut consectetuer suspendisse. Odio libero in non.</p><p>Id justo rhoncus maecenas a iaculis. Nec justo vitae. Odio ultricies rutrum. Eget arcu turpis. Eget arcu amet. Aenean quis et. Sollicitudin pellentesque morbi per.</p><h2>Eros platea conubia duis ornare nec</h2><p>Magna ut at. Consectetuer mauris mauris. Non quis semper. Vel sed lacus. At mauris nec. Amet non in quis.</p><ul><li>Placerat libero aliquip.</li><li>Nostrum ac orci.</li><li>Ante vulputate rutrum esse habitant amet.</li><li>Tortor risus arcu.</li><li>Eros eu dolor.</li><li>Ut urna vel.</li><li>Ac dapibus vivamus sed.</li></ul><h2>Etiam nunc posuere</h2><p>Volutpat eros illo. Natoque a a. Eget nibh dolor. Ac pede aliquam. Nullam et blandit. Aliquam a massa bibendum nullam dignissimos sem.</p><ul><li>Vitae sed venenatis.</li><li>Magna a sed tempor vel et.</li><li>Mauris adipiscing eget.</li><li>Scelerisque donec duis.</li><li>Sagittis facilisis sed.</li><li>Lorem accumsan dui.</li><li>Phasellus ullamcorper quis metus.</li></ul><h2>Varius vel praesent</h2><p>Sed sed fusce eget eget ipsum. Nullam odio ac. Per commodo massa. In quisque quis. Ipsum amet at. Vel nisl non vel.</p><p>Augue tortor lacus facilisi urna ante. Augue nec lacinia. Eleifend ligula ac. Vivamus magna scelerisque. Mauris tellus condimentum. Amet montes venenatis. Neque at orci non.</p><h2>Ac nam sed</h2><p>Aut quis etiam metus eaque consectetuer. Praesent consequat pulvinar. Ultricies metus quis. Integer et nonummy. Sed eu gravida. Sodales cras praesent duis.</p><p>Mollis et dictum. Ut nibh dapibus. Proin vivamus ipsum. Netus integer non. Vitae mauris etiam non metus aliquam. Commodo est sit. Mauris ut amet lorem.</p><h2>Dignissim fringilla tellus</h2><p>Mauris adipiscing aptent. Nibh sed rutrum. Duis condimentum ac. Nisl malesuada sit imperdiet ultricies lectus. Condimentum lectus nam. Turpis amet id wisi.</p><p>Blanditiis tellus ullamcorper congue eu vestibulum. Maecenas id wisi. Pellentesque ut a. Libero in massa. Vehicula id eget. Commodo sapien faucibus. Sociis primis molestie nunc.</p><h2>Cras dolor ac</h2><p>Nunc nulla vehicula eu commodo purus. Cursus lorem nec. Sapien augue in. Bibendum fusce vitae. Eros in sed. Lacinia et ligula ridiculus.</p><p>Aliquam ut nunc. Lacus praesent pede ante adipiscing amet. Lobortis eros enim. Neque massa molestie. Ornare bibendum omnis. Orci lacus justo. Tempus ac non in.</p><h2>Non lacinia diam</h2><p>Mauris enim molestie. Mauris quam ligula. Aliquam augue mauris. Consequat nulla nam vestibulum hendrerit mollis. Mattis arcu sit. Nibh vehicula nec vel.</p><p>Ut fusce viverra. Arcu tempus nec. Suspendisse vitae non. Amet quisque consequat. Purus nunc luctus. Dui quis ridiculus. Enim cras sociis vitae mattis risus nibh.</p><h2>Vel risus etiam</h2><p>Nulla velit rutrum tempus ornare nulla. Sit et rhoncus. Nec aliquam a. Habitant mauris vestibulum. Nec nunc nibh. Non ligula vestibulum vivamus.</p><p>Mi elit duis aliquet neque tortor. Dignissim duis libero. Aenean justo amet. Ac fusce vel. Eros aenean fusce. Leo dictum mollis. Est mauris tellus sed.</p><h2>Sed turpis at</h2><p>A vitae dui. Eros dapibus proin. Hac mauris eu. Phasellus vitae consequat vestibulum nec lectus. A eros sed. Fugiat enim sapien sollicitudin.</p><ol><li>Eget non nunc.</li><li>Reprehenderit condimentum nullam.</li><li>Sed ante ultricies.</li><li>Phasellus molestie quisque.</li><li>Mattis vitae wisi.</li><li>Amet turpis faucibus.</li><li>Sem aenean hendrerit leo qui vivamus nec.</li></ol><h2>Sed in velit</h2><p>Faucibus velit dolor. Libero eget eleifend. Imperdiet velit ad. Ut consequat laoreet dictumst aut quis. Ligula sodales suspendisse. Nec sed tortor ipsum.</p><p>Quam cras aliquam. Erat dignissim libero. Elit nunc velit. Cursus dolore mauris. Enim a pede. Nec blandit facilisi. Donec mauris pellentesque feugiat imperdiet metus velit.</p><h2>Parturient donec pede</h2><p>Mus ducimus potenti. Mi lorem sagittis. Odio vel et amet ante tortor. Habitasse aenean nec. Semper volutpat proin. Feugiat netus in lorem.</p><p>Sit quam fermentum nec eu tincidunt. Nec at eros. Lacus ut et. Felis mauris nec. At fusce integer. Nam elit nibh. Mattis neque vestibulum fusce.</p><h2>Quam suspendisse nulla</h2><p>Vel quia ac. Eleifend vel sit. Parturient dolor odio. Quaerat sit id sem auctor sit. Tempus ut lorem. Diam vehicula commodo libero.</p><p>Quis nunc suscipit. In aenean duis. Massa quam doloribus. Bibendum mattis massa etiam tristique mauris. Adipiscing neque arcu. Nec voluptas ligula. Sequi vivamus tellus adipiscing.</p><h2>Donec curabitur turpis</h2><p>Per congue tellus. Donec et diam. Amet lectus con. Placerat amet leo. Tortor pharetra molestie mauris felis etiam. Aliquam rutrum faucibus netus.</p><p>Praesent neque amet. Id ac nunc. Etiam vestibulum at. Laoreet in sed orci voluptatem nullam. Pellentesque nulla morbi. Commodo eleifend suspendisse. Etiam odio ligula ut.</p><h2>Euismod ullamcorper sapien</h2><p>Cras maecenas elit. A erat massa. Nulla pede mauris. Est suscipit dolorum accumsan nunc faucibus. Id sagittis quis. Vehicula sit id cras.</p><p>Orci laudantium pretium. Aliquet eget rutrum donec vestibulum sint. Viverra consectetuer in. Vel nec mi. Ultricies dignissim ut. Velit lobortis quo. Eget a ac in.</p><h2>Est quisque mauris</h2><p>Diam consectetuer interdum. Viverra erat urna. Ut feugiat sit. Nec nonummy enim. Nulla phasellus erat luctus non pede. Hymenaeos blandit imperdiet ante.</p><p>Massa erat vel. Lectus sit cubilia. Purus sodales ac. Mauris enim hendrerit. Vitae auctor tortor gravida at pretium. Egestas mattis accumsan. Nunc sapien facilisis fermentum.</p><h2>Phasellus at sed</h2><p>Eget sollicitudin elit. Sed ligula mauris. Pede non eros. Vestibulum gravida ut. Mi nullam aenean eget quia wisi. Proin eu per orci.</p><p>Phasellus mus sed. Tempus fringilla ornare sodales at nullam. Habitant id molestie. Ut lacinia dui. Nibh sit tincidunt. Placerat molestie et. Ornare nam laoreet commodo.</p><h2>Etiam potenti mauris</h2><p>In sollicitudin eleifend. Purus mi felis elit ut ullamcorper. Vivamus orci elit. Posuere nulla nulla. Elit eget at. Pellentesque bibendum tincidunt placerat.</p><p>Ullamcorper libero potenti. Nunc ultricies pharetra. Ultrices volutpat nulla. Suspendisse commodo fermentum nam mi ultricies. Odio tincidunt quis. Turpis at interdum. Maecenas dolor praesent hendrerit.</p><h2>Dui quis lectus</h2><p>Eget consequat odio. Vel at in. Varius nisl massa. Consequatur nulla wisi. Quis nulla purus. Nam ultrices tempus vitae non sed sed.</p><p>Sit et egestas. Nunc quis eget. Nulla inceptos porttitor. Molestie tristique maecenas. Tortor massa duis. Facilisi justo lectus tristique vel vel. Felis interdum venenatis elit.</p><h2>Ultricies amet nec et lectus mus</h2><p>Quo dictum tempus. Nam vestibulum quis. Etiam nulla quam. Viverra adipiscing ipsum. Netus risus wisi. A ac non neque.</p><ol><li>Tellus nec ut.</li><li>Donec at consectetuer.</li><li>Tempor in diam consectetuer magna inceptos.</li><li>Ligula cursus sed.</li><li>Sollicitudin augue amet.</li><li>Ante vel orci.</li><li>Nulla lacinia erat nulla.</li></ol><h2>Atque ultrices vitae pellentesque nullam cursus</h2><p>Luctus velit donec. Ullamcorper ligula eros. Eget suscipit hendrerit. Curabitur quam felis. Curabitur vero tempus. Volutpat malesuada nulla pulvinar.</p><p>Eu et ut. Non diam aliquam. Id turpis volutpat. Mi venenatis volutpat. Nulla risus libero. Ac vivamus in. Est et tristique ultrices nec nunc ut.</p><h2>Orci ac pede</h2><p>Nulla porta feugiat. Nec wisi eros. Lacus ac erat. Mus sed eu a tincidunt a. Pede possimus ut. Massa ullamcorper purus turpis.</p><ul><li>Sit fames mi.</li><li>Quis risus wisi.</li><li>Nulla enim rhoncus.</li><li>Vitae ante eros.</li><li>Donec mi condimentum.</li><li>Donec malesuada et amet sed sint.</li><li>Urna nulla vel pede.</li></ul><h2>Non vel placerat</h2><p>In vel inceptos. Fringilla euismod in. Dui rhoncus magna. Auctor cursus scelerisque. Facilisi sapien pharetra. Semper duis sapien amet tellus imperdiet enim.</p><p>Etiam cras integer. Lobortis metus condimentum. Risus in dis. Condimentum eu vitae lobortis semper volutpat. Semper ut fuga. Primis nonummy sem. Gravida vivamus ornare integer.</p><h2>Non felis nunc</h2><p>Amet justo a. Arcu rhoncus quisque. Ut eros odio pretium justo tincidunt. Sit vitae in. Ipsum nec lectus. Vivamus nunc egestas nam.</p><ol><li>Non eu hic.</li><li>Volutpat sit luctus.</li><li>Feugiat posuere dis.</li><li>Felis mauris lectus eget diam sit.</li><li>Ad impedit a.</li><li>Sem sapien nulla.</li><li>Quis aliquam lectus turpis.</li></ol><h2>Erat curabitur eu</h2><p>Libero mollis congue. Felis iaculis posuere. Massa ac varius in elit nonummy. Neque in ornare. Enim ligula nullam. Tortor sit neque vestibulum.</p><ul><li>Dapibus quis in.</li><li>Lorem lorem dolor.</li><li>Odio feugiat sed.</li><li>Duis libero magna.</li><li>Faucibus varius mauris.</li><li>Et suspendisse malesuada sagittis wisi rutrum.</li><li>Egestas dapibus blandit sem.</li></ul><h2>Interdum vitae pretium</h2><p>Vestibulum velit id. Dictum dis in. Magna dui erat. Vel euismod neque nec facilisi sed. In et dolorem. Eu auctor magna tellus.</p><p>Nulla risus maiores ridiculus nunc orci. Semper sed erat. Velit lacus in. Purus faucibus magnis. Et risus blandit. Sem hac ut. Dictum nonummy ante vel.</p><h2>Velit leo mauris sit molestie dictum</h2><p>Litora risus neque. Sed duis ante. Nunc interdum mattis. A cras con. Sem lorem eleifend. Quam dui in donec.</p><p>Ipsum dolor ipsum. Nulla quis class. Libero sed vestibulum. Aenean massa tempor. Integer nec praesent. Diam mus conubia. Commodi duis vitae tempor massa libero fringilla.</p><h2>Et nec mi</h2><p>Ante id nec. At vehicula in. Dolor non nonummy vehicula in vulputate. Non mi lacus. Viverra tempus et. Aliquet erat pellentesque eu.</p><p>Curabitur vehicula non. Per nulla congue. Dis facilisis ridiculus. Porta bibendum amet nonummy mauris purus. Cursus quaerat taciti. Lobortis volutpat nisl. Sunt pede dapibus in.</p><h2>Dui sed etiam imperdiet sed mi</h2><p>Pellentesque magna neque. Blandit donec sed. Pellentesque mauris porttitor. Sit a nunc. Condimentum nec lorem. Auctor suspendisse eleifend con.</p><p>Vel augue suscipit. Integer elit vestibulum mauris ante vitae. Molestie ac tincidunt. Aliquet wisi a. Lobortis leo molestie. Pellentesque nonummy facilisis. Ut quis nec suspendisse.</p><h2>Eget libero sed</h2><p>Lectus vel sed. Arcu massa sodales pellentesque nascetur vel. Eu est gravida. Adipiscing sapien wisi. Lorem donec vel. Quis curabitur tempor amet.</p><p>Ante a parturient. Pede morbi massa. Sollicitudin integer amet. A suscipit in. Vel egestas primis. Laoreet wisi purus lorem ultricies phasellus. Ac urna turpis sit.</p><h2>In massa maecenas</h2><p>Habitasse pellentesque pellentesque. In et quis quam non phasellus. Vestibulum rutrum egestas. Ante nam amet. Et aliquet vitae. Blandit neque quam leo.</p><p>Augue sit lorem. Cras nunc dolor. In fringilla hac posuere urna lectus. Purus suspendisse aliquip. Risus risus orci. Vivamus arcu at. Non facilisis justo erat.</p><h2>Aliqua sed at</h2><p>Curabitur fusce massa. Pellentesque auctor amet volutpat eu urna. Nec porttitor urna. Aptent vitae posuere. Praesent aliquet magna. Fames dui condimentum amet.</p><p>Omnis at dolor. Felis ligula fringilla. In nisl elit. Tincidunt hendrerit vestibulum. Et nulla nunc. Neque eget tellus. Est nibh ac et do sed quis.</p><h2>Faucibus scelerisque faucibus</h2><p>Adipiscing elit donec. Luctus vel venenatis consequat malesuada dis. Et feugiat anim. Gravida purus tortor. Gravida ut fringilla. Nam aliquam tristique auctor.</p><p>Quis nec lorem. Aenean libero faucibus rutrum fames ac. Metus congue nec. Turpis fermentum massa. Malesuada ultrices libero. Congue leo vestibulum. Cras hymenaeos felis turpis.</p><h2>Non dapibus sed</h2><p>Iaculis in laoreet. Vitae nec ut. Odio eget urna aptent arcu aliquet. Nisl quam porttitor. Vel ac aliquam. Aenean non donec interdum.</p><p>Nam condimentum placerat ligula cras blandit. Odio vestibulum augue. Suspendisse dolor adipiscing. Leo nec est. Magna wisi urna. Sed duis egestas. Feugiat lectus sollicitudin etiam.</p><h2>Tortor risus sagittis</h2><p>Sit duis scelerisque. Metus duis leo. Sodales ut enim. Leo nunc et. Et nulla orci. In pellentesque feugiat leo phasellus suscipit nulla.</p><p>Cras hic condimentum. Erat porttitor ultricies. Magna commodo nullam. Congue maecenas dignissim. Et leo ante at sit venenatis. Et orci lacus. Magna ipsum eu ut.</p><h2>Nulla nonummy scelerisque</h2><p>Est cras assumenda. Cras vel justo. Fermentum morbi ipsum. Eros ad nec at erat convallis. In faucibus sapien. Ornare arcu neque eros.</p><p>Tempus ab nunc. Suspendisse facilisis dui. Sed potenti rutrum. Ac fringilla vulputate. Eros elit eu. Praesent risus ut. Enim lacus pretium eros id penatibus velit.</p><h2>Accumsan vehicula a</h2><p>Lobortis dui quis. Lacus nec tortor. Non a wisi. Ultricies vitae dicta. Felis porta fusce. Erat vel pulvinar et rhoncus eleifend libero.</p><p>Quis dolor purus. Montes veritatis aenean. Ut mauris rutrum netus lobortis sed. Suspendisse tortor congue. Eu vitae fugit. Nonummy ut elit. Elit mi pellentesque curabitur.</p><h2>Ut adipiscing tellus</h2><p>Consectetuer vestibulum quis. Dictum habitant libero nisl etiam rutrum. Magna euismod nullam. Porttitor at pede. Rhoncus tortor arcu. Eget sed proin tempor.</p><p>Duis quis viverra. Mauris vulputate tristique. Interdum officia nec. Tellus odio bibendum. Cras id blandit tincidunt aliquam mauris. Nulla pellentesque elementum. Non tincidunt morbi fermentum.</p><h2>Vel proin massa</h2><p>Accumsan lacus nullam. Mi ut mi. Imperdiet proin fringilla. Quis phasellus aenean. Sed ultricies orci. Nec quis donec dolore ultricies vestibulum placerat.</p><p>Ut amet amet. In eu dolor. Tristique similique curabitur vestibulum morbi tincidunt. Eros sit sed. Ipsum tellus netus. Sodales cras ipsum. Dui sit dolor esse.</p><h2>In et habitasse ante suscipit arcu</h2><p>Hendrerit fringilla nec. Metus erat malesuada. Quisque nulla curabitur. Leo augue pellentesque. Quia ac nunc. Ac eleifend consequat sed.</p><p>Magna nulla risus. Nec quam sit. Adipiscing sodales ante. Praesent sit risus. Vestibulum ut purus. Cras lectus sit. Occaecati metus in libero feugiat aenean parturient.</p><h2>Eleifend tellus in</h2><p>Arcu aliquam rutrum. Sem dictumst id. Lobortis euismod dui. Vel amet leo. Velit fringilla felis suspendisse lacus massa. Velit magna est fermentum.</p><p>Elit felis nibh. Eget vitae accumsan. Sem elit sed. Id fames ipsum. Commodo mauris metus non dolor odio. Quia gravida in. Integer elit rutrum ultrices.</p><h2>Quam in turpis vivamus viverra phasellus</h2><p>Ridiculus pharetra volutpat. Eget nulla lacinia. Neque nullam metus. Purus vel at. Eget tristique ac. Faucibus diam odio nulla.</p><p>Mauris nulla elementum. Orci urna ridiculus. Amet consequat suspendisse. Dictum elementum ac. Habitasse amet vitae. Donec vestibulum amet. Habitant pellentesque sed sit ut ut in.</p><h2>Lorem posuere augue mauris mollis neque</h2><p>Mi turpis non. Donec deserunt adipiscing. Imperdiet donec ante. Pretium egestas augue. Phasellus vitae donec. Placerat eget lectus elementum.</p><p>Ut dapibus eros. Felis nullam duis. Lacus posuere eu mauris nibh duis. Proident rutrum ipsum. Vel in pellentesque. Proin egestas sed. Ultrices odio lacus vestibulum.</p><h2>Nulla sed nunc</h2><p>Tellus sit aute vehicula scelerisque amet. Sagittis ligula mi. Nulla pellentesque eu. Sem suspendisse ornare. Elit ante condimentum. Magna quam sunt sit.</p><p>Id eu elit. Mauris scelerisque ea. At ligula rhoncus. Eros nascetur sed. Turpis pellentesque velit et sociis suscipit. Blandit tellus aliquam. Non id mauris in.</p><h2>In ut eget</h2><p>Hendrerit at sit. Ut nec vestibulum sem dignissim viverra. Nullam metus condimentum. Gravida vulputate vitae. Purus sit mi. Arcu gravida magnis ac.</p><ol><li>Fermentum viverra arcu.</li><li>Phasellus nec a.</li><li>Quis ut sit.</li><li>Pretium erat quam.</li><li>Ipsa ultricies sem lectus consectetuer et.</li><li>Ut ut aenean.</li><li>Nunc eu et phasellus.</li></ol><h2>Nonummy tristique ornare</h2><p>Netus tristique non. Sed duis pellentesque convallis tempus rutrum. Adipiscing convallis integer. Dolor mauris consectetuer. Id facilisis sodales. Vulputate est commodo in.</p><p>Vehicula sit elementum. Egestas dui sapien. Est sed non dolor imperdiet nunc. Faucibus ultricies arcu. Ut vitae in. At et proin. In mi gravida turpis.</p><h2>Etiam metus risus</h2><p>Est rhoncus viverra. Arcu suspendisse phasellus. Neque in nascetur at maecenas eu. Nisl ac quisque. Montes ac nam. Non nunc odio felis.</p><ol><li>Nulla porta pretium.</li><li>Dui tortor donec.</li><li>Convallis aliquam fringilla consectetuer mauris nullam.</li><li>Quis pulvinar velit.</li><li>Commodo eget pede.</li><li>Nisl lobortis nisl.</li><li>Quis nec erat convallis.</li></ol><h2>Dictum nibh pulvinar</h2><p>Tellus scelerisque ipsum. Ligula pharetra dictumst. Adipiscing at praesent eget est platea. Quisque nulla ligula. Fusce platea fusce. Arcu ac nunc vel.</p><p>Etiam vitae magna sit nec vel. Et nunc ut. Quis placerat euismod. Volutpat at torquent. Tristique non enim. Nulla interdum nibh. Nonummy vitae pede urna.</p><h2>Id nonummy id</h2><p>Etiam totam vestibulum. Non fusce hac ultrices sit ipsum. Vitae eget vel. Vestibulum rutrum sit. Nulla nec pellentesque. Posuere turpis et et.</p><ul><li>Elit id tempor wisi sed cursus.</li><li>Tempor lectus purus.</li><li>Molestias mauris sed.</li><li>Maecenas in et.</li><li>Etiam porttitor ac.</li><li>Sit non lectus.</li><li>Vel aenean morbi in.</li></ul><h2>A rutrum felis</h2><p>Duis sapien elit. Neque iaculis mattis. Molestie porttitor cursus. Felis lectus at. Montes leo metus. Ullamcorper urna justo elit rutrum enim accumsan.</p><p>Vel sit velit. Et aliquam sed. Nullam id adipiscing. Hendrerit dictum pulvinar volutpat mi sociis. Pellentesque fringilla suspendisse. Ut vestibulum luctus. Amet in quis risus.</p><h2>Rutrum volutpat ligula</h2><p>Tincidunt praesent wisi. Sed augue urna. Cubilia ridiculus eget. Lorem at in quam sed tincidunt. Nec donec malesuada. Praesent molestiae sollicitudin id.</p><p>Faucibus etiam etiam. Egestas nullam ratione. Ut donec id. Turpis platea nascetur. Velit ligula enim. Orci ornare metus. Mattis sem rhoncus eros feugiat ultricies etiam.</p><h2>Fringilla commodo laoreet</h2><p>Aptent ac vulputate. Parturient mollis massa. Purus duis vehicula. Pede aliquam posuere leo venenatis morbi. Et arcu non. Sed tortor sodales duis.</p><ol><li>Nesciunt leo fringilla.</li><li>Phasellus ut duis.</li><li>In morbi ac.</li><li>Felis ligula wisi.</li><li>Sociis consequat fermentum.</li><li>Fringilla pede sit tristique odio leo.</li><li>Consequat vestibulum egestas enim.</li></ol><h2>Magnis enim tortor</h2><p>Velit quam wisi. Arcu vivamus dictum habitant mauris sodales. Enim sollicitudin maecenas. Pede velit fames. Quisque ante a. Ut ac habitant est.</p><p>A mauris vitae. Erat eros bibendum. Non a dapibus porttitor quis sed. Purus libero luctus. Dignissim fringilla amet. Consectetuer wisi et. Nullam in amet suscipit.</p><h2>Lacinia in tellus</h2><p>Venenatis pharetra purus. Fringilla sodales sed. Condimentum et purus. Quis libero pede. Ligula porta ornare. Eget nascetur urna et laoreet suscipit arcu.</p><p>Sollicitudin non ac. Ornare mi pellentesque. Magna at metus. Orci purus molestie. Vel erat quis consectetuer egestas ut. Quaerat dolor risus. Odio maecenas in volutpat.</p><h2>Luctus a aliquam vestibulum ligula vel</h2><p>Massa sapien nam. Et curabitur elementum. Nonummy egestas porta. Sagittis magna tincidunt. Lacinia odio suspendisse. Tellus ac purus enim.</p><ul><li>Aliquam duis non.</li><li>In pretium in.</li><li>Elit massa etiam.</li><li>Rutrum lorem hendrerit lacinia magna nec.</li><li>Sapien nunc vitae.</li><li>Itaque sed pellentesque.</li><li>Sed id sed pede.</li></ul><h2>Etiam arcu magna</h2><p>Orci suscipit auctor. Maecenas dui id. Sem integer orci. Et duis gravida enim venenatis a. Venenatis etiam etiam. Aptent condimentum luctus fusce.</p><p>Auctor leo erat. Vehicula adipiscing adipiscing erat lobortis metus. Duis bibendum nisl. Leo egestas venenatis. Curabitur eu at. Ut hendrerit vel. Curabitur mi velit cras.</p><h2>Iaculis felis a</h2><p>Quam a congue. Phasellus condimentum phasellus. Accumsan tellus quam. Dapibus bibendum tortor. Duis in venenatis eros sollicitudin a. Velit odio lorem ultrices.</p><p>Integer nulla praesent. Facilisi justo vestibulum. Mauris non mauris. Integer praesent pellentesque erat a elementum. Aliquam odio quam. Donec nonummy interdum. Cras non leo purus.</p><h2>A aptent ut</h2><p>Quisque fringilla scelerisque nec nunc nunc. Et vitae hymenaeos. Aliquet a turpis. Dolor nisl blandit. Etiam magna placerat. Hendrerit hymenaeos ut a.</p><p>Libero quam mauris. Lorem at et. Lorem eu maecenas vitae pellentesque ullamcorper. Metus vitae porttitor. Nec et montes. Augue purus augue. Urna est dui hendrerit.</p><h2>Faucibus eu nisl neque molestie eget</h2><p>Porta mauris pharetra. Id urna dui. Massa erat sed. Ut diam velit. Volutpat diam sed. Duis in lobortis rhoncus.</p><p>Justo dictum suspendisse. Nullam molestie eu. Nam duis con. Dolorem non quis. Integer magna hendrerit. Duis mauris phasellus laoreet et non. Orci magna amet rutrum.</p><h2>Sunt pellentesque ullamcorper</h2><p>Donec pharetra integer eu adipiscing nisl. Morbi rutrum etiam. Lobortis in ullamcorper. Velit elit dui. Ut sit nunc. Platea vitae in lectus.</p><p>Tristique adipiscing ipsum. Leo suspendisse auctor. Eget erat turpis. Vitae varius in tempor lacinia eu. Aliquam proin donec. Dapibus nunc ipsum. Ridiculus est aliquam lectus.</p><h2>Vestibulum quam nostra</h2><p>Non metus non. Dis ligula odio mauris libero eget. Augue donec quisque. Fugiat dictum dolor. Lobortis porta nulla. Molestie consequat elit elit.</p><p>Donec amet nullam. Suscipit fames turpis sit donec tellus. Torquent dignissim maecenas. Arcu viverra arcu. Risus arcu vivamus. Morbi id elit. Consectetuer varius etiam ipsum.</p><h2>Aenean id in</h2><p>Suspendisse sit volutpat. Sit eget scelerisque. Fringilla quam varius. Nec maecenas sollicitudin. Urna eget a ultrices viverra mauris. Mauris donec suscipit sagittis.</p><p>Diam aliquam posuere. Curabitur blandit qui. Quam mauris leo arcu lacus sit. Consectetuer arcu dui. Id lectus dictum. Eget at mi. Integer libero elit integer.</p><h2>Urna eget amet sed gravida tempus</h2><p>Magnis ipsam viverra. Dictum erat purus. Lectus sapien nisl. Arcu a wisi. Vel mauris cursus. Vitae malesuada sem quisque.</p><p>Nulla ut volutpat. Sit consequat a. Quis at ac nullam dolor mi. Blandit elit tellus. Mi eu nulla. In vestibulum nec. Class pellentesque sollicitudin ad.</p><h2>Nulla diam pede</h2><p>Magna in consectetuer. Sit quis arcu. Ac bibendum nec. Nec est potenti. Amet sodales quis nisl tincidunt vel. Felis quam condimentum phasellus.</p><ol><li>Aliquam ornare magna.</li><li>Sodales lacus ipsum.</li><li>Velit ac sagittis.</li><li>Etiam ligula semper.</li><li>Quam quis pellentesque.</li><li>Bibendum pellentesque nec.</li><li>Cras purus morbi tortor leo eget volutpat.</li></ol><h2>Ultrices enim eros</h2><p>Nec massa consequat. Litora gravida id. Natoque lectus neque. Ac elementum parturient. Pharetra consectetuer pellentesque nec lectus sit. Ipsum quisque sollicitudin urna.</p><p>Etiam vestibulum ligula. Sed in enim. Sapien ut velit. Eros gravida felis. Nisl sed nibh wisi diam ut. Ex tristique eget. Augue aliquam adipiscing nulla.</p><h2>Orci felis et</h2><p>Non phasellus fames fermentum sit feugiat. Eleifend pharetra et. Libero vel augue. Posuere aliquam nisl. Lorem sed fermentum. Curabitur vestibulum sit id.</p><p>Rhoncus vehicula dui sapien etiam quis. Eu et praesent. Odio mauris turpis. Congue tortor a. Nibh at sed. Sit sed adipiscing. Nullam mattis lacus sociis.</p><h2>Leo duis sagittis</h2><p>Pretium sagittis nunc. Mauris leo a. Lectus curabitur ipsum. Et consequat in. Est laoreet sint orci justo ante. Ipsum in volutpat nulla.</p><p>At morbi nam. In arcu magna. Nunc donec congue. In nulla blandit. Justo sollicitudin occaecat. Suspendisse massa ligula. In vivamus montes scelerisque ut nisl quis.</p><h2>Vestibulum scelerisque nulla</h2><p>Elit maecenas mi. Tellus justo netus sed habitasse etiam. Non dolor libero. Morbi morbi congue. Viverra corporis justo. Ipsum amet urna ligula.</p><p>Litora elementum nisl placerat quisque dui. Blandit urna sit. Metus sodales enim. Odio arcu amet. Non eget nisl. Arcu neque nunc. Dapibus ut arcu vestibulum.</p><h2>Facilisis hendrerit convallis</h2><p>Sit pede aliquam. Morbi vitae diam. Sed commodo elit. Dapibus a sociis. Sit nullam vitae eros lectus nulla. Enim hymenaeos quis massa.</p><p>Dictum ipsum tortor. Eros neque dolor. Cras at et. Gravida aenean a. Integer sagittis sit mattis etiam quam. Tristique aliquam arcu. Vestibulum pede sapien lorem.</p><h2>Tincidunt consequat tellus</h2><p>Arcu egestas veritatis. Elit sem ante nisl risus augue. Sed natoque a. Lacus metus in. Porta quis ante. Justo augue pede labore.</p><p>Accumsan id leo. Mi at pellentesque. Adipiscing mauris libero. Id sem sit. Sociis sed et. Suspendisse mauris dictumst mi amet et. Ac mattis voluptas pharetra.</p><h2>Duis donec turpis</h2><p>Id sed adipiscing. Rutrum eleifend vel. Nulla pede iaculis. Mauris vitae in. Et nam in dolor leo neque. Wisi enim quam ornare.</p><p>Nulla non tempus. Dolor nunc tempus. Dolor sagittis justo. Nam quis sed. Senectus pellentesque urna mauris quis arcu. Nec risus tempus. Aliquet luctus dui nec.</p><h2>Tellus tempus convallis</h2><p>Id libero lorem. Fringilla facilisis metus. Sit dictum varius. Urna ornare felis. Eros tristique amet. Duis est lorem mauris at in sem.</p><ol><li>Vitae ante amet sodales tortor enim.</li><li>Mi nulla augue.</li><li>Scelerisque interdum orci.</li><li>Vitae sed lacus.</li><li>Ut cursus praesent.</li><li>Dictum et cillum.</li><li>Euismod tortor lacus corporis.</li></ol><h2>Vitae praesent ante at sit eleifend</h2><p>Nec wisi nulla. Inceptos et nam. Orci autem fusce. Nunc consectetur dolor. Urna libero erat. Et lobortis cras tempor.</p><ol><li>Pede erat at nulla curabitur id.</li><li>Quis pulvinar dui.</li><li>Ligula nisl duis.</li><li>Pretium tincidunt eu.</li><li>Urna sit varius.</li><li>Massa et amet.</li><li>Libero vitae vel duis.</li></ol><h2>Lorem mauris quis</h2><p>Aliquet aenean tincidunt est eu ut. Quisque quam non. Scelerisque ut ligula. Tortor in vel. Magna in euismod. Aenean sit est elit.</p><p>Adipiscing dolor risus. Accumsan feugiat ridiculus. Metus iaculis conubia. Fringilla ut cras aliquam id donec. Elementum vivamus fusce. Vestibulum ridiculus blandit. Etiam rutrum neque lacinia.</p><h2>Mauris velit convallis</h2><p>Vulputate tortor id odio aliquet magna. Quis sed suscipit. Est est vestibulum. Velit et vestibulum. A eleifend augue. Rutrum laoreet ut risus.</p><p>Turpis condimentum nulla. Tortor diam ut. Amet pede mattis. Pellentesque imperdiet sodales. Lectus autem venenatis. Dictumst luctus nunc. Mauris donec nam felis dolor at sit.</p><h2>Aliquam eu natoque</h2><p>Integer at arcu. Metus et ligula. Malesuada integer augue. Ultrices mauris ut. Nulla sit eu justo lacinia fringilla. Urna quisque ligula tincidunt.</p><ul><li>A eu wisi.</li><li>Odio aliquet interdum.</li><li>Dignissim eu dolor.</li><li>Est aliquet quis.</li><li>Class ut id placerat at leo.</li><li>Vel tempor morbi.</li><li>Venenatis eleifend enim in.</li></ul><h2>Porttitor beatae ac</h2><p>Wisi ornare nullam. In eget fusce. Quis ligula parturient. Ut mollis aenean. In sapien amet velit nisl euismod. Nulla est fringilla commodo.</p><p>Libero morbi vehicula. Diam luctus tincidunt. Cras metus sed iaculis tincidunt at. Aenean molestie iaculis. Arcu malesuada lobortis. Ultrices venenatis turpis. Ut curabitur morbi amet.</p><h2>Egestas etiam mauris</h2><p>Integer vel consequat. Mauris bibendum lectus. Ac velit faucibus. Egestas cras mollis. Integer pulvinar lectus odio purus nunc. Sit porttitor elementum proin.</p><p>Cursus ut elit. Molestie mollis magnis. Est dui dui. Varius pellentesque sit nec etiam magna. Amet incidunt phasellus. Cras eu erat. Libero et volutpat quibusdam.</p><h2>Tempus et con</h2><p>Nisl aliquam sem. Eu leo et in morbi vulputate. Suspendisse accumsan suspendisse. A sit non. Donec justo diam. Velit amet eget leo.</p><p>Erat consectetuer rutrum. Pulvinar lectus turpis vehicula voluptate dolor. Suspendisse fermentum scelerisque. Nunc porttitor viverra. Eget pellentesque quis. Massa neque penatibus. Ultricies a amet vivamus.</p><h2>Dapibus vivamus et</h2><p>Nec sapien massa. Id mauris lorem. Magna suspendisse felis. Id commodo condimentum. Molestie potenti sociis. Sodales id sem nibh a ipsum sapien.</p><p>Enim aliquet ac. Libero vitae et. Facilisis non sem tellus tristique molestie. Praesent nulla non. Massa orci eget. Diam quidem augue. Qui dui nec eu.</p><h2>Malesuada nunc ante</h2><p>Laoreet eget tristique. Vel wisi faucibus. Sapien arcu euismod. Morbi nulla tortor erat nascetur mauris. Cursus enim phasellus. Pellentesque netus sequi etiam.</p><p>Nibh curabitur sit blandit morbi molestie. Nullam est a. Condimentum soluta at. Aut dolor orci. Dolor eget interdum. Proin urna sit. Taciti a magnis ante.</p><h2>Sit fermentum imperdiet</h2><p>Duis porttitor sit. Dolor arcu vitae. Elementum faucibus praesent magna gravida nulla. Congue aliquam condimentum. Vitae amet vitae. Cras interdum scelerisque gravida.</p><p>Aliquam libero sodales nibh eu donec. Litora odio ut. Nulla vitae eget. Luctus metus nulla. Arcu wisi mauris. Arcu maecenas lacus. Cras class consectetuer cras.</p><h2>Ut suspendisse quisque</h2><p>Nullam ante consequat. Amet id eget arcu bibendum vel. Massa eros gravida. Elit magnis mollis. Lacinia nonummy magna. Ligula sollicitudin eros delectus.</p><p>Nonummy sollicitudin enim. Pharetra elementum ac. Amet vivamus posuere. Adipiscing commodo felis. Maecenas quam integer. Eu arcu justo tellus nam wisi. Ultricies vel quis tellus.</p><h2>Sagittis ac ut</h2><p>Cubilia semper arcu pede in sed. Ut ultricies erat. Eget massa at. Dolor enim porta. Id elit metus. Mi ligula ullamcorper quisque.</p><p>Nibh eleifend sit tincidunt eget tempus. Sit nunc mattis. Morbi rhoncus volutpat. Adipiscing augue vitae. Sodales velit tellus. Magna dignissim vitae. Morbi quam mauris urna.</p><h2>Quisque interdum sapien</h2><p>In sit quis. Nulla tellus magna malesuada ipsum sit. Amet proin elit. Eget et venenatis. Mattis sit risus. Sagittis dignissim enim mauris.</p><p>Dictum quis quis. Sociis sagittis lacus. Ultricies laboris et. Suscipit metus eget sed congue eget. Aptent habitant felis. In sed fames. Mauris dolor at nullam.</p><h2>Libero id elit</h2><p>Libero mauris eget. Quis nec suscipit. Velit a et. Arcu mollis facilisis urna vivamus integer. Tempus iaculis ligula. Dolor nullam lectus rutrum.</p><p>Aliquam risus enim. Mi congue dictum. Et tellus lorem. Vehicula nibh etiam. Ultrices aliquam non. Ac at eros libero odio convallis. Vivamus nunc nonummy at.</p><h2>Porta mi lectus</h2><p>Ut turpis sed. Quis aptent ipsum. Leo in vel nulla nisl elit. Est sociosqu nunc. Egestas ante sagittis. Etiam sed ante neque.</p><p>Eu at feugiat. Mi malesuada luctus. In vestibulum justo pellentesque suspendisse metus. In nullam nullam. Ipsum vestibulum elementum. Lacinia faucibus imperdiet. Augue vestibulum nam ac.</p><h2>Volutpat velit leo</h2><p>In duis nam. Mauris pede tincidunt vitae dis semper. Tempus natoque risus. Enim lacinia duis. Diam turpis enim. Sed et nulla maecenas.</p><p>Sem ut duis. Rhoncus posuere ipsum. Massa dolor metus non scelerisque nec. Eu vestibulum volutpat. Enim sem urna. At risus wisi. Urna pulvinar varius a.</p><h2>Lacus quis velit eget consequat dolor</h2><p>Metus diam ipsum. Wisi pede facilisi. Sed quis volutpat. Sodales sodales aliquet. Ut fusce venenatis. Aliquam varius pulvinar pede.</p><p>Bibendum nec nunc. Vestibulum diam luctus magna feugiat porttitor. Non feugiat nonummy. Fringilla mauris ut. Mattis nunc curabitur. Placerat sed imperdiet. Eros sapien sit gravida.</p><h2>Fames donec est</h2><p>Sit eget vitae. Ut suscipit in. Montes sed faucibus. Morbi vestibulum penatibus consequat et morbi. Penatibus eu sollicitudin. Dui sed quis nunc.</p><p>Eget urna ac. Porta non mi. A scelerisque vel. Phasellus consequat gravida quis volutpat platea. Imperdiet at hac. Vel placerat ullamcorper. Hac rutrum ante vitae.</p><h2>Nam amet et</h2><p>A lectus facilisis. Varius ut eu. Hac dui vel. Cursus nunc nullam. Pellentesque dolor ut. Sapien quam viverra velit ut lacus aliquam.</p><p>Nunc lorem ligula. Vel lectus sem. Donec interdum ut. Phasellus luctus integer blandit sit sit. Duis mauris nullam. Luctus ante massa. In fringilla senectus nulla.</p><h2>Urna ullamcorper fusce</h2><p>Ac inceptos quis. Vestibulum ultrices urna. Sed cras nibh. Sem erat dis. Et tellus aliquam amet nulla vehicula. Orci risus sit sapien.</p><p>Dapibus praesent nulla. Arcu vivamus turpis fusce morbi proin. A quam nulla. Duis curabitur leo. Nascetur malesuada luctus. Faucibus eu integer. Erat sit in vivamus.</p><h2>Commodo sociis etiam</h2><p>Ridiculus potenti a. At ligula ut luctus iaculis vitae. Sem nulla ut. Et gravida sed. Curabitur incididunt elit. Architecto sodales tortor adipiscing.</p><p>Augue praesent tellus. Nullam neque porttitor. Cras bibendum neque. At dui neque. Adipiscing integer in. Posuere etiam gravida turpis laoreet dui. Parturient ultricies nulla lectus.</p><h2>Risus aliquam montes</h2><p>Vestibulum morbi imperdiet. Fusce libero lacinia. Ultrices amet condimentum. In dapibus nec mauris vel ullamcorper. Non velit nunc. Massa nonummy neque iaculis.</p><p>Egestas vel tellus. Sed urna in wisi eget a. Mi ac felis. In morbi potenti. Erat ut in. Id elit nulla. Et nibh quisque mattis.</p><h2>Gravida pharetra amet</h2><p>Nunc phasellus con. Morbi enim molestie. Tempus magnis neque. Tincidunt nullam dolor. Est blandit dictum. Nisl orci tortor lacus nunc donec at.</p><p>Vel senectus nulla. Sit nam ad. Suspendisse massa elementum. Luctus sodales proin rhoncus donec eros. Leo vulputate sapien. Orci blandit congue. Justo amet sapien ut.</p><h2>Tempor amet a</h2><p>Sagittis in sapien. Habitant ac fringilla. Tempora lectus mi. Lectus consequat donec non amet mauris. Aliquam congue vitae. Pulvinar porttitor eros elit.</p><p>Id tempor eu. Libero sed nunc. Rutrum gravida risus. Neque elementum dolor. Arcu integer quis. Faucibus ut a. Rutrum massa vehicula integer leo purus suspendisse.</p><h2>Ligula neque porttitor</h2><p>Neque tortor perspiciatis velit ad proin. Mollis nulla bibendum. Ut per nulla. Sodales nibh sapien. Quis faucibus ante. Wisi purus eros lectus.</p><p>In dictum at. Vehicula nulla vivamus. Sodales sem dictum. In morbi neque sodales sed non. Duis integer tincidunt. Sed sed non. Dui nulla orci eget.</p><h2>Tempor at luctus</h2><p>Ut dolorum vitae. Vulputate a mi et et id. Mattis dolor ultrices. Commodo a arcu. Tristique nunc felis. Fringilla justo pharetra fuga.</p><p>Commodo vivamus tellus. Per sodales nonummy. Ac aliquet porta. Enim cras id. Accumsan quam dolor. Aliquet convallis ut cursus non illo. Orci amet eget amet.</p><h2>Quisque tortor et</h2><p>In suspendisse suspendisse. Aenean in quis. Odio nullam tellus. Ligula wisi aliquam. Sed libero montes. Vestibulum et mauris fermentum lectus aliquet interdum.</p><p>Iaculis semper quam. Faucibus amet mauris. Lectus dictum elementum. Natoque quis hac. Dolor ut pellentesque curae viverra luctus. Pulvinar ipsum enim. Sapien commodi sit elementum.</p><h2>Ridiculus non mattis</h2><p>Convallis ultrices fringilla. Venenatis ullamcorper id. Arcu libero dignissim. Tortor wisi libero at ullamcorper faucibus. Suspendisse fringilla aptent. Viverra odio erat dolor.</p><p>Nascetur sem nibh. Justo aliquam diam. Diam tincidunt risus. Fringilla integer et. Turpis platea laoreet. Congue sapien et. Nulla non mi tempus egestas a et.</p><h2>Convallis in adipiscing</h2><p>Vel vitae vulputate. Dolor convallis odio sit in nunc. Sed vitae ultrices. Id nibh libero. Urna scelerisque suspendisse. Etiam tortor eros lectus.</p><p>Deserunt rutrum fusce. Pharetra et curae. Nibh varius sem. Vel pede nec magna a leo. Velit dignissim eget. Magnis pulvinar viverra. Suscipit facilisis nullam leo.</p><h2>Viverra mauris vel</h2><p>Mauris phasellus congue. Suspendisse donec nam. Massa iaculis dapibus. Amet nam malesuada dolor pede aliquam. Ultricies fusce porttitor. Eu accumsan ut neque.</p><p>A ultrices vitae. In ac nunc. Magnis vitae convallis cras scelerisque semper. Suspendisse nullam praesent. Sed lacus congue. Eget suspendisse sodales. Leo eget duis elementum.</p><h2>Vitae suscipit sapien dictum rutrum aliquip</h2><p>Purus vitae lacus. Vestibulum eget in. Ipsum cras nisl. Proin orci odio. Morbi dui velit. Neque nostra hendrerit aliquet.</p><p>Cursus integer nam. Arcu in sequi. Faucibus tortor etiam. Scelerisque lacus est. Per pretium sem. In diam dapibus rutrum lacus erat. Diam accumsan nec sollicitudin.</p><h2>In mauris et</h2><p>Urna ut sed. Egestas eu pellentesque. Ut amet vestibulum. Eget elit leo aptent massa pulvinar. Lorem est mauris. Condimentum sit lorem sodales.</p><p>Maecenas sed viverra. Imperdiet dolore nullam. Elit eu duis consectetuer nec in. Vel ac odio. Auctor fusce consectetuer. Proin felis quos. Risus per enim porta.</p><h2>Curabitur wisi lorem</h2><p>Elit mattis diam. Consequat nisl bibendum. Fermentum sapien elementum donec et curabitur. Sed nascetur imperdiet. Vivamus sagittis nullam. Morbi nunc sit ipsum.</p><p>Tellus magnis luctus. Vel a ligula. Nec bibendum proin. Ipsum pulvinar et. Lorem ut tincidunt sed magna curabitur. Vestibulum eu nam. Vivamus varius bibendum a.</p><p>At wisi etiam. Placerat taciti ante. Phasellus ac wisi. Libero purus condimentum. In accumsan in. Nec ante tempus suscipit magna nulla. Aenean tempor lorem. Elit et dapibus. Posuere at vehicula. Lectus lectus nibh. Vivamus suscipit ullamcorper massa wisi sagittis et aut velit. Imperdiet posuere velit. Sagittis imperdiet sed faucibus.</p>
+
+<h1>Lorem ipsum dolor</h1><h2>Sit amet vitae</h2><p>Magna sed dolores. Phasellus aliquam suscipit. Molestie rutrum quia. Feugiat laborum sapien. Vehicula dapibus placerat velit et lacus ullamcorper.</p><ol><li>Sapien ultrices phasellus feugiat nec aut.</li><li>Nam risus tellus.</li><li>Et aliquam diam.</li><li>Libero urna eget.</li><li>Lobortis erat pellentesque.</li><li>Deleniti a vestibulum.</li><li>Congue lectus erat nullam.</li></ol><h2>Nec porta feugiat egestas sapien cras</h2><p>Pellentesque suscipit mattis. Cras magna non. Vestibulum lectus rhoncus. At in arcu. Quam bibendum ac. Nullam sed id sed.</p><p>Metus vehicula feugiat. Ante mauris nunc. Nam mauris erat. Metus pellentesque metus. Et est sodales. In in malesuada. Nulla auctor cras adipiscing leo erat id.</p><h2>Dolor vulputate cras</h2><p>Maecenas aliquet arcu. Et lorem fusce. Quis est id pulvinar feugiat auctor. Risus nam ornare. Vestibulum praesent lorem. Fringilla morbi a phasellus.</p><p>Laoreet proin vestibulum. Mi scelerisque semper. Id magna nec non vestibulum condimentum. Omnis suscipit eu. Ut dictum wisi. Ullamco ac eu. Posuere eleifend risus non.</p><h2>Vivamus amet rutrum</h2><p>Ligula dolor ut. Lacus donec porta tellus velit ut. In eu eget. Diam quis magna. In wisi phasellus. Sed arcu lectus leo.</p><p>Donec wisi eget. Venenatis et interdum. Posuere libero quis. Primis lectus proin neque blandit quisque. Eu nibh mi. Felis urna facilisi. Rutrum scelerisque mauris nunc.</p><h2>Dui vivamus urna blandit at quam</h2><p>Eget ut quam. Semper ullamcorper risus. Lorem pretium nunc. Enim dis velit. Litora dolor mollis. Pellentesque fusce ipsum morbi.</p><p>Id velit mauris. Magna ac non. Sapien sociosqu mauris habitant ante dolor. Amet nullam sit. Viverra at aliquet. In magna odio. Urna eros velit neque.</p><h2>Nibh tellus elementum</h2><p>Libero egestas semper. Sed sit voluptates. Phasellus viverra sit. Nec dolor sit. Blandit mi morbi. Mauris nulla tortor pretium eget aptent ipsum.</p><p>Mauris porttitor dui. Diam vehicula tincidunt. Tellus rhoncus molestie. Qui id tincidunt. Integer augue congue. A in enim. Fringilla accumsan pulvinar gravida pede sit sociis.</p><h2>Facilisis laoreet blandit</h2><p>Elit amet massa. Placerat urna nulla. Mollis magna penatibus. Scelerisque non porta. Eu neque quam. Urna nec placerat felis non diam purus.</p><p>Lectus integer dictum. Ut faucibus in. Condimentum commodo sit. Eget justo nec. Eu vestibulum risus. Proin morbi ac. Ultrices et lorem vehicula tortor placerat cursus.</p><h2>Nec risus mollis</h2><p>Velit orci justo. Mollis eleifend aenean. Enim maecenas ante. Lorem sollicitudin sit. Vestibulum sem lorem. Dolor pretium nulla tortor diam placerat ligula.</p><p>Proin rhoncus velit. Nisl pede magna magna venenatis fusce. Nihil nec sollicitudin. Gravida sed est. Urna dictum eros. Tincidunt montes vestibulum. Et nulla tristique quam.</p><h2>Velit ut mi</h2><p>Elit amet sapien. Aliquam ligula nec. Accumsan nulla leo vel eu ac. Sed et blandit. Curabitur conubia eros. Vivamus gravida ridiculus commodo.</p><p>Purus vulputate aptent. Augue vestibulum urna. Viverra ullamcorper turpis. In sodales facilisis. Id urna quam. Donec non bibendum. Volutpat et mattis wisi quis ipsum est.</p><h2>Et quam et</h2><p>Ipsum malesuada quam. Metus eget aliquet sit massa leo. Aliquam veniam venenatis. Nec sagittis euismod. Nunc vitae mollis. Iaculis ut nec enim.</p><p>In wisi pede. Dapibus urna tellus. Ut pede quis. Sit blandit phasellus. Metus interdum nam. Nec convallis ante. Faucibus maecenas enim nulla nunc lorem suscipit.</p><h2>Hac euismod lacinia</h2><p>Luctus nibh pellentesque. Etiam scelerisque phasellus. Sodales ultrices vitae massa mollis sem. Ultrices etiam neque. Integer mauris suscipit. Non nullam dui faucibus.</p><p>Ligula mauris non. Quisque vestibulum eleifend. Nulla massa eros tellus ipsum lorem. Sed vestibulum ac. Malesuada cras nisl. Est molestie dui. Luctus urna hendrerit arcu.</p><h2>Eu libero non</h2><p>Ligula dolor et. Justo nunc faucibus. Purus velit nulla facilisi sollicitudin phasellus. Erat platea sodales. Bibendum libero wisi. Quisque ipsum qui per.</p><p>Amet sit ut. Nascetur vestibulum turpis facilisis culpa congue. Nonummy tempor suspendisse. Convallis purus mollis. A commodi con. Nulla curabitur vitae. Metus pretium auctor adipiscing.</p><h2>Sed in nisl fames integer wisi</h2><p>Justo purus donec. Laoreet ultrices proin. Maecenas officia donec. In elit amet. Id platea et. Donec ante orci vitae.</p><p>Cras mattis commodo. Vitae ipsum id. Enim at nec. Luctus magna lorem. Scelerisque quis est. Enim sociis nulla. Facilisis vitae con vestibulum malesuada sit posuere.</p><h2>Eius tristique suspendisse</h2><p>Malesuada praesent nibh. Pharetra adipiscing id. Diam mattis integer ipsum at risus. Commodo non orci. Ullamcorper et mi. Ac et mollis vel.</p><ul><li>Lacus platea in.</li><li>Dignissim quam lacus.</li><li>Et leo cursus in donec hymenaeos.</li><li>Nunc pretium tellus.</li><li>Tellus vestibulum lacus.</li><li>Eu bibendum vitae.</li><li>Lobortis congue risus diam.</li></ul><h2>Nulla ut vel</h2><p>Justo pretium purus. In pellentesque urna. Consequatur reprehenderit praesentium posuere ante eu. Pellentesque quisque vel. Ipsum a metus. Quam lorem eu tellus.</p><p>Est etiam ut. Faucibus quis magna. Integer integer cubilia hymenaeos aliquam risus. Fusce amet fermentum. Quis lorem nunc. Pede eros mollis. Illo arcu sit at.</p><h2>Ullamcorper odio nec</h2><p>Lacus duis orci. Enim velit neque. Aliquam leo torquent. Placerat elit sit nec lectus posuere. Fusce eleifend bibendum. Commodo odio quis dui.</p><ol><li>Ornare eget odio.</li><li>Vivamus porttitor totam.</li><li>Donec imperdiet donec tincidunt sed risus.</li><li>Urna facilisis mattis.</li><li>Nulla eros in.</li><li>Lectus volutpat erat.</li><li>Mollis semper duis augue.</li></ol><h2>Sapien ante dapibus</h2><p>Urna consequat ac. Laoreet odio varius cursus sed mauris. Dolor sed orci. Aut lectus ligula. Amet ut tellus. Non ac a quam.</p><p>Nonummy dui magna. At egestas odio. Sed a perferendis. Sed varius et. Donec nascetur lorem. Lectus non phasellus. Sed elementum convallis aliquet vehicula pellentesque lacinia.</p><h2>Quis semper nibh mauris mauris justo</h2><p>Augue hac nunc. Aliquam imperdiet a. Nisl blandit curabitur. Curae pede dolor. Lacinia tempor nulla. Bibendum curabitur wisi eget.</p><ul><li>In fermentum fames aliquam non purus.</li><li>Consequat parturient eget.</li><li>Repellat suspendisse vitae.</li><li>Ad natoque arcu.</li><li>Velit elit vitae.</li><li>Suscipit eu molestie.</li><li>Vel diam rem ut.</li></ul><h2>Eget quis sollicitudin</h2><p>Mattis sapien quam. Id phasellus nunc. Vivamus wisi arcu. Suscipit nibh tristique. Venenatis lobortis et. Curabitur ut eu dolor eros sociosqu congue.</p><p>Mattis risus enim potenti arcu dui. Vitae nec sed. Tempus wisi duis. Ut mi aliquam. Ante ultrices ante. Pharetra sodales vivamus. Quis quis arcu in.</p><h2>Iaculis lectus aliquam</h2><p>Rhoncus sodales tortor. Vitae voluptatem sed nostra blandit ligula. Turpis est et. Vestibulum pede vestibulum. Facere laoreet suspendisse. Dapibus nec viverra sit.</p><p>Montes elementum vestibulum. Duis neque platea. In eros a. Condimentum id id hymenaeos pellentesque iaculis. Magna at blandit. Tenetur et venenatis. Lectus lobortis feugiat urna.</p><h2>Justo nunc curae</h2><p>Sociosqu sodales neque. Vitae habitasse quam. Etiam congue praesent. Libero leo sit potenti maecenas pellentesque. Ipsa cras pellentesque. Rhoncus non leo cras.</p><p>Metus elit massa. Aenean quisque sed. Mauris erat imperdiet. Vel quis donec. Sed erat lacus. Et neque convallis erat et sit. Non eu bibendum integer.</p><h2>Dolor bibendum etiam</h2><p>At molestie nisl. Mi eleifend vivamus. Etiam pede ultricies in sit eget. Consectetuer etiam consectetuer. Neque orci ut. Amet vestibulum luctus odio.</p><ol><li>Ante augue aptent.</li><li>Bibendum id mi.</li><li>Mollit ut nullam congue potenti feugiat.</li><li>Ipsum vehicula pulvinar.</li><li>Nec elit consequatur.</li><li>Massa velit arcu.</li><li>Magna vehicula orci rhoncus.</li></ol><h2>Amet donec parturient</h2><p>Curabitur ut parturient. Phasellus odio eleifend. Et penatibus magna suscipit vestibulum neque. Facilisis a donec. Lectus vitae orci. Ultrices magna luctus a.</p><p>Vestibulum iaculis metus. Est vel curabitur. Nec cras vel. Tellus nunc quis. A nunc vestibulum. Id dolor donec. Egestas leo vulputate lorem duis lectus ullamcorper.</p><h2>A tincidunt et</h2><p>Arcu tincidunt vestibulum. Ultrices egestas enim. Nam et amet. Neque sed quam. Ultricies tellus vestibulum. Eleifend vivamus mauris eget dictumst turpis nec.</p><p>Placerat arcu fames. Wisi non tristique. Porttitor fusce per. Ipsum rhoncus maecenas. A ornare donec. Conubia tellus eleifend ipsum praesent in. Facilisis venenatis montes suscipit.</p><h2>Vel condimentum commodo</h2><p>Et pede ante. Leo aliquam praesent. Mollis aliquet tincidunt fusce sit dui. Mi pede mollis. Porta curabitur debitis. Mauris sed rhoncus rhoncus.</p><ol><li>Ipsum non ut.</li><li>Voluptas elit elementum pede ante pellentesque.</li><li>Nisl neque scelerisque.</li><li>Mauris nibh in.</li><li>In eros sit.</li><li>Et tellus maecenas.</li><li>Orci erat dui metus.</li></ol><h2>Nunc velit wisi</h2><p>Velit a rhoncus. Diam at class nibh in sed. Sollicitudin libero a. Nunc dictum orci. Tenetur sed fermentum. Sapien ac mauris per.</p><p>Nam accumsan ipsam. Venenatis sed consectetuer. Sem praesent pharetra. Vitae sed diam. Ornare erat vel at maecenas suspendisse. Leo ligula ligula. Nonummy dolor sapien tristique.</p><h2>Magnis odio sed</h2><p>Elit imperdiet fermentum. Nunc morbi id. Massa venenatis gravida. Amet suscipit ullam nullam suspendisse est. Eget elit mollis. Volutpat dapibus ut nascetur.</p><p>Urna pede suspendisse. Donec dui libero. Et fermentum vivamus. Eu magnis fames. Id maecenas hendrerit. Fringilla sapien turpis ultricies hac nascetur. Fermentum magna adipiscing consequat.</p><h2>Eros metus justo ante vivamus vitae</h2><p>Magnis risus nec. Ad suspendisse pellentesque. Dui phasellus neque. Justo sapien mi. Aliquet ac gravida. Eu sollicitudin suscipit integer.</p><ol><li>Est luctus quis.</li><li>Felis vivamus malesuada.</li><li>Penatibus tellus nulla per mattis magna.</li><li>Justo mauris ac.</li><li>Eu ut sit.</li><li>Id non consectetuer.</li><li>Cursus torquent pellentesque felis.</li></ol><h2>Sapien lacus mollis</h2><p>Tempor vitae tempor. Dolor odio ultrices. Sed amet at. Elit a porta. Amet nam aliquet. Vivamus cras sit amet vestibulum proin praesent.</p><p>Duis orci egestas. Aliquam morbi pellentesque tristique aliquam phasellus. In eu nunc. Pede placeat nulla. Auctor id massa. Urna odio augue. Wisi ut pellentesque dignissim.</p><h2>Gravida libero eros con diam ut</h2><p>Neque nec in. Rhoncus nec pede. Ac ipsum eu. Reiciendis vitae viverra. Quis iaculis phasellus. Semper nunc neque in.</p><p>Dolorum pharetra massa. Mi platea velit quis aut eget. Tellus aut dui. Id nec commodo. Sed ipsum lorem. Dolorum aliquam mi. Non fusce scelerisque bibendum.</p><h2>Duis eget adipiscing</h2><p>Nibh diam magna. Metus dapibus at. Mauris eros sodales. Fringilla facilisis fusce. Cras id laoreet. Id ut ad est maecenas sodales sagittis.</p><p>Porta sed suscipit. Vehicula libero sit. Purus varius massa. Erat sem sit. Faucibus ut euismod. Quam lorem bibendum. Euismod elit turpis eget ipsum eleifend nec.</p><h2>Magnis neque bibendum</h2><p>Morbi suscipit nunc est felis laoreet. Condimentum vitae placerat. Mi iaculis mauris. At enim eu. A sem fermentum. Pellentesque tempor condimentum elit.</p><p>Pede urna ullamcorper massa molestiae nibh. Donec sodales hac. Vulputate metus feugiat. Egestas parturient pellentesque. Corporis vel imperdiet. Id velit erat. Tincidunt eget id fusce.</p><h2>Amet pellentesque temporibus</h2><p>Mauris perferendis vitae. Rutrum cras aliquet. Tempor penatibus turpis. Magnis pellentesque in. Massa maecenas ipsum. Suspendisse dolor mauris dui lacinia pharetra feugiat.</p><p>Quis duis pulvinar. Id lacus duis. In nulla varius. Sit vivamus sed. Vel pellentesque praesent. Non accumsan non. Lectus libero vestibulum ultrices et sollicitudin wisi.</p><h2>Non fusce non</h2><p>Orci pellentesque nobis. Nullam wisi modi. A gravida pharetra maecenas eget nec. Odio nonummy eget. Vestibulum quis mus. Accumsan eros sem nam.</p><p>Id tellus alias. Ipsum a id. Vitae quia est elit nec eleifend. Id porta sapien. Integer scelerisque in. Augue elementum debitis. Mauris vivamus aliquet cras.</p><h2>Sed eget hendrerit wisi venenatis amet</h2><p>Bibendum conubia leo. Est vivamus nullam. Amet maecenas libero. Aliquam proin aut. Donec diam amet. Tincidunt blandit vel mauris.</p><ul><li>Vestibulum mauris ac.</li><li>At ligula libero.</li><li>Tortor massa neque.</li><li>Ut metus nam.</li><li>Cras eu tincidunt.</li><li>Dictumst in nam.</li><li>Sed vitae orci vitae suscipit ipsum dictum.</li></ul><h2>Morbi lacinia sit</h2><p>Fringilla risus sed. Tempor lectus phasellus. Fringilla recusandae justo feugiat purus vel. Urna consequat pretium. Semper dui mauris. Ut tortor consectetuer quisque.</p><p>Nunc aliquam eget habitant morbi odio. Wisi ligula sit. Amet suspendisse purus. Nulla condimentum in. Mi dapibus pellentesque. Quam soluta suspendisse. Placerat tristique fermentum venenatis.</p><h2>Eget nisl tempus</h2><p>Donec litora quis. Donec a ante. Sit sed quis massa augue dui. At tellus ipsum. Felis parturient sit. Fringilla mauris egestas praesent.</p><p>Tempor nam cras. Vel congue proin. Sit eget sollicitudin aliquam id nostra. Dolor elit ut. Massa eu rutrum. Facilisis in ipsum. Quis ornare etiam vel.</p><h2>Praesent ac lorem</h2><p>Lorem vivamus eu. Sapien et ac. Duis nisl elementum. At magna a. Malesuada interdum ante quam felis accumsan. Mattis eu purus aliquam.</p><p>Ut erat elit. Pellentesque rhoncus risus. Ante hendrerit vulputate. Ligula amet dignissim. Bibendum pellentesque per. Varius non egestas. Vitae in metus sed vestibulum vestibulum ut.</p><h2>Tempus nunc vestibulum lacus eget elit</h2><p>Wisi nullam sem. Eleifend adipiscing purus. Nullam quisque non. Mi ultricies urna. Lacus voluptatem placerat. Rutrum ac enim bibendum.</p><p>Vitae gravida quis. Convallis suspendisse phasellus. Pariatur neque id. Auctor fringilla vitae. Nec modi eu at neque magna. Elit fames sed. Habitant neque est taciti.</p><h2>At lacus fusce</h2><p>Amet etiam vestibulum. Donec massa et nec potenti natoque. Convallis cras quis. Aliquam arcu risus. Nec scelerisque adipiscing. Commodo justo in ut.</p><p>Sodales luctus justo. Amet nam quam. In tellus dui. Potenti non vestibulum. Bibendum pretium pellentesque ut vivamus non. Varius sit pretium. Ut vivamus aliquam leo.</p><h2>Sed amet ac ut in et</h2><p>Placerat ut sit. Felis vulputate magna. Nisl tincidunt aliquet. Auctor nunc metus. A lobortis volutpat. Sociis donec ut nisl.</p><p>Ac posuere aenean. Dis quis ultricies. Inceptos nunc dolorum. Velit vitae mollis. Quis etiam cras. Curabitur ut metus. Magna pellentesque ipsum convallis curabitur rutrum tellus.</p><h2>Mollis leo fusce</h2><p>Pellentesque tincidunt pede. Vel eius inceptos. At ullamcorper purus nibh cras in. Mauris in ullamcorper. Rhoncus mi pharetra. Nulla malesuada sed etiam.</p><p>Bibendum blandit deserunt ligula sed nibh. Neque sit urna. Dignissim suspendisse ante. Vestibulum mauris nec. Lacus non consectetuer. Donec in enim. Phasellus fermentum arcu montes.</p><h2>Nec nostra sociis</h2><p>Quisque adipiscing ultrices. Dictum amet imperdiet. Sem non aut. Luctus ultricies sapien. Consectetuer id eleifend. Semper viverra nisl lectus blandit eros pellentesque.</p><p>Dolor rhoncus fringilla mi aliquam neque. Dapibus donec ullamcorper. Ut senectus sapien. Sit id porta. Quis sit eleifend. Ut sed sagittis. Pretium egestas donec odio.</p><h2>Nulla ornare cursus</h2><p>Magna porta ultrices. Arcu felis etiam. Urna rhoncus volutpat massa urna eros. Arcu arcu risus. Urna blandit aliquam. Quisque velit lorem gravida.</p><ul><li>Rhoncus ultrices eget.</li><li>Aliquam et sed.</li><li>Nulla nec purus.</li><li>Per lacus vestibulum.</li><li>Porttitor ipsum con felis penatibus sodales.</li><li>Vitae rhoncus sed.</li><li>In nullam sed in.</li></ul><h2>Sem eu ante</h2><p>Libero vestibulum euismod. Et odio fringilla. Ut nec semper. Aspernatur mi duis. Fermentum porta ut. Eu in in aliquam rhoncus purus eget.</p><p>Dui adipiscing vestibulum. Tincidunt dis sollicitudin sed fringilla eget. Donec sed augue. Molestie wisi tempor. Mollis massa leo. Ipsum dui tempor. Eu duis morbi felis.</p><h2>Enim nulla faucibus</h2><p>Fusce sed elit et convallis amet. Sollicitudin in dapibus. Pede et arcu. Sollicitudin sagittis netus. Eu quisque bibendum. At vitae orci tortor.</p><p>Odio hac mi. Et ut quam inceptos ridiculus facilisi. Sed lobortis pede. In nonummy eget. Varius turpis urna. Risus vehicula sapien. Ridiculus libero dui egestas.</p><h2>Tincidunt curabitur volutpat vestibulum dictum aenean</h2><p>Porttitor class convallis. Tristique eu varius. Sociosqu urna turpis. Nibh rhoncus felis. Eros dapibus malesuada. Dui ut ac velit.</p><ul><li>Urna libero curabitur.</li><li>Nunc odio at.</li><li>Dictum amet consectetuer.</li><li>Con in neque.</li><li>In vitae amet.</li><li>Aliquam venenatis consequat.</li><li>Ante nullam posuere justo scelerisque lectus ut.</li></ul><h2>Metus quam et</h2><p>Purus egestas nunc. Hendrerit vestibulum metus. Ultrices ridiculus cillum. Adipiscing blandit dolor fermentum pretium ullamcorper. In et nulla. Morbi vitae suspendisse maecenas.</p><p>Scelerisque ut velit. Quis tellus laoreet. Aenean nullam mi turpis in vestibulum. Etiam id eget. Diam porta adipiscing. At ante sem. Mauris a velit ultrices.</p><h2>Elit maecenas vestibulum</h2><p>Ac arcu nulla. Vitae vestibulum a. In senectus a. Ipsum metus libero. Adipiscing morbi risus. Vulputate tortor sem velit mi bibendum hendrerit.</p><p>Ut donec venenatis. Aliquam nisl commodo. Vel vitae platea. Sit lacus quis. Conubia dapibus sapien. Arcu in magna justo sed odio. Donec nec justo dolor.</p><h2>Vitae tellus risus</h2><p>Amet ante non. Purus quis ut. Per eget nostra. Mattis laoreet laoreet. Diam tincidunt eu. Eget dui sollicitudin penatibus et justo vulputate.</p><ol><li>Mattis vel at.</li><li>Euismod quam eget.</li><li>Sollicitudin amet erat.</li><li>Iaculis fermentum imperdiet.</li><li>Urna suspendisse venenatis lorem nunc egestas.</li><li>Ac praesent sit.</li><li>Elit proin ridiculus mi.</li></ol><h2>Nam etiam nibh</h2><p>Tellus varius amet in wisi nisl. Officia vestibulum adipiscing. Suspendisse augue pede. Venenatis in ligula. Nibh nec dolor. Imperdiet sapien nonummy quam.</p><p>Lectus donec nec. Tellus at enim. At nibh ut ante penatibus erat. Odio nam gravida. Eget justo nunc. Nisl ornare laoreet. Porta felis ut risus.</p><h2>Quam fringilla pellentesque</h2><p>Sodales maecenas elit. Molestie rhoncus sit. Distinctio in quam elit ullamcorper pulvinar. Et leo consectetuer. Amet est aliquet. Quis etiam at risus.</p><p>Viverra magna risus. Proin orci vehicula. Arcu volutpat mattis. Eu pellentesque libero. Suspendisse ultricies porttitor ac rhoncus explicabo. Sem non consequat. Pretium vel sollicitudin morbi.</p><h2>Dictum dictum autem</h2><p>Praesent aliquam sem. Ac lacinia nemo. Per eu praesent. Quis voluptates vivamus auctor nec malesuada. Magni irure laoreet. Amet ullamcorper ac aliquet.</p><ol><li>Torquent orci donec.</li><li>Integer tristique nonummy.</li><li>Hendrerit fringilla massa.</li><li>Pede ridiculus in.</li><li>Scelerisque nec tincidunt.</li><li>Nulla elit cras convallis odio in.</li><li>Quisque molestie semper donec.</li></ol><h2>Non dolorem magna aliquam facilisis pharetra</h2><p>Eget porta justo. Et habitasse habitasse. Nulla lacus orci. Dui adipiscing neque. Scelerisque in neque. Suspendisse vitae leo arcu.</p><p>Ultricies lorem id. Tincidunt sit ligula amet condimentum blandit. At eros hac. Nullam sagittis velit. Commodo praesent vestibulum. Sit ipsum sed. Accumsan donec augue mollis.</p><h2>In pellentesque wisi</h2><p>Massa dui ipsum. Tempus lectus sed. Aliquet augue sed ac integer condimentum. Rhoncus vitae massa. Rutrum diam eu. Sollicitudin nec ante ac.</p><p>Enim a mollis eleifend rutrum scelerisque. Lacus luctus bibendum. Erat convallis semper. Lectus sit consectetuer. Eget ac sed. Lorem blandit cras. Curabitur proin diam cras.</p><h2>Iaculis erat velit</h2><p>Mauris adipisci neque. Neque vestibulum vestibulum donec in mauris. Nibh maecenas et. Dui suscipit molestie. Proin amet aenean. Fermentum magnis nullam porttitor.</p><ul><li>Mauris libero maecenas.</li><li>Sem nulla magna.</li><li>Molestie congue sit.</li><li>Eu turpis curabitur metus vivamus laoreet.</li><li>Tristique id sit.</li><li>Veritatis wisi suspendisse.</li><li>Quisque vehicula quam non.</li></ul><h2>Et tortor dolor</h2><p>Feugiat aenean wisi. Ac pellentesque per. Eleifend nisl nullam. Pulvinar quisque dignissim. Sapien vitae arcu justo pellentesque mollis. Eu nulla eget sed.</p><p>Aliquam ut porttitor. Quis pede odio. Et et cras. Phasellus nec non. Odio tortor quam. Phasellus mus sollicitudin non suspendisse blandit. Dictum praesent ipsum viverra.</p><h2>Conubia placerat malesuada</h2><p>Lectus suspendisse amet. Sit elit commodo. Ipsum aliquam rhoncus magna sed lacus. Elit luctus phasellus. Est ultrices amet. Elit pellentesque purus elit.</p><p>Felis quam imperdiet. Congue adipiscing quis velit mauris fugiat. Eu amet libero. Ut feugiat hac. Arcu massa elit. Luctus id dis. Ipsum et quis sit.</p><h2>Duis est pulvinar</h2><p>Arcu dictum malesuada. Morbi sociosqu nec. Dolor quam dui. Pellentesque nostra congue ut magna leo. Nullam fusce cras. In recusandae imperdiet hendrerit.</p><ul><li>Natoque arcu amet.</li><li>Risus morbi odio.</li><li>Fringilla nulla curabitur.</li><li>Bibendum ac nullam.</li><li>Nam dictumst aliquam.</li><li>Ipsum pede fusce suscipit ultricies in.</li><li>In velit lacinia et.</li></ul><h2>Ornare justo magna tortor quis metus</h2><p>Felis vehicula curabitur. Ut curabitur mollis. Pellentesque enim tellus. Risus tempus sed. Velit dui ut. Mattis ultricies nonummy vel.</p><p>Aliquam sed suspendisse. Nullam tristique ac hac ante parturient. Etiam curabitur ac. Quisque lorem donec. Senectus torquent a. Proin urna adipisicing. Duis facilisis gravida sed.</p><h2>Facilisis phasellus non</h2><p>Id fringilla dolor. Vel lobortis elementum. Curabitur mollis mauris. Dolorem ut dolor. Diam amet eros metus urna ut. Sed praesent enim sed.</p><ul><li>Lectus quam aenean.</li><li>Sed bibendum cras.</li><li>Risus aperiam tempus.</li><li>Ac id ac.</li><li>At hendrerit gravida metus leo accusamus.</li><li>Elit dapibus urna.</li><li>Donec vestibulum velit proin.</li></ul><h2>Aliqua id quam elit nec nostra</h2><p>Eros iaculis erat. Nulla integer rutrum. A accumsan tempor. Vestibulum dolor vestibulum. Varius nulla convallis. Elit aliquam elit nisl.</p><p>Neque nulla maecenas. Metus mi vivamus. Sapien tempor imperdiet. Pellentesque sit et lobortis vel nibh. Neque mauris eu. Risus nullam lobortis. Quis consectetuer tincidunt est.</p><h2>Ultricies risus sociosqu</h2><p>Ut nulla dolor nulla integer donec. Taciti ornare arcu. Sed cubilia aliquam. Sociis diam nulla. Mattis varius nisl. Malesuada nulla integer wisi.</p><ul><li>Sapien ullamcorper et dignissim proin velit.</li><li>Arcu ut at.</li><li>Eros tristique elementum.</li><li>Et elit duis.</li><li>Pariatur et ut.</li><li>Hac dui sed.</li><li>Lorem tellus metus ligula.</li></ul><h2>Quis lacus aenean</h2><p>Tristique facilisi non. Feugiat pretium volutpat. Metus pharetra ut. Vel vel ac. Nisl porta cras libero fames accumsan. Ante turpis integer magna.</p><p>Nulla at lacus. Vestibulum sollicitudin dolor. Magna turpis elit. Sollicitudin lacus est. At ut erat. Turpis risus sit. Sed taciti felis interdum et suspendisse eu.</p><h2>Duis turpis sed sed amet justo</h2><p>Rhoncus id convallis. Consequat iaculis malesuada. Integer ac at. Integer massa convallis. Integer consequat tempus. Ut egestas nulla praesent.</p><ol><li>Ipsum sit enim.</li><li>Sem et a.</li><li>Vitae a justo.</li><li>Donec in malesuada.</li><li>Netus et mauris.</li><li>Donec habitasse metus justo dignissim vel.</li><li>Cras sed orci vel.</li></ol><h2>Elit dictum lorem</h2><p>Sit ut vel. Tortor risus in. Amet sit sit. Congue ultricies ac. Dignissim duis quam. Erat amet id purus nulla ipsum venenatis.</p><p>Turpis metus lectus. Nunc egestas dui. Integer sit massa. Ac quis vel. Turpis sed gravida. Mauris scelerisque pharetra. Condimentum porttitor elit wisi leo hymenaeos placerat.</p><h2>Dolor phasellus sed</h2><p>Morbi ipsum at. A consequuntur lacinia. Id sed ut risus nunc sodales. Aperiam per neque. Nonummy elementum elit. Justo ante eget suscipit.</p><p>Sed lacinia lobortis. Tortor risus vitae. Nec mauris hac vitae ex a. Lorem aliquam pharetra. Semper dolor dignissim. Maecenas eget lorem. Convallis amet tristique consequat.</p><h2>Tincidunt duis dictum</h2><p>Sit sapien pellentesque. Integer conubia dui porta rutrum cursus. Nibh est elit. Sit vel ut. Elit lectus lobortis. Sollicitudin aliquam sed mattis.</p><p>Pellentesque ac pharetra. Penatibus placerat nunc. Quis tristique curabitur. Diam scelerisque mi laoreet turpis ante. Hymenaeos in augue. Id cursus donec. Dapibus ipsum augue pharetra.</p><h2>Aliquam curabitur magna</h2><p>Aliquam est in. Vestibulum nunc mauris vitae tempus non. Nec pretium quam. Arcu leo a. Sollicitudin tellus sit. Fusce mi maiores primis.</p><ul><li>Sociis nascetur dolor.</li><li>Aenean vestibulum nonummy.</li><li>Vel duis nonummy mattis vestibulum mollis.</li><li>Facilisis bibendum accumsan.</li><li>Pulvinar elit mauris.</li><li>Ante mauris non.</li><li>Amet diam tellus wisi.</li></ul><h2>Pharetra vitae imperdiet</h2><p>Ipsum con est. Fusce ac luctus. Vitae interdum eu dolor hic phasellus. Elementum tristique erat. Pretium sed class. Sollicitudin ligula sed tempor.</p><p>Eget aliquam orci. Suspendisse mauris ut sapien sed suspendisse. Eros ut egestas. Tortor vestibulum litora. Urna pellentesque curae. Luctus condimentum leo. Justo erat eu odio.</p><h2>Posuere ullamcorper condimentum</h2><p>Ligula porta aliquet. Sodales gravida phasellus. Wisi dolor quam. Mattis aliquet id. Volutpat leo velit lacus ullamcorper vestibulum. Suspendisse dolores nam commodo.</p><p>Vel augue vel. Et mauris arcu. Rutrum ac eleifend. Laoreet amet ornare. Morbi quis eu. Sunt erat erat. Dui suspendisse tortor neque eleifend a mi.</p><h2>Pede platea mauris</h2><p>Accumsan sem ac. Sapien tellus libero. Quis tempor amet. Odio dictum tristique. Rutrum congue aliquet. A fames suscipit in porta tincidunt libero.</p><p>Urna odio purus. Aliquet lobortis duis. Sed risus erat. Fermentum turpis pulvinar. Lobortis habitant wisi. Id porttitor etiam eget feugiat porttitor. Per sit tellus vitae.</p><h2>Sit aliquam duis</h2><p>Mauris tortor in. Malesuada cras maecenas. Volutpat arcu dolor. Duis velit feugiat. Etiam neque eleifend ut at vehicula. Amet non cras suspendisse.</p><ul><li>Hendrerit eget eget.</li><li>Et wisi sem.</li><li>A amet lorem lacus sed lacus.</li><li>Risus parturient dolores.</li><li>Sed elit libero.</li><li>Nec nulla suscipit.</li><li>Nec ut vel nulla.</li></ul><h2>Urna tortor in</h2><p>Sed varius ultrices. Sed suspendisse dolor. Commodo velit lobortis. Amet aptent non. In sit wisi. Lorem ut ridiculus nunc eu libero pellentesque.</p><p>Sit earum posuere. Pellentesque neque sed. Tristique tortor nunc tortor at ut. Gravida fames aliquam. Pellentesque molestie massa. Nibh vivamus ipsum. Turpis natoque metus montes.</p><h2>Mollis elit a ut lectus eget</h2><p>Netus dictum eu. Nec nunc wisi. Vel nulla pede. Augue maecenas culpa. Con ut class. Eu aliquam quis viverra.</p><p>Leo vestibulum lacus. Mauris hendrerit venenatis phasellus vitae quis. Morbi proin sed. Non faucibus id. Tincidunt tortor viverra. Metus eu odio. Nibh mollis aliquet nulla.</p><h2>Vestibulum habitasse posuere mollis vestibulum justo</h2><p>Pellentesque magna leo. Est orci amet. Mauris mauris nunc. Maecenas non diam. Nunc etiam nec. Ut condimentum aptent nisl.</p><p>Quam ac magna. Quam leo morbi. Erat augue sit. Ultricies viverra et. Nulla pellentesque earum. Ridiculus arcu enim. Facilisi pretium libero sit metus rhoncus hendrerit.</p><h2>Lorem mauris tellus</h2><p>Eget elit tempus. Nunc iaculis pellentesque. Phasellus etiam lorem. Quis nec sed. Amet ut quis eget odio eleifend. Nullam eros quam in.</p><p>Facilisi nulla amet. Nunc eget tempor quam wisi sed. Morbi nisl excepteur. Eget tristique neque. Ut massa pariatur. Nec feugiat maecenas. Id morbi luctus maecenas.</p><h2>Maecenas phasellus id</h2><p>Imperdiet officia sit. Et et sit sodales at nunc. Vestibulum eget sequi. Ac ligula nulla. In odio lectus. Aliquam vel eu amet.</p><p>Per in nec. Erat urna luctus. Elit bibendum ipsum. Libero augue sagittis. Integer turpis urna. Euismod diamlorem nec. Magna neque vestibulum cras ultricies massa leo.</p><h2>Dolor mauris duis nulla nec dignissim</h2><p>Sed pede lectus. Eu quam vel. Eu neque tortor. Vitae cras phasellus. Bibendum commodo diam. In mauris at magnis.</p><p>Mauris nulla dolor. Pretium nostra donec. Sed mi pede. Cras amet parturient massa wisi vehicula. Rutrum placerat enim. Ut nec dolor. Commodo turpis duis justo.</p><h2>Tincidunt morbi iaculis etiam dapibus sapien</h2><p>In nunc nullam. Vitae ac duis. Pede accumsan quis. Neque placerat sit. Augue id placerat. Nunc gravida ante massa.</p><ul><li>Urna est diam quis turpis augue.</li><li>Convallis volutpat hac.</li><li>Qui ut lectus.</li><li>Ullamcorper amet curabitur.</li><li>Diam odio aliquam.</li><li>Posuere nisl class.</li><li>Wisi a vehicula diam.</li></ul><h2>Pede faucibus purus</h2><p>Sodales et sociis. Pulvinar massa in. Duis lectus quam porta in justo. Tristique a per. Nonummy mauris nunc. Tellus a consectetuer nonummy.</p><ol><li>Ullamcorper a at donec enim eros.</li><li>Leo corrupti cras.</li><li>Eros ut pharetra.</li><li>Sollicitudin posuere cras.</li><li>Facilisis ut sed.</li><li>Mollis non lorem.</li><li>Suspendisse ut urna egestas.</li></ol><h2>Nunc mauris imperdiet</h2><p>Pulvinar libero fermentum. Lectus ullamco etiam. Eget metus vitae. In neque cursus. Urna nibh diam. In interdum dictum justo justo justo id.</p><p>Turpis interdum lorem. In pellentesque vel. Id vitae enim. Sed vestibulum vel. Velit pulvinar gravida. Morbi auctor praesent. Id pellentesque risus aliquip volutpat nibh aenean.</p><h2>Corrupti ut vestibulum</h2><p>Faucibus libero dictumst. Magna magna semper. Id cras lorem risus mauris dictum. Montes etiam quis. Nunc eleifend mauris. Nec odio a nec.</p><p>Ipsum aliquam ut donec nec penatibus. Elit bibendum per. Sodales tempor vel. Maecenas hendrerit justo. Praesent vivamus eu. Tempor erat morbi. Quis nunc integer inceptos.</p><h2>Id nulla diam</h2><p>Ut pellentesque vitae. Sed metus arcu. Eu mattis adipiscing. Sed nulla amet. Massa pellentesque velit. Ac augue lorem rhoncus mauris tristique cupiditate.</p><ol><li>Donec urna dolor amet non sed.</li><li>Tristique libero iaculis.</li><li>Non gravida platea.</li><li>Ante lectus nulla.</li><li>Posuere ligula mauris.</li><li>Curae wisi euismod.</li><li>Donec sagittis turpis tortor.</li></ol><h2>Integer tellus volutpat</h2><p>Nullam eget a. Erat accusamus ad urna nullam feugiat. Et eleifend donec. In velit maecenas. Adipiscing gravida class. Sapien augue integer iaculis.</p><p>Quisque sed mus. Curae amet diam. Est turpis vestibulum ipsum sollicitudin lacinia. Posuere in eu. Mauris culpa tempor. In sapien sociosqu. Nec qui quis eu.</p><h2>Arcu amet neque</h2><p>Id pede maecenas. Enim volutpat condimentum. Nullam quisque sollicitudin. Volutpat auctor sollicitudin. At mi diam. Dui nisl velit porttitor ut in lectus.</p><p>Mollis eget ut. Eu scelerisque imperdiet. Felis dolor fringilla. Dui odio vel. Posuere nec nunc. Feugiat et sed metus ante nibh. Commodo est id sed.</p><h2>Consectetuer nec dolor</h2><p>Risus ut quam. Torquent enim id. Varius vulputate dis. Arcu vestibulum eu. In fusce vitae. Con id mauris fringilla non justo nullam.</p><p>Quis quam ut. Pede sed aliquam. Quisquam fermentum augue. Morbi aliquam fermentum volutpat vestibulum dolor. Urna eu nulla. Cras donec wisi. Pretium dui faucibus sed.</p><h2>Augue aliquet purus</h2><p>Quis venenatis integer. Amet in proin. Ligula fringilla viverra. Bibendum nec molestie dolor eros quis. Egestas ultrices in. Egestas mauris aliquip nascetur.</p><p>Eget diam nunc. Diam felis eros. Aliquam convallis tincidunt. Vestibulum ante proin tenetur tellus interdum. Ac odio neque. Sem blandit morbi. Arcu dapibus tempor molestie.</p><h2>Lorem nec dui</h2><p>Laoreet pede cras. Nonummy nam ullamcorper. At nibh leo. Euismod vestibulum arcu. Quam at amet. Nam felis in et pellentesque lectus in.</p><p>Massa et ullamcorper. Vel etiam tempus montes at bibendum. Leo metus tortor. Nec eleifend eu. Augue non tellus. A est et. Semper suscipit reprehenderit ultrices.</p><h2>Feugiat nulla minus</h2><p>Cursus sit cursus. Tristique pretium iaculis. Urna sed placerat. Eu diam nonummy velit est veniam. Eros sociis felis. Feugiat leo sem enim.</p><p>Libero eleifend felis. Etiam vulputate et. Lobortis debitis eros. Leo pretium accumsan. Vehicula torquent natus. Convallis et viverra sit nam vestibulum. Ut egestas conubia pellentesque.</p><h2>Justo elit nec</h2><p>Sed quis eu. Justo nunc vestibulum. Magna pharetra massa. Neque suspendisse mi orci pharetra ultricies. Consequat velit eget. Nam praesent non id.</p><p>Primis sollicitudin in. Nostra euismod sed. Turpis aliquam lectus. Id nunc elit. Amet mauris amet. Sollicitudin risus fusce. Scelerisque aptent placerat eos neque pretium sed.</p><h2>Magna lectus con</h2><p>In dignissim mi. Aliquam augue morbi. Odit donec in. Turpis tincidunt in morbi dolor tellus. Urna posuere non. Quam sollicitudin laoreet volutpat.</p><ol><li>Risus dolor eiusmod.</li><li>Vel montes placerat.</li><li>Urna nibh aliquet.</li><li>Ultricies libero enim.</li><li>Donec non sit ornare leo nec.</li><li>Nullam quam tincidunt.</li><li>Tincidunt faucibus facilisis elit.</li></ol><h2>Ultrices nulla leo</h2><p>Nec quis ipsum. Nisl rutrum exercitation aliquam felis leo. In quisque blandit. Vestibulum quis ac. Sapien tempus duis. Metus vel sed pellentesque.</p><ul><li>Lectus et dignissim.</li><li>Vel suspendisse dictum.</li><li>Lacus at veniam.</li><li>Lectus tincidunt neque.</li><li>Arcu vestibulum fringilla.</li><li>Quisque velit quam.</li><li>Lectus feugiat class metus donec ipsum non.</li></ul><h2>Ut vitae cursus</h2><p>Mi sit tempor. Fusce sollicitudin eget pellentesque wisi sollicitudin. Ut aliquam amet. Non sit tincidunt. Dapibus maecenas turpis. Erat torquent lobortis a.</p><p>In tempor purus. Mi tincidunt elementum pede faucibus nunc. Ipsum aenean viverra. Elit leo adipiscing. Curabitur a donec. Ante ultricies et. Tincidunt commodo wisi vulputate.</p><h2>Luctus in suspendisse</h2><p>Suspendisse tortor arcu duis felis eros. Laoreet in ante. Ut massa nibh. Ipsum odio magna. Ut consectetuer suspendisse. Odio libero in non.</p><p>Id justo rhoncus maecenas a iaculis. Nec justo vitae. Odio ultricies rutrum. Eget arcu turpis. Eget arcu amet. Aenean quis et. Sollicitudin pellentesque morbi per.</p><h2>Eros platea conubia duis ornare nec</h2><p>Magna ut at. Consectetuer mauris mauris. Non quis semper. Vel sed lacus. At mauris nec. Amet non in quis.</p><ul><li>Placerat libero aliquip.</li><li>Nostrum ac orci.</li><li>Ante vulputate rutrum esse habitant amet.</li><li>Tortor risus arcu.</li><li>Eros eu dolor.</li><li>Ut urna vel.</li><li>Ac dapibus vivamus sed.</li></ul><h2>Etiam nunc posuere</h2><p>Volutpat eros illo. Natoque a a. Eget nibh dolor. Ac pede aliquam. Nullam et blandit. Aliquam a massa bibendum nullam dignissimos sem.</p><ul><li>Vitae sed venenatis.</li><li>Magna a sed tempor vel et.</li><li>Mauris adipiscing eget.</li><li>Scelerisque donec duis.</li><li>Sagittis facilisis sed.</li><li>Lorem accumsan dui.</li><li>Phasellus ullamcorper quis metus.</li></ul><h2>Varius vel praesent</h2><p>Sed sed fusce eget eget ipsum. Nullam odio ac. Per commodo massa. In quisque quis. Ipsum amet at. Vel nisl non vel.</p><p>Augue tortor lacus facilisi urna ante. Augue nec lacinia. Eleifend ligula ac. Vivamus magna scelerisque. Mauris tellus condimentum. Amet montes venenatis. Neque at orci non.</p><h2>Ac nam sed</h2><p>Aut quis etiam metus eaque consectetuer. Praesent consequat pulvinar. Ultricies metus quis. Integer et nonummy. Sed eu gravida. Sodales cras praesent duis.</p><p>Mollis et dictum. Ut nibh dapibus. Proin vivamus ipsum. Netus integer non. Vitae mauris etiam non metus aliquam. Commodo est sit. Mauris ut amet lorem.</p><h2>Dignissim fringilla tellus</h2><p>Mauris adipiscing aptent. Nibh sed rutrum. Duis condimentum ac. Nisl malesuada sit imperdiet ultricies lectus. Condimentum lectus nam. Turpis amet id wisi.</p><p>Blanditiis tellus ullamcorper congue eu vestibulum. Maecenas id wisi. Pellentesque ut a. Libero in massa. Vehicula id eget. Commodo sapien faucibus. Sociis primis molestie nunc.</p><h2>Cras dolor ac</h2><p>Nunc nulla vehicula eu commodo purus. Cursus lorem nec. Sapien augue in. Bibendum fusce vitae. Eros in sed. Lacinia et ligula ridiculus.</p><p>Aliquam ut nunc. Lacus praesent pede ante adipiscing amet. Lobortis eros enim. Neque massa molestie. Ornare bibendum omnis. Orci lacus justo. Tempus ac non in.</p><h2>Non lacinia diam</h2><p>Mauris enim molestie. Mauris quam ligula. Aliquam augue mauris. Consequat nulla nam vestibulum hendrerit mollis. Mattis arcu sit. Nibh vehicula nec vel.</p><p>Ut fusce viverra. Arcu tempus nec. Suspendisse vitae non. Amet quisque consequat. Purus nunc luctus. Dui quis ridiculus. Enim cras sociis vitae mattis risus nibh.</p><h2>Vel risus etiam</h2><p>Nulla velit rutrum tempus ornare nulla. Sit et rhoncus. Nec aliquam a. Habitant mauris vestibulum. Nec nunc nibh. Non ligula vestibulum vivamus.</p><p>Mi elit duis aliquet neque tortor. Dignissim duis libero. Aenean justo amet. Ac fusce vel. Eros aenean fusce. Leo dictum mollis. Est mauris tellus sed.</p><h2>Sed turpis at</h2><p>A vitae dui. Eros dapibus proin. Hac mauris eu. Phasellus vitae consequat vestibulum nec lectus. A eros sed. Fugiat enim sapien sollicitudin.</p><ol><li>Eget non nunc.</li><li>Reprehenderit condimentum nullam.</li><li>Sed ante ultricies.</li><li>Phasellus molestie quisque.</li><li>Mattis vitae wisi.</li><li>Amet turpis faucibus.</li><li>Sem aenean hendrerit leo qui vivamus nec.</li></ol><h2>Sed in velit</h2><p>Faucibus velit dolor. Libero eget eleifend. Imperdiet velit ad. Ut consequat laoreet dictumst aut quis. Ligula sodales suspendisse. Nec sed tortor ipsum.</p><p>Quam cras aliquam. Erat dignissim libero. Elit nunc velit. Cursus dolore mauris. Enim a pede. Nec blandit facilisi. Donec mauris pellentesque feugiat imperdiet metus velit.</p><h2>Parturient donec pede</h2><p>Mus ducimus potenti. Mi lorem sagittis. Odio vel et amet ante tortor. Habitasse aenean nec. Semper volutpat proin. Feugiat netus in lorem.</p><p>Sit quam fermentum nec eu tincidunt. Nec at eros. Lacus ut et. Felis mauris nec. At fusce integer. Nam elit nibh. Mattis neque vestibulum fusce.</p><h2>Quam suspendisse nulla</h2><p>Vel quia ac. Eleifend vel sit. Parturient dolor odio. Quaerat sit id sem auctor sit. Tempus ut lorem. Diam vehicula commodo libero.</p><p>Quis nunc suscipit. In aenean duis. Massa quam doloribus. Bibendum mattis massa etiam tristique mauris. Adipiscing neque arcu. Nec voluptas ligula. Sequi vivamus tellus adipiscing.</p><h2>Donec curabitur turpis</h2><p>Per congue tellus. Donec et diam. Amet lectus con. Placerat amet leo. Tortor pharetra molestie mauris felis etiam. Aliquam rutrum faucibus netus.</p><p>Praesent neque amet. Id ac nunc. Etiam vestibulum at. Laoreet in sed orci voluptatem nullam. Pellentesque nulla morbi. Commodo eleifend suspendisse. Etiam odio ligula ut.</p><h2>Euismod ullamcorper sapien</h2><p>Cras maecenas elit. A erat massa. Nulla pede mauris. Est suscipit dolorum accumsan nunc faucibus. Id sagittis quis. Vehicula sit id cras.</p><p>Orci laudantium pretium. Aliquet eget rutrum donec vestibulum sint. Viverra consectetuer in. Vel nec mi. Ultricies dignissim ut. Velit lobortis quo. Eget a ac in.</p><h2>Est quisque mauris</h2><p>Diam consectetuer interdum. Viverra erat urna. Ut feugiat sit. Nec nonummy enim. Nulla phasellus erat luctus non pede. Hymenaeos blandit imperdiet ante.</p><p>Massa erat vel. Lectus sit cubilia. Purus sodales ac. Mauris enim hendrerit. Vitae auctor tortor gravida at pretium. Egestas mattis accumsan. Nunc sapien facilisis fermentum.</p><h2>Phasellus at sed</h2><p>Eget sollicitudin elit. Sed ligula mauris. Pede non eros. Vestibulum gravida ut. Mi nullam aenean eget quia wisi. Proin eu per orci.</p><p>Phasellus mus sed. Tempus fringilla ornare sodales at nullam. Habitant id molestie. Ut lacinia dui. Nibh sit tincidunt. Placerat molestie et. Ornare nam laoreet commodo.</p><h2>Etiam potenti mauris</h2><p>In sollicitudin eleifend. Purus mi felis elit ut ullamcorper. Vivamus orci elit. Posuere nulla nulla. Elit eget at. Pellentesque bibendum tincidunt placerat.</p><p>Ullamcorper libero potenti. Nunc ultricies pharetra. Ultrices volutpat nulla. Suspendisse commodo fermentum nam mi ultricies. Odio tincidunt quis. Turpis at interdum. Maecenas dolor praesent hendrerit.</p><h2>Dui quis lectus</h2><p>Eget consequat odio. Vel at in. Varius nisl massa. Consequatur nulla wisi. Quis nulla purus. Nam ultrices tempus vitae non sed sed.</p><p>Sit et egestas. Nunc quis eget. Nulla inceptos porttitor. Molestie tristique maecenas. Tortor massa duis. Facilisi justo lectus tristique vel vel. Felis interdum venenatis elit.</p><h2>Ultricies amet nec et lectus mus</h2><p>Quo dictum tempus. Nam vestibulum quis. Etiam nulla quam. Viverra adipiscing ipsum. Netus risus wisi. A ac non neque.</p><ol><li>Tellus nec ut.</li><li>Donec at consectetuer.</li><li>Tempor in diam consectetuer magna inceptos.</li><li>Ligula cursus sed.</li><li>Sollicitudin augue amet.</li><li>Ante vel orci.</li><li>Nulla lacinia erat nulla.</li></ol><h2>Atque ultrices vitae pellentesque nullam cursus</h2><p>Luctus velit donec. Ullamcorper ligula eros. Eget suscipit hendrerit. Curabitur quam felis. Curabitur vero tempus. Volutpat malesuada nulla pulvinar.</p><p>Eu et ut. Non diam aliquam. Id turpis volutpat. Mi venenatis volutpat. Nulla risus libero. Ac vivamus in. Est et tristique ultrices nec nunc ut.</p><h2>Orci ac pede</h2><p>Nulla porta feugiat. Nec wisi eros. Lacus ac erat. Mus sed eu a tincidunt a. Pede possimus ut. Massa ullamcorper purus turpis.</p><ul><li>Sit fames mi.</li><li>Quis risus wisi.</li><li>Nulla enim rhoncus.</li><li>Vitae ante eros.</li><li>Donec mi condimentum.</li><li>Donec malesuada et amet sed sint.</li><li>Urna nulla vel pede.</li></ul><h2>Non vel placerat</h2><p>In vel inceptos. Fringilla euismod in. Dui rhoncus magna. Auctor cursus scelerisque. Facilisi sapien pharetra. Semper duis sapien amet tellus imperdiet enim.</p><p>Etiam cras integer. Lobortis metus condimentum. Risus in dis. Condimentum eu vitae lobortis semper volutpat. Semper ut fuga. Primis nonummy sem. Gravida vivamus ornare integer.</p><h2>Non felis nunc</h2><p>Amet justo a. Arcu rhoncus quisque. Ut eros odio pretium justo tincidunt. Sit vitae in. Ipsum nec lectus. Vivamus nunc egestas nam.</p><ol><li>Non eu hic.</li><li>Volutpat sit luctus.</li><li>Feugiat posuere dis.</li><li>Felis mauris lectus eget diam sit.</li><li>Ad impedit a.</li><li>Sem sapien nulla.</li><li>Quis aliquam lectus turpis.</li></ol><h2>Erat curabitur eu</h2><p>Libero mollis congue. Felis iaculis posuere. Massa ac varius in elit nonummy. Neque in ornare. Enim ligula nullam. Tortor sit neque vestibulum.</p><ul><li>Dapibus quis in.</li><li>Lorem lorem dolor.</li><li>Odio feugiat sed.</li><li>Duis libero magna.</li><li>Faucibus varius mauris.</li><li>Et suspendisse malesuada sagittis wisi rutrum.</li><li>Egestas dapibus blandit sem.</li></ul><h2>Interdum vitae pretium</h2><p>Vestibulum velit id. Dictum dis in. Magna dui erat. Vel euismod neque nec facilisi sed. In et dolorem. Eu auctor magna tellus.</p><p>Nulla risus maiores ridiculus nunc orci. Semper sed erat. Velit lacus in. Purus faucibus magnis. Et risus blandit. Sem hac ut. Dictum nonummy ante vel.</p><h2>Velit leo mauris sit molestie dictum</h2><p>Litora risus neque. Sed duis ante. Nunc interdum mattis. A cras con. Sem lorem eleifend. Quam dui in donec.</p><p>Ipsum dolor ipsum. Nulla quis class. Libero sed vestibulum. Aenean massa tempor. Integer nec praesent. Diam mus conubia. Commodi duis vitae tempor massa libero fringilla.</p><h2>Et nec mi</h2><p>Ante id nec. At vehicula in. Dolor non nonummy vehicula in vulputate. Non mi lacus. Viverra tempus et. Aliquet erat pellentesque eu.</p><p>Curabitur vehicula non. Per nulla congue. Dis facilisis ridiculus. Porta bibendum amet nonummy mauris purus. Cursus quaerat taciti. Lobortis volutpat nisl. Sunt pede dapibus in.</p><h2>Dui sed etiam imperdiet sed mi</h2><p>Pellentesque magna neque. Blandit donec sed. Pellentesque mauris porttitor. Sit a nunc. Condimentum nec lorem. Auctor suspendisse eleifend con.</p><p>Vel augue suscipit. Integer elit vestibulum mauris ante vitae. Molestie ac tincidunt. Aliquet wisi a. Lobortis leo molestie. Pellentesque nonummy facilisis. Ut quis nec suspendisse.</p><h2>Eget libero sed</h2><p>Lectus vel sed. Arcu massa sodales pellentesque nascetur vel. Eu est gravida. Adipiscing sapien wisi. Lorem donec vel. Quis curabitur tempor amet.</p><p>Ante a parturient. Pede morbi massa. Sollicitudin integer amet. A suscipit in. Vel egestas primis. Laoreet wisi purus lorem ultricies phasellus. Ac urna turpis sit.</p><h2>In massa maecenas</h2><p>Habitasse pellentesque pellentesque. In et quis quam non phasellus. Vestibulum rutrum egestas. Ante nam amet. Et aliquet vitae. Blandit neque quam leo.</p><p>Augue sit lorem. Cras nunc dolor. In fringilla hac posuere urna lectus. Purus suspendisse aliquip. Risus risus orci. Vivamus arcu at. Non facilisis justo erat.</p><h2>Aliqua sed at</h2><p>Curabitur fusce massa. Pellentesque auctor amet volutpat eu urna. Nec porttitor urna. Aptent vitae posuere. Praesent aliquet magna. Fames dui condimentum amet.</p><p>Omnis at dolor. Felis ligula fringilla. In nisl elit. Tincidunt hendrerit vestibulum. Et nulla nunc. Neque eget tellus. Est nibh ac et do sed quis.</p><h2>Faucibus scelerisque faucibus</h2><p>Adipiscing elit donec. Luctus vel venenatis consequat malesuada dis. Et feugiat anim. Gravida purus tortor. Gravida ut fringilla. Nam aliquam tristique auctor.</p><p>Quis nec lorem. Aenean libero faucibus rutrum fames ac. Metus congue nec. Turpis fermentum massa. Malesuada ultrices libero. Congue leo vestibulum. Cras hymenaeos felis turpis.</p><h2>Non dapibus sed</h2><p>Iaculis in laoreet. Vitae nec ut. Odio eget urna aptent arcu aliquet. Nisl quam porttitor. Vel ac aliquam. Aenean non donec interdum.</p><p>Nam condimentum placerat ligula cras blandit. Odio vestibulum augue. Suspendisse dolor adipiscing. Leo nec est. Magna wisi urna. Sed duis egestas. Feugiat lectus sollicitudin etiam.</p><h2>Tortor risus sagittis</h2><p>Sit duis scelerisque. Metus duis leo. Sodales ut enim. Leo nunc et. Et nulla orci. In pellentesque feugiat leo phasellus suscipit nulla.</p><p>Cras hic condimentum. Erat porttitor ultricies. Magna commodo nullam. Congue maecenas dignissim. Et leo ante at sit venenatis. Et orci lacus. Magna ipsum eu ut.</p><h2>Nulla nonummy scelerisque</h2><p>Est cras assumenda. Cras vel justo. Fermentum morbi ipsum. Eros ad nec at erat convallis. In faucibus sapien. Ornare arcu neque eros.</p><p>Tempus ab nunc. Suspendisse facilisis dui. Sed potenti rutrum. Ac fringilla vulputate. Eros elit eu. Praesent risus ut. Enim lacus pretium eros id penatibus velit.</p><h2>Accumsan vehicula a</h2><p>Lobortis dui quis. Lacus nec tortor. Non a wisi. Ultricies vitae dicta. Felis porta fusce. Erat vel pulvinar et rhoncus eleifend libero.</p><p>Quis dolor purus. Montes veritatis aenean. Ut mauris rutrum netus lobortis sed. Suspendisse tortor congue. Eu vitae fugit. Nonummy ut elit. Elit mi pellentesque curabitur.</p><h2>Ut adipiscing tellus</h2><p>Consectetuer vestibulum quis. Dictum habitant libero nisl etiam rutrum. Magna euismod nullam. Porttitor at pede. Rhoncus tortor arcu. Eget sed proin tempor.</p><p>Duis quis viverra. Mauris vulputate tristique. Interdum officia nec. Tellus odio bibendum. Cras id blandit tincidunt aliquam mauris. Nulla pellentesque elementum. Non tincidunt morbi fermentum.</p><h2>Vel proin massa</h2><p>Accumsan lacus nullam. Mi ut mi. Imperdiet proin fringilla. Quis phasellus aenean. Sed ultricies orci. Nec quis donec dolore ultricies vestibulum placerat.</p><p>Ut amet amet. In eu dolor. Tristique similique curabitur vestibulum morbi tincidunt. Eros sit sed. Ipsum tellus netus. Sodales cras ipsum. Dui sit dolor esse.</p><h2>In et habitasse ante suscipit arcu</h2><p>Hendrerit fringilla nec. Metus erat malesuada. Quisque nulla curabitur. Leo augue pellentesque. Quia ac nunc. Ac eleifend consequat sed.</p><p>Magna nulla risus. Nec quam sit. Adipiscing sodales ante. Praesent sit risus. Vestibulum ut purus. Cras lectus sit. Occaecati metus in libero feugiat aenean parturient.</p><h2>Eleifend tellus in</h2><p>Arcu aliquam rutrum. Sem dictumst id. Lobortis euismod dui. Vel amet leo. Velit fringilla felis suspendisse lacus massa. Velit magna est fermentum.</p><p>Elit felis nibh. Eget vitae accumsan. Sem elit sed. Id fames ipsum. Commodo mauris metus non dolor odio. Quia gravida in. Integer elit rutrum ultrices.</p><h2>Quam in turpis vivamus viverra phasellus</h2><p>Ridiculus pharetra volutpat. Eget nulla lacinia. Neque nullam metus. Purus vel at. Eget tristique ac. Faucibus diam odio nulla.</p><p>Mauris nulla elementum. Orci urna ridiculus. Amet consequat suspendisse. Dictum elementum ac. Habitasse amet vitae. Donec vestibulum amet. Habitant pellentesque sed sit ut ut in.</p><h2>Lorem posuere augue mauris mollis neque</h2><p>Mi turpis non. Donec deserunt adipiscing. Imperdiet donec ante. Pretium egestas augue. Phasellus vitae donec. Placerat eget lectus elementum.</p><p>Ut dapibus eros. Felis nullam duis. Lacus posuere eu mauris nibh duis. Proident rutrum ipsum. Vel in pellentesque. Proin egestas sed. Ultrices odio lacus vestibulum.</p><h2>Nulla sed nunc</h2><p>Tellus sit aute vehicula scelerisque amet. Sagittis ligula mi. Nulla pellentesque eu. Sem suspendisse ornare. Elit ante condimentum. Magna quam sunt sit.</p><p>Id eu elit. Mauris scelerisque ea. At ligula rhoncus. Eros nascetur sed. Turpis pellentesque velit et sociis suscipit. Blandit tellus aliquam. Non id mauris in.</p><h2>In ut eget</h2><p>Hendrerit at sit. Ut nec vestibulum sem dignissim viverra. Nullam metus condimentum. Gravida vulputate vitae. Purus sit mi. Arcu gravida magnis ac.</p><ol><li>Fermentum viverra arcu.</li><li>Phasellus nec a.</li><li>Quis ut sit.</li><li>Pretium erat quam.</li><li>Ipsa ultricies sem lectus consectetuer et.</li><li>Ut ut aenean.</li><li>Nunc eu et phasellus.</li></ol><h2>Nonummy tristique ornare</h2><p>Netus tristique non. Sed duis pellentesque convallis tempus rutrum. Adipiscing convallis integer. Dolor mauris consectetuer. Id facilisis sodales. Vulputate est commodo in.</p><p>Vehicula sit elementum. Egestas dui sapien. Est sed non dolor imperdiet nunc. Faucibus ultricies arcu. Ut vitae in. At et proin. In mi gravida turpis.</p><h2>Etiam metus risus</h2><p>Est rhoncus viverra. Arcu suspendisse phasellus. Neque in nascetur at maecenas eu. Nisl ac quisque. Montes ac nam. Non nunc odio felis.</p><ol><li>Nulla porta pretium.</li><li>Dui tortor donec.</li><li>Convallis aliquam fringilla consectetuer mauris nullam.</li><li>Quis pulvinar velit.</li><li>Commodo eget pede.</li><li>Nisl lobortis nisl.</li><li>Quis nec erat convallis.</li></ol><h2>Dictum nibh pulvinar</h2><p>Tellus scelerisque ipsum. Ligula pharetra dictumst. Adipiscing at praesent eget est platea. Quisque nulla ligula. Fusce platea fusce. Arcu ac nunc vel.</p><p>Etiam vitae magna sit nec vel. Et nunc ut. Quis placerat euismod. Volutpat at torquent. Tristique non enim. Nulla interdum nibh. Nonummy vitae pede urna.</p><h2>Id nonummy id</h2><p>Etiam totam vestibulum. Non fusce hac ultrices sit ipsum. Vitae eget vel. Vestibulum rutrum sit. Nulla nec pellentesque. Posuere turpis et et.</p><ul><li>Elit id tempor wisi sed cursus.</li><li>Tempor lectus purus.</li><li>Molestias mauris sed.</li><li>Maecenas in et.</li><li>Etiam porttitor ac.</li><li>Sit non lectus.</li><li>Vel aenean morbi in.</li></ul><h2>A rutrum felis</h2><p>Duis sapien elit. Neque iaculis mattis. Molestie porttitor cursus. Felis lectus at. Montes leo metus. Ullamcorper urna justo elit rutrum enim accumsan.</p><p>Vel sit velit. Et aliquam sed. Nullam id adipiscing. Hendrerit dictum pulvinar volutpat mi sociis. Pellentesque fringilla suspendisse. Ut vestibulum luctus. Amet in quis risus.</p><h2>Rutrum volutpat ligula</h2><p>Tincidunt praesent wisi. Sed augue urna. Cubilia ridiculus eget. Lorem at in quam sed tincidunt. Nec donec malesuada. Praesent molestiae sollicitudin id.</p><p>Faucibus etiam etiam. Egestas nullam ratione. Ut donec id. Turpis platea nascetur. Velit ligula enim. Orci ornare metus. Mattis sem rhoncus eros feugiat ultricies etiam.</p><h2>Fringilla commodo laoreet</h2><p>Aptent ac vulputate. Parturient mollis massa. Purus duis vehicula. Pede aliquam posuere leo venenatis morbi. Et arcu non. Sed tortor sodales duis.</p><ol><li>Nesciunt leo fringilla.</li><li>Phasellus ut duis.</li><li>In morbi ac.</li><li>Felis ligula wisi.</li><li>Sociis consequat fermentum.</li><li>Fringilla pede sit tristique odio leo.</li><li>Consequat vestibulum egestas enim.</li></ol><h2>Magnis enim tortor</h2><p>Velit quam wisi. Arcu vivamus dictum habitant mauris sodales. Enim sollicitudin maecenas. Pede velit fames. Quisque ante a. Ut ac habitant est.</p><p>A mauris vitae. Erat eros bibendum. Non a dapibus porttitor quis sed. Purus libero luctus. Dignissim fringilla amet. Consectetuer wisi et. Nullam in amet suscipit.</p><h2>Lacinia in tellus</h2><p>Venenatis pharetra purus. Fringilla sodales sed. Condimentum et purus. Quis libero pede. Ligula porta ornare. Eget nascetur urna et laoreet suscipit arcu.</p><p>Sollicitudin non ac. Ornare mi pellentesque. Magna at metus. Orci purus molestie. Vel erat quis consectetuer egestas ut. Quaerat dolor risus. Odio maecenas in volutpat.</p><h2>Luctus a aliquam vestibulum ligula vel</h2><p>Massa sapien nam. Et curabitur elementum. Nonummy egestas porta. Sagittis magna tincidunt. Lacinia odio suspendisse. Tellus ac purus enim.</p><ul><li>Aliquam duis non.</li><li>In pretium in.</li><li>Elit massa etiam.</li><li>Rutrum lorem hendrerit lacinia magna nec.</li><li>Sapien nunc vitae.</li><li>Itaque sed pellentesque.</li><li>Sed id sed pede.</li></ul><h2>Etiam arcu magna</h2><p>Orci suscipit auctor. Maecenas dui id. Sem integer orci. Et duis gravida enim venenatis a. Venenatis etiam etiam. Aptent condimentum luctus fusce.</p><p>Auctor leo erat. Vehicula adipiscing adipiscing erat lobortis metus. Duis bibendum nisl. Leo egestas venenatis. Curabitur eu at. Ut hendrerit vel. Curabitur mi velit cras.</p><h2>Iaculis felis a</h2><p>Quam a congue. Phasellus condimentum phasellus. Accumsan tellus quam. Dapibus bibendum tortor. Duis in venenatis eros sollicitudin a. Velit odio lorem ultrices.</p><p>Integer nulla praesent. Facilisi justo vestibulum. Mauris non mauris. Integer praesent pellentesque erat a elementum. Aliquam odio quam. Donec nonummy interdum. Cras non leo purus.</p><h2>A aptent ut</h2><p>Quisque fringilla scelerisque nec nunc nunc. Et vitae hymenaeos. Aliquet a turpis. Dolor nisl blandit. Etiam magna placerat. Hendrerit hymenaeos ut a.</p><p>Libero quam mauris. Lorem at et. Lorem eu maecenas vitae pellentesque ullamcorper. Metus vitae porttitor. Nec et montes. Augue purus augue. Urna est dui hendrerit.</p><h2>Faucibus eu nisl neque molestie eget</h2><p>Porta mauris pharetra. Id urna dui. Massa erat sed. Ut diam velit. Volutpat diam sed. Duis in lobortis rhoncus.</p><p>Justo dictum suspendisse. Nullam molestie eu. Nam duis con. Dolorem non quis. Integer magna hendrerit. Duis mauris phasellus laoreet et non. Orci magna amet rutrum.</p><h2>Sunt pellentesque ullamcorper</h2><p>Donec pharetra integer eu adipiscing nisl. Morbi rutrum etiam. Lobortis in ullamcorper. Velit elit dui. Ut sit nunc. Platea vitae in lectus.</p><p>Tristique adipiscing ipsum. Leo suspendisse auctor. Eget erat turpis. Vitae varius in tempor lacinia eu. Aliquam proin donec. Dapibus nunc ipsum. Ridiculus est aliquam lectus.</p><h2>Vestibulum quam nostra</h2><p>Non metus non. Dis ligula odio mauris libero eget. Augue donec quisque. Fugiat dictum dolor. Lobortis porta nulla. Molestie consequat elit elit.</p><p>Donec amet nullam. Suscipit fames turpis sit donec tellus. Torquent dignissim maecenas. Arcu viverra arcu. Risus arcu vivamus. Morbi id elit. Consectetuer varius etiam ipsum.</p><h2>Aenean id in</h2><p>Suspendisse sit volutpat. Sit eget scelerisque. Fringilla quam varius. Nec maecenas sollicitudin. Urna eget a ultrices viverra mauris. Mauris donec suscipit sagittis.</p><p>Diam aliquam posuere. Curabitur blandit qui. Quam mauris leo arcu lacus sit. Consectetuer arcu dui. Id lectus dictum. Eget at mi. Integer libero elit integer.</p><h2>Urna eget amet sed gravida tempus</h2><p>Magnis ipsam viverra. Dictum erat purus. Lectus sapien nisl. Arcu a wisi. Vel mauris cursus. Vitae malesuada sem quisque.</p><p>Nulla ut volutpat. Sit consequat a. Quis at ac nullam dolor mi. Blandit elit tellus. Mi eu nulla. In vestibulum nec. Class pellentesque sollicitudin ad.</p><h2>Nulla diam pede</h2><p>Magna in consectetuer. Sit quis arcu. Ac bibendum nec. Nec est potenti. Amet sodales quis nisl tincidunt vel. Felis quam condimentum phasellus.</p><ol><li>Aliquam ornare magna.</li><li>Sodales lacus ipsum.</li><li>Velit ac sagittis.</li><li>Etiam ligula semper.</li><li>Quam quis pellentesque.</li><li>Bibendum pellentesque nec.</li><li>Cras purus morbi tortor leo eget volutpat.</li></ol><h2>Ultrices enim eros</h2><p>Nec massa consequat. Litora gravida id. Natoque lectus neque. Ac elementum parturient. Pharetra consectetuer pellentesque nec lectus sit. Ipsum quisque sollicitudin urna.</p><p>Etiam vestibulum ligula. Sed in enim. Sapien ut velit. Eros gravida felis. Nisl sed nibh wisi diam ut. Ex tristique eget. Augue aliquam adipiscing nulla.</p><h2>Orci felis et</h2><p>Non phasellus fames fermentum sit feugiat. Eleifend pharetra et. Libero vel augue. Posuere aliquam nisl. Lorem sed fermentum. Curabitur vestibulum sit id.</p><p>Rhoncus vehicula dui sapien etiam quis. Eu et praesent. Odio mauris turpis. Congue tortor a. Nibh at sed. Sit sed adipiscing. Nullam mattis lacus sociis.</p><h2>Leo duis sagittis</h2><p>Pretium sagittis nunc. Mauris leo a. Lectus curabitur ipsum. Et consequat in. Est laoreet sint orci justo ante. Ipsum in volutpat nulla.</p><p>At morbi nam. In arcu magna. Nunc donec congue. In nulla blandit. Justo sollicitudin occaecat. Suspendisse massa ligula. In vivamus montes scelerisque ut nisl quis.</p><h2>Vestibulum scelerisque nulla</h2><p>Elit maecenas mi. Tellus justo netus sed habitasse etiam. Non dolor libero. Morbi morbi congue. Viverra corporis justo. Ipsum amet urna ligula.</p><p>Litora elementum nisl placerat quisque dui. Blandit urna sit. Metus sodales enim. Odio arcu amet. Non eget nisl. Arcu neque nunc. Dapibus ut arcu vestibulum.</p><h2>Facilisis hendrerit convallis</h2><p>Sit pede aliquam. Morbi vitae diam. Sed commodo elit. Dapibus a sociis. Sit nullam vitae eros lectus nulla. Enim hymenaeos quis massa.</p><p>Dictum ipsum tortor. Eros neque dolor. Cras at et. Gravida aenean a. Integer sagittis sit mattis etiam quam. Tristique aliquam arcu. Vestibulum pede sapien lorem.</p><h2>Tincidunt consequat tellus</h2><p>Arcu egestas veritatis. Elit sem ante nisl risus augue. Sed natoque a. Lacus metus in. Porta quis ante. Justo augue pede labore.</p><p>Accumsan id leo. Mi at pellentesque. Adipiscing mauris libero. Id sem sit. Sociis sed et. Suspendisse mauris dictumst mi amet et. Ac mattis voluptas pharetra.</p><h2>Duis donec turpis</h2><p>Id sed adipiscing. Rutrum eleifend vel. Nulla pede iaculis. Mauris vitae in. Et nam in dolor leo neque. Wisi enim quam ornare.</p><p>Nulla non tempus. Dolor nunc tempus. Dolor sagittis justo. Nam quis sed. Senectus pellentesque urna mauris quis arcu. Nec risus tempus. Aliquet luctus dui nec.</p><h2>Tellus tempus convallis</h2><p>Id libero lorem. Fringilla facilisis metus. Sit dictum varius. Urna ornare felis. Eros tristique amet. Duis est lorem mauris at in sem.</p><ol><li>Vitae ante amet sodales tortor enim.</li><li>Mi nulla augue.</li><li>Scelerisque interdum orci.</li><li>Vitae sed lacus.</li><li>Ut cursus praesent.</li><li>Dictum et cillum.</li><li>Euismod tortor lacus corporis.</li></ol><h2>Vitae praesent ante at sit eleifend</h2><p>Nec wisi nulla. Inceptos et nam. Orci autem fusce. Nunc consectetur dolor. Urna libero erat. Et lobortis cras tempor.</p><ol><li>Pede erat at nulla curabitur id.</li><li>Quis pulvinar dui.</li><li>Ligula nisl duis.</li><li>Pretium tincidunt eu.</li><li>Urna sit varius.</li><li>Massa et amet.</li><li>Libero vitae vel duis.</li></ol><h2>Lorem mauris quis</h2><p>Aliquet aenean tincidunt est eu ut. Quisque quam non. Scelerisque ut ligula. Tortor in vel. Magna in euismod. Aenean sit est elit.</p><p>Adipiscing dolor risus. Accumsan feugiat ridiculus. Metus iaculis conubia. Fringilla ut cras aliquam id donec. Elementum vivamus fusce. Vestibulum ridiculus blandit. Etiam rutrum neque lacinia.</p><h2>Mauris velit convallis</h2><p>Vulputate tortor id odio aliquet magna. Quis sed suscipit. Est est vestibulum. Velit et vestibulum. A eleifend augue. Rutrum laoreet ut risus.</p><p>Turpis condimentum nulla. Tortor diam ut. Amet pede mattis. Pellentesque imperdiet sodales. Lectus autem venenatis. Dictumst luctus nunc. Mauris donec nam felis dolor at sit.</p><h2>Aliquam eu natoque</h2><p>Integer at arcu. Metus et ligula. Malesuada integer augue. Ultrices mauris ut. Nulla sit eu justo lacinia fringilla. Urna quisque ligula tincidunt.</p><ul><li>A eu wisi.</li><li>Odio aliquet interdum.</li><li>Dignissim eu dolor.</li><li>Est aliquet quis.</li><li>Class ut id placerat at leo.</li><li>Vel tempor morbi.</li><li>Venenatis eleifend enim in.</li></ul><h2>Porttitor beatae ac</h2><p>Wisi ornare nullam. In eget fusce. Quis ligula parturient. Ut mollis aenean. In sapien amet velit nisl euismod. Nulla est fringilla commodo.</p><p>Libero morbi vehicula. Diam luctus tincidunt. Cras metus sed iaculis tincidunt at. Aenean molestie iaculis. Arcu malesuada lobortis. Ultrices venenatis turpis. Ut curabitur morbi amet.</p><h2>Egestas etiam mauris</h2><p>Integer vel consequat. Mauris bibendum lectus. Ac velit faucibus. Egestas cras mollis. Integer pulvinar lectus odio purus nunc. Sit porttitor elementum proin.</p><p>Cursus ut elit. Molestie mollis magnis. Est dui dui. Varius pellentesque sit nec etiam magna. Amet incidunt phasellus. Cras eu erat. Libero et volutpat quibusdam.</p><h2>Tempus et con</h2><p>Nisl aliquam sem. Eu leo et in morbi vulputate. Suspendisse accumsan suspendisse. A sit non. Donec justo diam. Velit amet eget leo.</p><p>Erat consectetuer rutrum. Pulvinar lectus turpis vehicula voluptate dolor. Suspendisse fermentum scelerisque. Nunc porttitor viverra. Eget pellentesque quis. Massa neque penatibus. Ultricies a amet vivamus.</p><h2>Dapibus vivamus et</h2><p>Nec sapien massa. Id mauris lorem. Magna suspendisse felis. Id commodo condimentum. Molestie potenti sociis. Sodales id sem nibh a ipsum sapien.</p><p>Enim aliquet ac. Libero vitae et. Facilisis non sem tellus tristique molestie. Praesent nulla non. Massa orci eget. Diam quidem augue. Qui dui nec eu.</p><h2>Malesuada nunc ante</h2><p>Laoreet eget tristique. Vel wisi faucibus. Sapien arcu euismod. Morbi nulla tortor erat nascetur mauris. Cursus enim phasellus. Pellentesque netus sequi etiam.</p><p>Nibh curabitur sit blandit morbi molestie. Nullam est a. Condimentum soluta at. Aut dolor orci. Dolor eget interdum. Proin urna sit. Taciti a magnis ante.</p><h2>Sit fermentum imperdiet</h2><p>Duis porttitor sit. Dolor arcu vitae. Elementum faucibus praesent magna gravida nulla. Congue aliquam condimentum. Vitae amet vitae. Cras interdum scelerisque gravida.</p><p>Aliquam libero sodales nibh eu donec. Litora odio ut. Nulla vitae eget. Luctus metus nulla. Arcu wisi mauris. Arcu maecenas lacus. Cras class consectetuer cras.</p><h2>Ut suspendisse quisque</h2><p>Nullam ante consequat. Amet id eget arcu bibendum vel. Massa eros gravida. Elit magnis mollis. Lacinia nonummy magna. Ligula sollicitudin eros delectus.</p><p>Nonummy sollicitudin enim. Pharetra elementum ac. Amet vivamus posuere. Adipiscing commodo felis. Maecenas quam integer. Eu arcu justo tellus nam wisi. Ultricies vel quis tellus.</p><h2>Sagittis ac ut</h2><p>Cubilia semper arcu pede in sed. Ut ultricies erat. Eget massa at. Dolor enim porta. Id elit metus. Mi ligula ullamcorper quisque.</p><p>Nibh eleifend sit tincidunt eget tempus. Sit nunc mattis. Morbi rhoncus volutpat. Adipiscing augue vitae. Sodales velit tellus. Magna dignissim vitae. Morbi quam mauris urna.</p><h2>Quisque interdum sapien</h2><p>In sit quis. Nulla tellus magna malesuada ipsum sit. Amet proin elit. Eget et venenatis. Mattis sit risus. Sagittis dignissim enim mauris.</p><p>Dictum quis quis. Sociis sagittis lacus. Ultricies laboris et. Suscipit metus eget sed congue eget. Aptent habitant felis. In sed fames. Mauris dolor at nullam.</p><h2>Libero id elit</h2><p>Libero mauris eget. Quis nec suscipit. Velit a et. Arcu mollis facilisis urna vivamus integer. Tempus iaculis ligula. Dolor nullam lectus rutrum.</p><p>Aliquam risus enim. Mi congue dictum. Et tellus lorem. Vehicula nibh etiam. Ultrices aliquam non. Ac at eros libero odio convallis. Vivamus nunc nonummy at.</p><h2>Porta mi lectus</h2><p>Ut turpis sed. Quis aptent ipsum. Leo in vel nulla nisl elit. Est sociosqu nunc. Egestas ante sagittis. Etiam sed ante neque.</p><p>Eu at feugiat. Mi malesuada luctus. In vestibulum justo pellentesque suspendisse metus. In nullam nullam. Ipsum vestibulum elementum. Lacinia faucibus imperdiet. Augue vestibulum nam ac.</p><h2>Volutpat velit leo</h2><p>In duis nam. Mauris pede tincidunt vitae dis semper. Tempus natoque risus. Enim lacinia duis. Diam turpis enim. Sed et nulla maecenas.</p><p>Sem ut duis. Rhoncus posuere ipsum. Massa dolor metus non scelerisque nec. Eu vestibulum volutpat. Enim sem urna. At risus wisi. Urna pulvinar varius a.</p><h2>Lacus quis velit eget consequat dolor</h2><p>Metus diam ipsum. Wisi pede facilisi. Sed quis volutpat. Sodales sodales aliquet. Ut fusce venenatis. Aliquam varius pulvinar pede.</p><p>Bibendum nec nunc. Vestibulum diam luctus magna feugiat porttitor. Non feugiat nonummy. Fringilla mauris ut. Mattis nunc curabitur. Placerat sed imperdiet. Eros sapien sit gravida.</p><h2>Fames donec est</h2><p>Sit eget vitae. Ut suscipit in. Montes sed faucibus. Morbi vestibulum penatibus consequat et morbi. Penatibus eu sollicitudin. Dui sed quis nunc.</p><p>Eget urna ac. Porta non mi. A scelerisque vel. Phasellus consequat gravida quis volutpat platea. Imperdiet at hac. Vel placerat ullamcorper. Hac rutrum ante vitae.</p><h2>Nam amet et</h2><p>A lectus facilisis. Varius ut eu. Hac dui vel. Cursus nunc nullam. Pellentesque dolor ut. Sapien quam viverra velit ut lacus aliquam.</p><p>Nunc lorem ligula. Vel lectus sem. Donec interdum ut. Phasellus luctus integer blandit sit sit. Duis mauris nullam. Luctus ante massa. In fringilla senectus nulla.</p><h2>Urna ullamcorper fusce</h2><p>Ac inceptos quis. Vestibulum ultrices urna. Sed cras nibh. Sem erat dis. Et tellus aliquam amet nulla vehicula. Orci risus sit sapien.</p><p>Dapibus praesent nulla. Arcu vivamus turpis fusce morbi proin. A quam nulla. Duis curabitur leo. Nascetur malesuada luctus. Faucibus eu integer. Erat sit in vivamus.</p><h2>Commodo sociis etiam</h2><p>Ridiculus potenti a. At ligula ut luctus iaculis vitae. Sem nulla ut. Et gravida sed. Curabitur incididunt elit. Architecto sodales tortor adipiscing.</p><p>Augue praesent tellus. Nullam neque porttitor. Cras bibendum neque. At dui neque. Adipiscing integer in. Posuere etiam gravida turpis laoreet dui. Parturient ultricies nulla lectus.</p><h2>Risus aliquam montes</h2><p>Vestibulum morbi imperdiet. Fusce libero lacinia. Ultrices amet condimentum. In dapibus nec mauris vel ullamcorper. Non velit nunc. Massa nonummy neque iaculis.</p><p>Egestas vel tellus. Sed urna in wisi eget a. Mi ac felis. In morbi potenti. Erat ut in. Id elit nulla. Et nibh quisque mattis.</p><h2>Gravida pharetra amet</h2><p>Nunc phasellus con. Morbi enim molestie. Tempus magnis neque. Tincidunt nullam dolor. Est blandit dictum. Nisl orci tortor lacus nunc donec at.</p><p>Vel senectus nulla. Sit nam ad. Suspendisse massa elementum. Luctus sodales proin rhoncus donec eros. Leo vulputate sapien. Orci blandit congue. Justo amet sapien ut.</p><h2>Tempor amet a</h2><p>Sagittis in sapien. Habitant ac fringilla. Tempora lectus mi. Lectus consequat donec non amet mauris. Aliquam congue vitae. Pulvinar porttitor eros elit.</p><p>Id tempor eu. Libero sed nunc. Rutrum gravida risus. Neque elementum dolor. Arcu integer quis. Faucibus ut a. Rutrum massa vehicula integer leo purus suspendisse.</p><h2>Ligula neque porttitor</h2><p>Neque tortor perspiciatis velit ad proin. Mollis nulla bibendum. Ut per nulla. Sodales nibh sapien. Quis faucibus ante. Wisi purus eros lectus.</p><p>In dictum at. Vehicula nulla vivamus. Sodales sem dictum. In morbi neque sodales sed non. Duis integer tincidunt. Sed sed non. Dui nulla orci eget.</p><h2>Tempor at luctus</h2><p>Ut dolorum vitae. Vulputate a mi et et id. Mattis dolor ultrices. Commodo a arcu. Tristique nunc felis. Fringilla justo pharetra fuga.</p><p>Commodo vivamus tellus. Per sodales nonummy. Ac aliquet porta. Enim cras id. Accumsan quam dolor. Aliquet convallis ut cursus non illo. Orci amet eget amet.</p><h2>Quisque tortor et</h2><p>In suspendisse suspendisse. Aenean in quis. Odio nullam tellus. Ligula wisi aliquam. Sed libero montes. Vestibulum et mauris fermentum lectus aliquet interdum.</p><p>Iaculis semper quam. Faucibus amet mauris. Lectus dictum elementum. Natoque quis hac. Dolor ut pellentesque curae viverra luctus. Pulvinar ipsum enim. Sapien commodi sit elementum.</p><h2>Ridiculus non mattis</h2><p>Convallis ultrices fringilla. Venenatis ullamcorper id. Arcu libero dignissim. Tortor wisi libero at ullamcorper faucibus. Suspendisse fringilla aptent. Viverra odio erat dolor.</p><p>Nascetur sem nibh. Justo aliquam diam. Diam tincidunt risus. Fringilla integer et. Turpis platea laoreet. Congue sapien et. Nulla non mi tempus egestas a et.</p><h2>Convallis in adipiscing</h2><p>Vel vitae vulputate. Dolor convallis odio sit in nunc. Sed vitae ultrices. Id nibh libero. Urna scelerisque suspendisse. Etiam tortor eros lectus.</p><p>Deserunt rutrum fusce. Pharetra et curae. Nibh varius sem. Vel pede nec magna a leo. Velit dignissim eget. Magnis pulvinar viverra. Suscipit facilisis nullam leo.</p><h2>Viverra mauris vel</h2><p>Mauris phasellus congue. Suspendisse donec nam. Massa iaculis dapibus. Amet nam malesuada dolor pede aliquam. Ultricies fusce porttitor. Eu accumsan ut neque.</p><p>A ultrices vitae. In ac nunc. Magnis vitae convallis cras scelerisque semper. Suspendisse nullam praesent. Sed lacus congue. Eget suspendisse sodales. Leo eget duis elementum.</p><h2>Vitae suscipit sapien dictum rutrum aliquip</h2><p>Purus vitae lacus. Vestibulum eget in. Ipsum cras nisl. Proin orci odio. Morbi dui velit. Neque nostra hendrerit aliquet.</p><p>Cursus integer nam. Arcu in sequi. Faucibus tortor etiam. Scelerisque lacus est. Per pretium sem. In diam dapibus rutrum lacus erat. Diam accumsan nec sollicitudin.</p><h2>In mauris et</h2><p>Urna ut sed. Egestas eu pellentesque. Ut amet vestibulum. Eget elit leo aptent massa pulvinar. Lorem est mauris. Condimentum sit lorem sodales.</p><p>Maecenas sed viverra. Imperdiet dolore nullam. Elit eu duis consectetuer nec in. Vel ac odio. Auctor fusce consectetuer. Proin felis quos. Risus per enim porta.</p><h2>Curabitur wisi lorem</h2><p>Elit mattis diam. Consequat nisl bibendum. Fermentum sapien elementum donec et curabitur. Sed nascetur imperdiet. Vivamus sagittis nullam. Morbi nunc sit ipsum.</p><p>Tellus magnis luctus. Vel a ligula. Nec bibendum proin. Ipsum pulvinar et. Lorem ut tincidunt sed magna curabitur. Vestibulum eu nam. Vivamus varius bibendum a.</p><p>At wisi etiam. Placerat taciti ante. Phasellus ac wisi. Libero purus condimentum. In accumsan in. Nec ante tempus suscipit magna nulla. Aenean tempor lorem. Elit et dapibus. Posuere at vehicula. Lectus lectus nibh. Vivamus suscipit ullamcorper massa wisi sagittis et aut velit. Imperdiet posuere velit. Sagittis imperdiet sed faucibus.</p>
+</body>
diff --git a/tools/perf/profile_creators/profile_generator.py b/tools/perf/profile_creators/profile_generator.py
index 9d6038ba..7636568 100644
--- a/tools/perf/profile_creators/profile_generator.py
+++ b/tools/perf/profile_creators/profile_generator.py
@@ -13,6 +13,7 @@
 import tempfile
 
 from profile_creators import profile_extender
+from telemetry.core import browser_finder
 from telemetry.core import browser_options
 from telemetry.core import discover
 from telemetry.core import util
@@ -64,33 +65,86 @@
   return ignore_list
 
 
-def GenerateProfiles(profile_extender_class, profile_creator_name, options):
-  """Generate a profile"""
+class ProfileGenerator(object):
+  """Generate profile.
 
-  temp_output_directory = tempfile.mkdtemp()
-  options.output_profile_path = temp_output_directory
+  On desktop the generated profile is copied to the specified location so later
+  runs can reuse it.
+  On CrOS profile resides on cryptohome and there is no easy way to
+  override it before user login. So for CrOS we just generate the profile
+  every time when the benchmark starts to run.
+  """
+  def __init__(self, profile_extender_class, profile_name):
+    self._profile_extender_class = profile_extender_class
+    self._profile_name = profile_name
 
-  profile_creator_instance = profile_extender_class(options)
-  try:
-    profile_creator_instance.Run()
-  except Exception as e:
-    logging.exception('Profile creation failed.')
-    shutil.rmtree(temp_output_directory)
-    raise e
+  def Run(self, options):
+    """Kick off the process.
 
-  # Everything is a-ok, move results to final destination.
-  generated_profiles_dir = os.path.abspath(options.output_dir)
-  if not os.path.exists(generated_profiles_dir):
-    os.makedirs(generated_profiles_dir)
-  out_path = os.path.join(generated_profiles_dir, profile_creator_name)
-  if os.path.exists(out_path):
-    shutil.rmtree(out_path)
+    Args:
+      options: Instance of BrowserFinderOptions to search for proper browser.
 
-  shutil.copytree(temp_output_directory, out_path, ignore=_IsPseudoFile)
-  shutil.rmtree(temp_output_directory)
-  sys.stderr.write("SUCCESS: Generated profile copied to: '%s'.\n" % out_path)
+    Returns:
+      The path of generated profile or existing profile if --profile-dir
+      is given. Could be None if it's generated on default location
+      (e.g., crytohome on CrOS).
+    """
+    possible_browser = browser_finder.FindBrowser(options)
+    is_cros = possible_browser.browser_type.startswith('cros')
 
-  return 0
+    out_dir = None
+    if is_cros:
+      self.Create(options, None)
+    else:
+      # Decide profile output path.
+      out_dir = (options.browser_options.profile_dir or
+          os.path.abspath(os.path.join(
+              tempfile.gettempdir(), self._profile_name, self._profile_name)))
+      if not os.path.exists(out_dir):
+        self.Create(options, out_dir)
+
+    return out_dir
+
+  def Create(self, options, out_dir):
+    """Generate profile.
+
+    If out_dir is given, copy the generated profile to out_dir.
+    Otherwise the profile is generated to its default position
+    (e.g., cryptohome on CrOS).
+    """
+
+    # Leave the global options intact.
+    creator_options = options.Copy()
+
+    if out_dir:
+      sys.stderr.write('Generating profile to: %s \n' % out_dir)
+      # The genrated profile is copied to out_dir only if the generation is
+      # successful. In the generation process a temp directory is used so
+      # the default profile is not polluted on failure.
+      tmp_profile_path = tempfile.mkdtemp()
+      creator_options.output_profile_path = tmp_profile_path
+
+    creator = self._profile_extender_class(creator_options)
+
+    try:
+      creator.Run()
+    except Exception as e:
+      logging.exception('Profile creation failed.')
+      raise e
+    else:
+      sys.stderr.write('SUCCESS: Profile generated.\n')
+
+      # Copy generated profile to final destination if out_dir is given.
+      if out_dir:
+        if os.path.exists(out_dir):
+          shutil.rmtree(out_dir)
+        shutil.copytree(tmp_profile_path,
+                        out_dir, ignore=_IsPseudoFile)
+        sys.stderr.write(
+            "SUCCESS: Generated profile copied to: '%s'.\n" % out_dir)
+    finally:
+      if out_dir:
+        shutil.rmtree(tmp_profile_path)
 
 
 def AddCommandLineArgs(parser):
@@ -140,5 +194,8 @@
   # Generate profile.
   profile_extenders = _DiscoverProfileExtenderClasses()
   profile_extender_class = profile_extenders[options.profile_type_to_generate]
-  return GenerateProfiles(profile_extender_class,
-      options.profile_type_to_generate, options)
+
+  generator = ProfileGenerator(profile_extender_class,
+      options.profile_type_to_generate)
+  generator.Create(options, options.output_dir)
+  return 0
diff --git a/tools/perf_expectations/make_expectations.py b/tools/perf_expectations/make_expectations.py
index 0aca7a0d..b8c35a9 100755
--- a/tools/perf_expectations/make_expectations.py
+++ b/tools/perf_expectations/make_expectations.py
@@ -241,14 +241,15 @@
     scanning = False
     for line in summarylist:
       jsondata = ConvertJsonIntoDict(line)
-
-      # TODO(iannucci): Remove this once http://crbug.com/336471 is resolved.
-      if 'Force the Chro' in jsondata['rev']:
+      try:
+        rev = int(jsondata['rev'])
+      except ValueError:
+        print ('Warning: skipping rev %r because could not be parsed '
+               'as an integer.' % jsondata['rev'])
         continue
-
-      if int(jsondata['rev']) <= revb:
+      if rev <= revb:
         scanning = True
-      if int(jsondata['rev']) < reva:
+      if rev < reva:
         break
 
       # We found the upper revision in the range.  Scan for trace data until we
diff --git a/tools/perf_expectations/perf_expectations.json b/tools/perf_expectations/perf_expectations.json
index 6bfbeb894..27235e6 100644
--- a/tools/perf_expectations/perf_expectations.json
+++ b/tools/perf_expectations/perf_expectations.json
@@ -381,7 +381,7 @@
  "linux-release/sizes/nacl_helper_bootstrap-text/text": {"reva": 256743, "revb": 256743, "type": "absolute", "better": "lower", "improve": 4882, "regress": 5396, "sha1": "ffc106e5"},
  "linux-release/sizes/nacl_helper_bootstrap/nacl_helper_bootstrap": {"reva": 114822, "revb": 115019, "type": "absolute", "better": "lower", "improve": 8776, "regress": 9700, "sha1": "3f284fed"},
  "linux-release/sizes/totals-textrel/textrel": {"reva": 205083, "revb": 206071, "type": "absolute", "better": "lower", "improve": 1075, "regress": 1189, "sha1": "69d07fda"},
- "mac-release/sizes/Chromium.app/Chromium.app": {"reva": 326940, "revb": 326990, "type": "absolute", "better": "lower", "improve": 155912232, "regress": 159128167, "tolerance": 0.01, "sha1": "0e4899e7"},
+ "mac-release/sizes/Chromium.app/Chromium.app": {"reva": 333120, "revb": 333170, "type": "absolute", "better": "lower", "improve": 157534248, "regress": 160720896, "tolerance": 0.01, "sha1": "f5025410"},
  "mac-release/sizes/Chromium/Chromium": {"reva": 165473, "revb": 165473, "type": "absolute", "better": "lower", "improve": 8132, "regress": 8988, "sha1": "8e448691"},
  "mac-release/sizes/ChromiumFramework/ChromiumFramework": {"reva": 326940, "revb": 326990, "type": "absolute", "better": "lower", "improve": 102571179, "regress": 104681006, "tolerance": 0.01, "sha1": "f9819a70"},
  "mac-release/sizes/chrome-si/initializers": {"reva": 281731, "revb": 281731, "type": "absolute", "better": "lower", "improve": 0, "regress": 0, "tolerance": 0, "sha1": "01759b7f"},
diff --git a/tools/telemetry/bootstrap_deps b/tools/telemetry/bootstrap_deps
index 3ab61ad..1ae0cd82 100644
--- a/tools/telemetry/bootstrap_deps
+++ b/tools/telemetry/bootstrap_deps
@@ -12,13 +12,9 @@
     "src/tools/telemetry": "",
     "src/build/util": "",
     "src/chrome/test/data/extensions/profiles": "",
-    "src/chrome/test/data/perf/canvas_bench": "",
     "src/third_party/android_testrunner": "",
     "src/third_party/android_tools/sdk/platform-tools": "",
     "src/third_party/chromite/ssh_keys": "",
-    "src/third_party/flot/jquery.flot.min.js": "",
-    "src/third_party/WebKit/PerformanceTests/resources/jquery.tablesorter.min.js": "",
-    "src/third_party/WebKit/PerformanceTests/resources/statistics.js": "",
     "src/third_party/webpagereplay": "",
     "src/third_party/trace-viewer": "",
     "src/third_party/typ": "",
diff --git a/tools/telemetry/telemetry/TELEMETRY_DEPS b/tools/telemetry/telemetry/TELEMETRY_DEPS
index 3077c1a..d054d16 100644
--- a/tools/telemetry/telemetry/TELEMETRY_DEPS
+++ b/tools/telemetry/telemetry/TELEMETRY_DEPS
@@ -6,7 +6,6 @@
   "directory_deps": [
     "build/android/pylib/",
     "chrome/test/data/extensions/",
-    "chrome/test/data/perf/canvas_bench/",
     "third_party/android_testrunner/",
     "third_party/android_tools/sdk/platform-tools/",
     "third_party/trace-viewer/",
@@ -28,11 +27,8 @@
     "build/util/lib/common/util.py",
     "build/util/version.gypi",
     "build/util/version.py",
-    "third_party/WebKit/PerformanceTests/resources/jquery.tablesorter.min.js",
-    "third_party/WebKit/PerformanceTests/resources/statistics.js",
     "third_party/chromite/ssh_keys/testing_rsa",
     "third_party/chromite/ssh_keys/testing_rsa.pub",
-    "third_party/flot/jquery.flot.min.js",
     "tools/perf/unit-info.json"
   ]
 }
diff --git a/tools/telemetry/telemetry/android/__init__.py b/tools/telemetry/telemetry/android/__init__.py
new file mode 100644
index 0000000..6bd5e3a
--- /dev/null
+++ b/tools/telemetry/telemetry/android/__init__.py
@@ -0,0 +1,6 @@
+# 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.
+
+from telemetry.android.android_story import AndroidStory
+from telemetry.android.shared_android_state import SharedAndroidState
diff --git a/tools/telemetry/telemetry/user_story/android/__init__.py b/tools/telemetry/telemetry/android/android_story.py
similarity index 80%
rename from tools/telemetry/telemetry/user_story/android/__init__.py
rename to tools/telemetry/telemetry/android/android_story.py
index 7b5f442..34bea6e 100644
--- a/tools/telemetry/telemetry/user_story/android/__init__.py
+++ b/tools/telemetry/telemetry/android/android_story.py
@@ -2,10 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from telemetry.android import shared_android_state
 from telemetry import user_story
-from telemetry.user_story.android import shared_app_state
 
-class AppStory(user_story.UserStory):
+class AndroidStory(user_story.UserStory):
   def __init__(self, start_intent, is_app_ready_predicate=None,
                name='', labels=None, is_local=False):
     """Creates a new user story for Android app.
@@ -17,8 +17,8 @@
       labels: See UserStory.__init__.
       is_app_ready_predicate: See UserStory.__init__.
     """
-    super(AppStory, self).__init__(
-        shared_app_state.SharedAppState, name=name, labels=labels,
+    super(AndroidStory, self).__init__(
+        shared_android_state.SharedAndroidState, name=name, labels=labels,
         is_local=is_local)
     self.start_intent = start_intent
     self.is_app_ready_predicate = is_app_ready_predicate
diff --git a/tools/telemetry/telemetry/user_story/android/shared_app_state.py b/tools/telemetry/telemetry/android/shared_android_state.py
similarity index 83%
rename from tools/telemetry/telemetry/user_story/android/shared_app_state.py
rename to tools/telemetry/telemetry/android/shared_android_state.py
index 1ffd8ee..4c48266d 100644
--- a/tools/telemetry/telemetry/user_story/android/shared_app_state.py
+++ b/tools/telemetry/telemetry/android/shared_android_state.py
@@ -8,26 +8,26 @@
 from telemetry.web_perf import timeline_based_measurement
 
 
-class SharedAppState(shared_state.SharedState):
-  """Manage test state/transitions across multiple android.UserStory's.
+class SharedAndroidState(shared_state.SharedState):
+  """Manage test state/transitions across multiple android.AndroidStory's.
 
   WARNING: the class is not ready for public consumption.
   Email telemetry@chromium.org if you feel like you must use it.
   """
 
-  def __init__(self, test, finder_options, user_story_set):
+  def __init__(self, test, finder_options, story_set):
     """This method is styled on unittest.TestCase.setUpClass.
 
     Args:
       test: a web_perf.TimelineBasedMeasurement instance.
       options: a BrowserFinderOptions instance with command line options.
-      user_story_set: an android.UserStorySet instance.
+      story_set: a story.StorySet instance.
     """
-    super(SharedAppState, self).__init__(test, finder_options, user_story_set)
+    super(SharedAndroidState, self).__init__(test, finder_options, story_set)
     if not isinstance(
         test, timeline_based_measurement.TimelineBasedMeasurement):
       raise ValueError(
-          'SharedAppState only accepts TimelineBasedMeasurement tests'
+          'SharedAndroidState only accepts TimelineBasedMeasurement tests'
           ' (not %s).' % test.__class__)
     self._test = test
     self._finder_options = finder_options
@@ -71,6 +71,6 @@
   def TearDownState(self):
     """Tear down anything created in the __init__ method that is not needed.
 
-    Currently, there is no clean-up needed from SharedAppState.__init__.
+    Currently, there is no clean-up needed from SharedAndroidState.__init__.
     """
     pass
diff --git a/tools/telemetry/telemetry/benchmark.py b/tools/telemetry/telemetry/benchmark.py
index 48e244d1..56224050 100644
--- a/tools/telemetry/telemetry/benchmark.py
+++ b/tools/telemetry/telemetry/benchmark.py
@@ -58,7 +58,7 @@
   Benchmarks default to using TBM unless you override the value of
   Benchmark.test, or override the CreatePageTest method.
 
-  New benchmarks should override CreateUserStorySet.
+  New benchmarks should override CreateStorySet.
   """
   options = {}
   test = timeline_based_measurement.TimelineBasedMeasurement
@@ -147,7 +147,8 @@
     results.
 
     Args:
-      value: a value.Value instance.
+      value: a value.Value instance (except failure.FailureValue,
+        skip.SkipValue or trace.TraceValue which will always be added).
       is_first_result: True if |value| is the first result for its
           corresponding user story.
 
@@ -184,11 +185,11 @@
       pt._enabled_strings = self._enabled_strings
 
     expectations = self.CreateExpectations()
-    us = self.CreateUserStorySet(finder_options)
+    us = self.CreateStorySet(finder_options)
     if isinstance(pt, page_test.PageTest):
       if any(not isinstance(p, page.Page) for p in us.user_stories):
         raise Exception(
-            'PageTest must be used with UserStorySet containing only '
+            'PageTest must be used with StorySet containing only '
             'telemetry.page.Page user stories.')
 
     self._DownloadGeneratedProfileArchive(finder_options)
@@ -327,7 +328,7 @@
       raise TypeError('"%s" is not a PageSet.' % self.page_set.__name__)
     return self.page_set()
 
-  def CreateUserStorySet(self, options):
+  def CreateStorySet(self, options):
     return self.CreatePageSet(options)
 
   @classmethod
diff --git a/tools/telemetry/telemetry/benchmark_unittest.py b/tools/telemetry/telemetry/benchmark_unittest.py
index 7c81561..611761d4 100644
--- a/tools/telemetry/telemetry/benchmark_unittest.py
+++ b/tools/telemetry/telemetry/benchmark_unittest.py
@@ -5,6 +5,7 @@
 import optparse
 import unittest
 
+from telemetry import android
 from telemetry import benchmark
 from telemetry.core import browser_options
 from telemetry.internal import story_runner
@@ -12,9 +13,8 @@
 from telemetry.page import page_test
 from telemetry.page import shared_page_state
 from telemetry.story import shared_state
+from telemetry import story as story_module
 from telemetry import user_story
-from telemetry.user_story import android
-from telemetry.user_story import user_story_set as user_story_set_module
 from telemetry.web_perf import timeline_based_measurement
 
 
@@ -26,14 +26,14 @@
 class TestBenchmark(benchmark.Benchmark):
   def __init__(self, story):
     super(TestBenchmark, self).__init__()
-    self._uss = user_story_set_module.UserStorySet()
-    self._uss.AddUserStory(story)
+    self._story_set = story_module.StorySet()
+    self._story_set.AddUserStory(story)
 
   def CreatePageTest(self, _):
     return DummyPageTest()
 
-  def CreateUserStorySet(self, _):
-    return self._uss
+  def CreateStorySet(self, _):
+    return self._story_set
 
 
 class BenchmarkTest(unittest.TestCase):
@@ -52,7 +52,7 @@
         Exception, 'containing only telemetry.page.Page user stories'):
       b.Run(browser_options.BrowserFinderOptions())
 
-    b = TestBenchmark(android.AppStory(start_intent=None))
+    b = TestBenchmark(android.AndroidStory(start_intent=None))
     with self.assertRaisesRegexp(
         Exception, 'containing only telemetry.page.Page user stories'):
       b.Run(browser_options.BrowserFinderOptions())
@@ -138,7 +138,7 @@
     original_run_fn = story_runner.Run
     validPredicate = [False]
 
-    def RunStub(test, user_story_set, expectations, finder_options, results,
+    def RunStub(test, story_set_module, expectations, finder_options, results,
                 **args): # pylint: disable=unused-argument
       predicate = results._value_can_be_added_predicate
       valid = predicate == PredicateBenchmark.ValueCanBeAddedPredicate
diff --git a/tools/telemetry/telemetry/core/backends/chrome/cros_browser_backend.py b/tools/telemetry/telemetry/core/backends/chrome/cros_browser_backend.py
index 6eb512e..1238cc0b 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/cros_browser_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/cros_browser_backend.py
@@ -54,11 +54,6 @@
     if not self.browser_options.dont_override_profile:
       self._cri.RunCmdOnDevice(['cryptohome', '--action=remove', '--force',
                                 '--user=%s' % self._username])
-    if self.browser_options.profile_dir:
-      cri.RmRF(self.profile_directory)
-      cri.PushFile(self.browser_options.profile_dir + '/Default',
-                   self.profile_directory)
-      cri.Chown(self.profile_directory)
 
   def GetBrowserStartupArgs(self):
     args = super(CrOSBrowserBackend, self).GetBrowserStartupArgs()
diff --git a/tools/telemetry/telemetry/core/backends/chrome/oobe.py b/tools/telemetry/telemetry/core/backends/chrome/oobe.py
index 60abfd9ac..25a20eb 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/oobe.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/oobe.py
@@ -27,14 +27,10 @@
         pass
     return None
 
-  def _GaiaWebViewContext(self):
-    devtools_context_map = (
-        self._inspector_backend._devtools_client.GetUpdatedInspectableContexts()
-    )
-    for context in devtools_context_map.contexts:
-      if context['type'] == 'webview':
-        return web_contents.WebContents(
-            devtools_context_map.GetInspectorBackend(context['id']))
+  def _GaiaWebviewContext(self):
+    webview_contexts = self.GetWebviewContexts()
+    if webview_contexts:
+      return webview_contexts[0]
     return None
 
   def _ExecuteOobeApi(self, api, *args):
@@ -74,11 +70,12 @@
   def NavigateGaiaLogin(self, username, password):
     """Logs in using the GAIA webview or IFrame, whichever is
     present."""
+    self._ExecuteOobeApi('Oobe.skipToLoginForTesting')
     def _GetGaiaFunction():
       self._ExecuteOobeApi('Oobe.showAddUserForTesting')
       if self._GaiaIFrameContext() is not None:
         return Oobe._NavigateIFrameLogin
-      elif self._GaiaWebViewContext() is not None:
+      elif self._GaiaWebviewContext():
         return Oobe._NavigateWebViewLogin
       return None
     util.WaitFor(_GetGaiaFunction, 20)(self, username, password)
@@ -97,23 +94,23 @@
   def _NavigateWebViewLogin(self, username, password, wait_for_close=True):
     """Logs into the webview-based GAIA screen"""
     self._NavigateWebViewEntry('identifierId', username)
-    self._GaiaWebViewContext().WaitForJavaScriptExpression(
+    self._GaiaWebviewContext().WaitForJavaScriptExpression(
         "document.getElementById('identifierId') == null", 20)
     self._NavigateWebViewEntry('password', password)
     if wait_for_close:
-      util.WaitFor(lambda: self._GaiaWebViewContext() == None, 20)
+      util.WaitFor(lambda: not self._GaiaWebviewContext(), 20)
 
   def _NavigateWebViewEntry(self, field, value):
     self._WaitForField(field)
     self._WaitForField('next')
-    gaia_webview_context = self._GaiaWebViewContext()
+    gaia_webview_context = self._GaiaWebviewContext()
     gaia_webview_context.EvaluateJavaScript("""
        document.getElementById('%s').value='%s';
        document.getElementById('next').click()"""
            % (field, value))
 
   def _WaitForField(self, field_id):
-    gaia_webview_context = util.WaitFor(self._GaiaWebViewContext, 5)
+    gaia_webview_context = util.WaitFor(self._GaiaWebviewContext, 5)
     util.WaitFor(gaia_webview_context.HasReachedQuiescence, 20)
     gaia_webview_context.WaitForJavaScriptExpression(
         "document.getElementById('%s') != null" % field_id, 20)
diff --git a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend.py b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend.py
index 1290153be..ab6e870 100644
--- a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend.py
@@ -106,6 +106,20 @@
   def debugger_url(self):
     return self._context['webSocketDebuggerUrl']
 
+  def GetWebviewInspectorBackends(self):
+    """Returns a list of InspectorBackend instances associated with webviews.
+
+    Raises:
+      devtools_http.DevToolsClientConnectionError
+    """
+    inspector_backends = []
+    devtools_context_map = self._devtools_client.GetUpdatedInspectableContexts()
+    for context in devtools_context_map.contexts:
+      if context['type'] == 'webview':
+        inspector_backends.append(
+            devtools_context_map.GetInspectorBackend(context['id']))
+    return inspector_backends
+
   def IsInspectable(self):
     """Whether the tab is inspectable, as reported by devtools."""
     try:
diff --git a/tools/telemetry/telemetry/core/extension_unittest.py b/tools/telemetry/telemetry/core/extension_unittest.py
index 20f3553..2092b04 100644
--- a/tools/telemetry/telemetry/core/extension_unittest.py
+++ b/tools/telemetry/telemetry/core/extension_unittest.py
@@ -180,3 +180,26 @@
                           extension_path,
                           browser_type=options.browser_type,
                           is_component=True))
+
+
+class WebviewInExtensionTest(ExtensionTest):
+  def testWebviewInExtension(self):
+    """Tests GetWebviewContext() for a web app containing <webview> element."""
+    if not self.CreateBrowserWithExtension('webview_app'):
+      logging.warning('Did not find a browser that supports extensions, '
+                      'skipping test.')
+      return
+
+    self._browser.extensions.GetByExtensionId(self._extension_id)
+    webview_contexts = self._extension.GetWebviewContexts()
+    self.assertEquals(1, len(webview_contexts))
+    webview_context = webview_contexts[0]
+    webview_context.WaitForDocumentReadyStateToBeComplete()
+    # Check that the context has the right url from the <webview> element.
+    self.assertTrue(webview_context.GetUrl().startswith('data:'))
+    # Check |test_input_id| element is accessible from the webview context.
+    self.assertTrue(webview_context.EvaluateJavaScript(
+                    'document.getElementById("test_input_id") != null'))
+    # Check that |test_input_id| is not accessible from outside webview context
+    self.assertFalse(self._extension.EvaluateJavaScript(
+                    'document.getElementById("test_input_id") != null'))
diff --git a/tools/telemetry/telemetry/core/forwarders/android_forwarder.py b/tools/telemetry/telemetry/core/forwarders/android_forwarder.py
index ed8ed7b..65be8cd 100644
--- a/tools/telemetry/telemetry/core/forwarders/android_forwarder.py
+++ b/tools/telemetry/telemetry/core/forwarders/android_forwarder.py
@@ -279,7 +279,7 @@
     except device_errors.AdbCommandFailedError:
       # Ignore exception due to USB connection being reset.
       pass
-    self._device.adb.WaitForDevice()
+    self._device.WaitUntilFullyBooted()
 
   def _EnableRndis(self):
     """Enables the RNDIS network interface."""
@@ -321,7 +321,7 @@
     # TODO(szym): run via su -c if necessary.
     self._device.RunShellCommand('rm %s.log' % script_prefix)
     self._device.RunShellCommand('. %s.sh' % script_prefix)
-    self._device.adb.WaitForDevice()
+    self._device.WaitUntilFullyBooted()
     result = self._device.ReadFile('%s.log' % script_prefix).splitlines()
     assert any('DONE' in line for line in result), 'RNDIS script did not run!'
 
@@ -489,7 +489,7 @@
     self._device.RunShellCommand(
         'ifconfig %s %s netmask %s up' % (device_iface, device_ip, netmask))
     # Enabling the interface sometimes breaks adb.
-    self._device.adb.WaitForDevice()
+    self._device.WaitUntilFullyBooted()
     self._host_iface = host_iface
     self._host_ip = host_ip
     self.device_iface = device_iface
diff --git a/tools/telemetry/telemetry/core/platform/android_platform_backend.py b/tools/telemetry/telemetry/core/platform/android_platform_backend.py
index 579f43d..7f16e83 100644
--- a/tools/telemetry/telemetry/core/platform/android_platform_backend.py
+++ b/tools/telemetry/telemetry/core/platform/android_platform_backend.py
@@ -84,8 +84,12 @@
     self._perf_tests_setup = perf_control.PerfControl(self._device)
     self._thermal_throttle = thermal_throttle.ThermalThrottle(self._device)
     self._raw_display_frame_rate_measurements = []
-    self._can_access_protected_file_contents = (
-        self._device.HasRoot() or self._device.NeedsSU())
+    try:
+      self._can_access_protected_file_contents = (
+          self._device.HasRoot() or self._device.NeedsSU())
+    except:
+      logging.exception('New exception caused by DeviceUtils conversion')
+      raise
     self._device_copy_script = None
     power_controller = power_monitor_controller.PowerMonitorController([
         monsoon_power_monitor.MonsoonPowerMonitor(self._device, self),
@@ -210,9 +214,12 @@
     if not android_prebuilt_profiler_helper.InstallOnDevice(
         self._device, 'purge_ashmem'):
       raise Exception('Error installing purge_ashmem.')
-    output = self._device.RunShellCommand(
-        android_prebuilt_profiler_helper.GetDevicePath('purge_ashmem'),
-        check_return=True)
+    try:
+      output = self._device.RunShellCommand(
+          android_prebuilt_profiler_helper.GetDevicePath('purge_ashmem'))
+    except:
+      logging.exception('New exception caused by DeviceUtils conversion')
+      raise
     for l in output:
       logging.info(l)
 
@@ -244,6 +251,10 @@
       raise exceptions.ProcessGoneException()
     return ps[0][1]
 
+  @decorators.Cache
+  def GetArchName(self):
+    return self._device.GetABI()
+
   def GetOSName(self):
     return 'android'
 
@@ -539,8 +550,12 @@
     self._device.PushChangedFiles([(new_profile_dir, saved_profile_location)])
 
     profile_dir = self._GetProfileDir(package)
-    self._EfficientDeviceDirectoryCopy(
-        saved_profile_location, profile_dir)
+    try:
+      self._EfficientDeviceDirectoryCopy(
+          saved_profile_location, profile_dir)
+    except:
+      logging.exception('New exception caused by DeviceUtils conversion')
+      raise
     dumpsys = self._device.RunShellCommand('dumpsys package %s' % package)
     id_line = next(line for line in dumpsys if 'userId=' in line)
     uid = re.search(r'\d+', id_line).group()
@@ -560,8 +575,7 @@
           _DEVICE_COPY_SCRIPT_LOCATION)
       self._device_copy_script = _DEVICE_COPY_SCRIPT_FILE
     self._device.RunShellCommand(
-        ['sh', self._device_copy_script, source, dest],
-        check_return=True)
+        ['sh', self._device_copy_script, source, dest])
 
   def RemoveProfile(self, package, ignore_list):
     """Delete application profile on device.
@@ -593,8 +607,11 @@
     # pulled down is really needed e.g. .pak files.
     if not os.path.exists(output_profile_path):
       os.makedirs(output_profile_path)
-    files = self._device.RunShellCommand(
-        ['ls', profile_dir], check_return=True)
+    try:
+      files = self._device.RunShellCommand(['ls', profile_dir])
+    except:
+      logging.exception('New exception caused by DeviceUtils conversion')
+      raise
     for f in files:
       # Don't pull lib, since it is created by the installer.
       if f != 'lib':
diff --git a/tools/telemetry/telemetry/core/platform/power_monitor/android_ds2784_power_monitor.py b/tools/telemetry/telemetry/core/platform/power_monitor/android_ds2784_power_monitor.py
index 92abae1..d00629c 100644
--- a/tools/telemetry/telemetry/core/platform/power_monitor/android_ds2784_power_monitor.py
+++ b/tools/telemetry/telemetry/core/platform/power_monitor/android_ds2784_power_monitor.py
@@ -43,9 +43,13 @@
   def CanMonitorPower(self):
     if not self._HasFuelGauge():
       return False
-    if self._device_battery.GetCharging():
-      logging.warning("Can't monitor power usage since device is charging.")
-      return False
+    try:
+      if self._device_battery.GetCharging():
+        logging.warning("Can't monitor power usage since device is charging.")
+        return False
+    except:
+      logging.exception('New exception caused by DeviceUtils conversion')
+      raise
     return True
 
   def StartMonitoringPower(self, browser):
diff --git a/tools/telemetry/telemetry/core/platform/profiler/android_profiling_helper.py b/tools/telemetry/telemetry/core/platform/profiler/android_profiling_helper.py
index e06ab32e..4608e36 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/android_profiling_helper.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/android_profiling_helper.py
@@ -208,7 +208,11 @@
         pull = True
       else:
         host_md5sums = md5sum.CalculateHostMd5Sums([output_lib])
-        device_md5sums = md5sum.CalculateDeviceMd5Sums([lib], device)
+        try:
+          device_md5sums = md5sum.CalculateDeviceMd5Sums([lib], device)
+        except:
+          logging.exception('New exception caused by DeviceUtils conversion')
+          raise
         pull = (not host_md5sums or not device_md5sums
                 or host_md5sums[0] != device_md5sums[0])
 
diff --git a/tools/telemetry/telemetry/core/platform/profiler/android_traceview_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/android_traceview_profiler.py
index 3f7a080..e10d9c1 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/android_traceview_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/android_traceview_profiler.py
@@ -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 logging
 import os
 
 from telemetry.core.backends.chrome import android_browser_finder
@@ -58,8 +59,12 @@
       # pylint: disable=cell-var-from-loop
       util.WaitFor(lambda: self._FileSize(trace_file) > 0, timeout=10)
       output_files.append(trace_file)
-    self._browser_backend.adb.device().PullFile(
-        self._DEFAULT_DEVICE_DIR, self._output_path)
+    try:
+      self._browser_backend.adb.device().PullFile(
+          self._DEFAULT_DEVICE_DIR, self._output_path)
+    except:
+      logging.exception('New exception caused by DeviceUtils conversion')
+      raise
     self._browser_backend.adb.RunShellCommand(
         'rm ' + os.path.join(self._DEFAULT_DEVICE_DIR, '*'))
     print 'Traceview profiles available in ', self._output_path
diff --git a/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py
index 8719406..3fd7ab7 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/java_heap_profiler.py
@@ -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 logging
 import os
 import subprocess
 import threading
@@ -48,8 +49,12 @@
   def CollectProfile(self):
     self._timer.cancel()
     self._DumpJavaHeap(True)
-    self._browser_backend.adb.device().PullFile(
-        self._DEFAULT_DEVICE_DIR, self._output_path)
+    try:
+      self._browser_backend.adb.device().PullFile(
+          self._DEFAULT_DEVICE_DIR, self._output_path)
+    except:
+      logging.exception('New exception caused by DeviceUtils conversion')
+      raise
     self._browser_backend.adb.RunShellCommand(
         'rm ' + os.path.join(self._DEFAULT_DEVICE_DIR, '*'))
     output_files = []
diff --git a/tools/telemetry/telemetry/core/platform/profiler/netlog_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/netlog_profiler.py
index aa0070a..b63596a 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/netlog_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/netlog_profiler.py
@@ -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 logging
 import tempfile
 
 from telemetry.core.platform import profiler
@@ -36,7 +37,12 @@
     # On Android pull the output file to the host.
     if self._platform_backend.GetOSName() == 'android':
       host_output_file = '%s.json' % self._output_path
-      self._browser_backend.adb.device().PullFile(output_file, host_output_file)
+      try:
+        self._browser_backend.adb.device().PullFile(
+            output_file, host_output_file)
+      except:
+        logging.exception('New exception caused by DeviceUtils conversion')
+        raise
       # Clean the device
       self._browser_backend.adb.device().RunShellCommand('rm %s' % output_file)
       output_file = host_output_file
diff --git a/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py
index f0982e6..cbc88878 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py
@@ -128,7 +128,11 @@
                                   self._output_file)
     if self._is_android:
       device = self._browser_backend.adb.device()
-      device.PullFile(self._device_output_file, self._output_file)
+      try:
+        device.PullFile(self._device_output_file, self._output_file)
+      except:
+        logging.exception('New exception caused by DeviceUtils conversion')
+        raise
       required_libs = \
           android_profiling_helper.GetRequiredLibrariesForPerfProfile(
               self._output_file)
diff --git a/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py
index 4fc3982..01d95c3 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/tcmalloc_heap_profiler.py
@@ -34,7 +34,11 @@
   def _SetDeviceProperties(self, properties):
     device_configured = False
     # This profiler requires adb root to set properties.
-    self._browser_backend.adb.device().EnableRoot()
+    try:
+      self._browser_backend.adb.device().EnableRoot()
+    except:
+      logging.exception('New exception caused by DeviceUtils conversion')
+      raise
     for values in properties.itervalues():
       device_property = self._browser_backend.adb.device().GetProp(values[0])
       if not device_property or not device_property.strip():
@@ -51,8 +55,12 @@
       raise Exception('Device required special config, run again.')
 
   def CollectProfile(self):
-    self._browser_backend.adb.device().PullFile(
-        self._DEFAULT_DEVICE_DIR, self._output_path)
+    try:
+      self._browser_backend.adb.device().PullFile(
+          self._DEFAULT_DEVICE_DIR, self._output_path)
+    except:
+      logging.exception('New exception caused by DeviceUtils conversion')
+      raise
     self._browser_backend.adb.RunShellCommand(
         'rm ' + os.path.join(self._DEFAULT_DEVICE_DIR, '*'))
     if os.path.exists(self._output_path):
diff --git a/tools/telemetry/telemetry/core/platform/profiler/tcpdump_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/tcpdump_profiler.py
index 6ad22c4e..6b62474 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/tcpdump_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/tcpdump_profiler.py
@@ -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 logging
 import os
 import signal
 import subprocess
@@ -44,7 +45,11 @@
     self._proc.terminate()
     host_dump = os.path.join(self._output_path,
                              os.path.basename(self._DEVICE_DUMP_FILE))
-    self._adb.device().PullFile(self._DEVICE_DUMP_FILE, host_dump)
+    try:
+      self._adb.device().PullFile(self._DEVICE_DUMP_FILE, host_dump)
+    except:
+      logging.exception('New exception caused by DeviceUtils conversion')
+      raise
     print 'TCP dump available at: %s ' % host_dump
     print 'Use Wireshark to open it.'
     return host_dump
diff --git a/tools/telemetry/telemetry/core/platform/profiler/v8_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/v8_profiler.py
index 73e126e..34bc476 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/v8_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/v8_profiler.py
@@ -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 logging
 import re
 import tempfile
 
@@ -38,7 +39,12 @@
     # On Android pull the output file to the host.
     if self._platform_backend.GetOSName() == 'android':
       host_output_file = '%s.log' % self._output_path
-      self._browser_backend.adb.device().PullFile(output_file, host_output_file)
+      try:
+        self._browser_backend.adb.device().PullFile(
+            output_file, host_output_file)
+      except:
+        logging.exception('New exception caused by DeviceUtils conversion')
+        raise
       # Clean the device
       self._browser_backend.adb.device().RunShellCommand('rm %s' % output_file)
       output_file = host_output_file
diff --git a/tools/telemetry/telemetry/core/util.py b/tools/telemetry/telemetry/core/util.py
index 7abfff4..471985c 100644
--- a/tools/telemetry/telemetry/core/util.py
+++ b/tools/telemetry/telemetry/core/util.py
@@ -26,6 +26,11 @@
       __file__, os.pardir, os.pardir, os.pardir))
 
 
+def GetTelemetryThirdPartyDir():
+  return os.path.normpath(os.path.join(
+      __file__, os.pardir, os.pardir, os.pardir, 'third_party'))
+
+
 def GetUnittestDataDir():
   return os.path.join(GetTelemetryDir(), 'unittest_data')
 
diff --git a/tools/telemetry/telemetry/core/web_contents.py b/tools/telemetry/telemetry/core/web_contents.py
index 88231a3..a9731c8 100644
--- a/tools/telemetry/telemetry/core/web_contents.py
+++ b/tools/telemetry/telemetry/core/web_contents.py
@@ -25,6 +25,29 @@
     """Return the unique id string for this tab object."""
     return self._inspector_backend.id
 
+  def GetUrl(self):
+    """Returns the URL to which the WebContents is connected.
+
+    Raises:
+      exceptions.Error: If there is an error in inspector backend connection.
+    """
+    return self._inspector_backend.url
+
+  def GetWebviewContexts(self):
+    """Returns a list of webview contexts within the current inspector backend.
+
+    Returns:
+      A list of WebContents objects representing the webview contexts.
+
+    Raises:
+      exceptions.Error: If there is an error in inspector backend connection.
+    """
+    webviews = []
+    inspector_backends = self._inspector_backend.GetWebviewInspectorBackends()
+    for inspector_backend in inspector_backends:
+      webviews.append(WebContents(inspector_backend))
+    return webviews
+
   def WaitForDocumentReadyStateToBeComplete(self,
       timeout=DEFAULT_WEB_CONTENTS_TIMEOUT):
     """Waits for the document to finish loading.
diff --git a/tools/telemetry/telemetry/internal/story_runner.py b/tools/telemetry/telemetry/internal/story_runner.py
index 7ddeaff..4fa7155 100644
--- a/tools/telemetry/telemetry/internal/story_runner.py
+++ b/tools/telemetry/telemetry/internal/story_runner.py
@@ -13,7 +13,7 @@
 from telemetry.internal.actions import page_action
 from telemetry.page import page_test
 from telemetry.results import results_options
-from telemetry.story import story_filter
+from telemetry import story
 from telemetry.util import cloud_storage
 from telemetry.util import exception_formatter
 from telemetry.value import failure
@@ -25,7 +25,7 @@
 
 
 def AddCommandLineArgs(parser):
-  story_filter.StoryFilter.AddCommandLineArgs(parser)
+  story.StoryFilter.AddCommandLineArgs(parser)
   results_options.AddResultsOptions(parser)
 
   # Page set options
@@ -54,7 +54,7 @@
                     help='Ignore @Disabled and @Enabled restrictions.')
 
 def ProcessCommandLineArgs(parser, args):
-  story_filter.StoryFilter.ProcessCommandLineArgs(parser, args)
+  story.StoryFilter.ProcessCommandLineArgs(parser, args)
   results_options.ProcessCommandLineArgs(parser, args)
 
   # Page set options
@@ -130,30 +130,30 @@
     self._user_stories.append(user_story)
 
 
-def StoriesGroupedByStateClass(user_story_set, allow_multiple_groups):
+def StoriesGroupedByStateClass(story_set, allow_multiple_groups):
   """ Returns a list of user story groups which each contains user stories with
   the same shared_state_class.
 
   Example:
     Assume A1, A2, A3 are user stories with same shared user story class, and
     similar for B1, B2.
-    If their orders in user story set is A1 A2 B1 B2 A3, then the grouping will
+    If their orders in story set is A1 A2 B1 B2 A3, then the grouping will
     be [A1 A2] [B1 B2] [A3].
 
   It's purposefully done this way to make sure that order of user
-  stories are the same of that defined in user_story_set. It's recommended that
+  stories are the same of that defined in story_set. It's recommended that
   user stories with the same states should be arranged next to each others in
-  user story sets to reduce the overhead of setting up & tearing down the
+  story sets to reduce the overhead of setting up & tearing down the
   shared user story state.
   """
   user_story_groups = []
   user_story_groups.append(
-      UserStoryGroup(user_story_set[0].shared_state_class))
-  for user_story in user_story_set:
+      UserStoryGroup(story_set[0].shared_state_class))
+  for user_story in story_set:
     if (user_story.shared_state_class is not
         user_story_groups[-1].shared_state_class):
       if not allow_multiple_groups:
-        raise ValueError('This UserStorySet is only allowed to have one '
+        raise ValueError('This StorySet is only allowed to have one '
                          'SharedState but contains the following '
                          'SharedState classes: %s, %s.\n Either '
                          'remove the extra SharedStates or override '
@@ -166,7 +166,7 @@
   return user_story_groups
 
 
-def Run(test, user_story_set, expectations, finder_options, results,
+def Run(test, story_set, expectations, finder_options, results,
         max_failures=None):
   """Runs a given test against a given page_set with the given options.
 
@@ -175,17 +175,16 @@
   can continue running the remaining user stories.
   """
   # Filter page set based on options.
-  user_stories = filter(story_filter.StoryFilter.IsSelected,
-                              user_story_set)
+  user_stories = filter(story.StoryFilter.IsSelected, story_set)
 
-  if (not finder_options.use_live_sites and user_story_set.bucket and
+  if (not finder_options.use_live_sites and story_set.bucket and
       finder_options.browser_options.wpr_mode != wpr_modes.WPR_RECORD):
-    serving_dirs = user_story_set.serving_dirs
+    serving_dirs = story_set.serving_dirs
     for directory in serving_dirs:
       cloud_storage.GetFilesInDirectoryIfChanged(directory,
-                                                 user_story_set.bucket)
+                                                 story_set.bucket)
     if not _UpdateAndCheckArchives(
-        user_story_set.archive_data_file, user_story_set.wpr_archive_info,
+        story_set.archive_data_file, story_set.wpr_archive_info,
         user_stories):
       return
 
@@ -199,7 +198,7 @@
 
   user_story_groups = StoriesGroupedByStateClass(
       user_stories,
-      user_story_set.allow_mixed_story_states)
+      story_set.allow_mixed_story_states)
 
   for group in user_story_groups:
     state = None
@@ -209,7 +208,7 @@
           for _ in xrange(finder_options.page_repeat):
             if not state:
               state = group.shared_state_class(
-                  test, finder_options, user_story_set)
+                  test, finder_options, story_set)
             results.WillRunPage(user_story)
             try:
               _WaitForThermalThrottlingIfNeeded(state.platform)
@@ -261,13 +260,13 @@
 
   Logs warnings and returns False if any are missing.
   """
-  # Report any problems with the entire user story set.
+  # Report any problems with the entire story set.
   if any(not user_story.is_local for user_story in filtered_user_stories):
     if not archive_data_file:
-      logging.error('The user story set is missing an "archive_data_file" '
+      logging.error('The story set is missing an "archive_data_file" '
                     'property.\nTo run from live sites pass the flag '
                     '--use-live-sites.\nTo create an archive file add an '
-                    'archive_data_file property to the user story set and then '
+                    'archive_data_file property to the story set and then '
                     'run record_wpr.')
       raise ArchiveError('No archive data file.')
     if not wpr_archive_info:
@@ -290,7 +289,7 @@
         user_stories_missing_archive_data.append(user_story)
   if user_stories_missing_archive_path:
     logging.error(
-        'The user story set archives for some user stories do not exist.\n'
+        'The story set archives for some user stories do not exist.\n'
         'To fix this, record those user stories using record_wpr.\n'
         'To ignore this warning and run against live sites, '
         'pass the flag --use-live-sites.')
@@ -300,7 +299,7 @@
                   for user_story in user_stories_missing_archive_path))
   if user_stories_missing_archive_data:
     logging.error(
-        'The user story set archives for some user stories are missing.\n'
+        'The story set archives for some user stories are missing.\n'
         'Someone forgot to check them in, uploaded them to the '
         'wrong cloud storage bucket, or they were deleted.\n'
         'To fix this, record those user stories using record_wpr.\n'
@@ -312,7 +311,7 @@
                   for user_story in user_stories_missing_archive_data))
   if user_stories_missing_archive_path or user_stories_missing_archive_data:
     raise ArchiveError('Archive file is missing user stories.')
-  # Only run valid user stories if no problems with the user story set or
+  # Only run valid user stories if no problems with the story set or
   # individual user stories.
   return True
 
diff --git a/tools/telemetry/telemetry/internal/story_runner_unittest.py b/tools/telemetry/telemetry/internal/story_runner_unittest.py
index 65959c76..390aeb56 100644
--- a/tools/telemetry/telemetry/internal/story_runner_unittest.py
+++ b/tools/telemetry/telemetry/internal/story_runner_unittest.py
@@ -14,14 +14,16 @@
 from telemetry.page import page_test
 from telemetry.page import test_expectations
 from telemetry.results import results_options
+from telemetry import story
 from telemetry.story import shared_state
 from telemetry.unittest_util import options_for_unittests
 from telemetry.unittest_util import system_stub
-from telemetry import user_story
-from telemetry.user_story import user_story_set
+from telemetry import user_story as user_story_module
 from telemetry.util import cloud_storage
 from telemetry.util import exception_formatter as exception_formatter_module
+from telemetry.value import list_of_scalar_values
 from telemetry.value import scalar
+from telemetry.value import summary as summary_module
 from telemetry.web_perf import timeline_based_measurement
 from telemetry.wpr import archive_info
 
@@ -42,9 +44,9 @@
   def SetTestPlatform(cls, platform):
     cls._platform = platform
 
-  def __init__(self, test, options, user_story_setz):
+  def __init__(self, test, options, story_set):
     super(TestSharedState, self).__init__(
-        test, options, user_story_setz)
+        test, options, story_set)
     self._test = test
     self._current_user_story = None
 
@@ -52,8 +54,8 @@
   def platform(self):
     return self._platform
 
-  def WillRunUserStory(self, user_storyz):
-    self._current_user_story = user_storyz
+  def WillRunUserStory(self, user_story):
+    self._current_user_story = user_story
 
   def GetTestExpectationAndSkipValue(self, expectations):
     return 'pass', None
@@ -73,11 +75,11 @@
     self._test.RunPage(self._current_user_story, None, results)
 
 
-class FooUserStoryState(TestSharedPageState):
+class FooStoryState(TestSharedPageState):
   pass
 
 
-class BarUserStoryState(TestSharedPageState):
+class BarStoryState(TestSharedPageState):
   pass
 
 
@@ -94,7 +96,7 @@
     super(EmptyMetadataForTest, self).__init__('')
 
 
-class DummyLocalUserStory(user_story.UserStory):
+class DummyLocalUserStory(user_story_module.UserStory):
   def __init__(self, shared_state_class, name=''):
     super(DummyLocalUserStory, self).__init__(
         shared_state_class, name=name)
@@ -103,19 +105,19 @@
   def is_local(self):
     return True
 
-class MixedStateStorySet(user_story_set.UserStorySet):
+class MixedStateStorySet(story.StorySet):
   @property
   def allow_mixed_story_states(self):
     return True
 
-def SetupUserStorySet(allow_multiple_user_story_states, user_story_state_list):
+def SetupStorySet(allow_multiple_user_story_states, user_story_state_list):
   if allow_multiple_user_story_states:
-    us = MixedStateStorySet()
+    story_set = MixedStateStorySet()
   else:
-    us = user_story_set.UserStorySet()
+    story_set = story.StorySet()
   for user_story_state in user_story_state_list:
-    us.AddUserStory(DummyLocalUserStory(user_story_state))
-  return us
+    story_set.AddUserStory(DummyLocalUserStory(user_story_state))
+  return story_set
 
 def _GetOptionForUnittest():
   options = options_for_unittests.GetCopy()
@@ -168,33 +170,33 @@
     self.RestoreExceptionFormatter()
 
   def testStoriesGroupedByStateClass(self):
-    foo_states = [FooUserStoryState, FooUserStoryState, FooUserStoryState,
-                  FooUserStoryState, FooUserStoryState]
-    mixed_states = [FooUserStoryState, FooUserStoryState, FooUserStoryState,
-                    BarUserStoryState, FooUserStoryState]
-    # UserStorySet's are only allowed to have one SharedState.
-    us = SetupUserStorySet(False, foo_states)
+    foo_states = [FooStoryState, FooStoryState, FooStoryState,
+                  FooStoryState, FooStoryState]
+    mixed_states = [FooStoryState, FooStoryState, FooStoryState,
+                    BarStoryState, FooStoryState]
+    # StorySet's are only allowed to have one SharedState.
+    story_set = SetupStorySet(False, foo_states)
     story_groups = (
         story_runner.StoriesGroupedByStateClass(
-            us, False))
+            story_set, False))
     self.assertEqual(len(story_groups), 1)
-    us = SetupUserStorySet(False, mixed_states)
+    story_set = SetupStorySet(False, mixed_states)
     self.assertRaises(
         ValueError,
         story_runner.StoriesGroupedByStateClass,
-        us, False)
-    # BaseUserStorySets are allowed to have multiple SharedStates.
-    bus = SetupUserStorySet(True, mixed_states)
+        story_set, False)
+    # BaseStorySets are allowed to have multiple SharedStates.
+    mixed_story_set = SetupStorySet(True, mixed_states)
     story_groups = (
         story_runner.StoriesGroupedByStateClass(
-            bus, True))
+            mixed_story_set, True))
     self.assertEqual(len(story_groups), 3)
     self.assertEqual(story_groups[0].shared_state_class,
-                     FooUserStoryState)
+                     FooStoryState)
     self.assertEqual(story_groups[1].shared_state_class,
-                     BarUserStoryState)
+                     BarStoryState)
     self.assertEqual(story_groups[2].shared_state_class,
-                     FooUserStoryState)
+                     FooStoryState)
 
   def RunUserStoryTest(self, us, expected_successes):
     test = DummyTest()
@@ -205,17 +207,17 @@
                       GetNumberOfSuccessfulPageRuns(self.results))
 
   def testUserStoryTest(self):
-    all_foo = [FooUserStoryState, FooUserStoryState, FooUserStoryState]
-    one_bar = [FooUserStoryState, FooUserStoryState, BarUserStoryState]
-    us = SetupUserStorySet(True, one_bar)
-    self.RunUserStoryTest(us, 3)
-    us = SetupUserStorySet(True, all_foo)
-    self.RunUserStoryTest(us, 6)
-    us = SetupUserStorySet(False, all_foo)
-    self.RunUserStoryTest(us, 9)
-    us = SetupUserStorySet(False, one_bar)
+    all_foo = [FooStoryState, FooStoryState, FooStoryState]
+    one_bar = [FooStoryState, FooStoryState, BarStoryState]
+    story_set = SetupStorySet(True, one_bar)
+    self.RunUserStoryTest(story_set, 3)
+    story_set = SetupStorySet(True, all_foo)
+    self.RunUserStoryTest(story_set, 6)
+    story_set = SetupStorySet(False, all_foo)
+    self.RunUserStoryTest(story_set, 9)
+    story_set = SetupStorySet(False, one_bar)
     test = DummyTest()
-    self.assertRaises(ValueError, story_runner.Run, test, us,
+    self.assertRaises(ValueError, story_runner.Run, test, story_set,
                       self.expectations, self.options, self.results)
 
   def testSuccessfulTimelineBasedMeasurementTest(self):
@@ -230,12 +232,12 @@
 
     test = timeline_based_measurement.TimelineBasedMeasurement(
         timeline_based_measurement.Options())
-    us = user_story_set.UserStorySet()
-    us.AddUserStory(DummyLocalUserStory(TestSharedTbmState))
-    us.AddUserStory(DummyLocalUserStory(TestSharedTbmState))
-    us.AddUserStory(DummyLocalUserStory(TestSharedTbmState))
+    story_set = story.StorySet()
+    story_set.AddUserStory(DummyLocalUserStory(TestSharedTbmState))
+    story_set.AddUserStory(DummyLocalUserStory(TestSharedTbmState))
+    story_set.AddUserStory(DummyLocalUserStory(TestSharedTbmState))
     story_runner.Run(
-        test, us, self.expectations, self.options, self.results)
+        test, story_set, self.expectations, self.options, self.results)
     self.assertEquals(0, len(self.results.failures))
     self.assertEquals(3, GetNumberOfSuccessfulPageRuns(self.results))
 
@@ -245,18 +247,18 @@
     fooz_tear_down_call_counter = [0]
     barz_init_call_counter = [0]
     barz_tear_down_call_counter = [0]
-    class FoozUserStoryState(FooUserStoryState):
-      def __init__(self, test, options, user_story_setz):
-        super(FoozUserStoryState, self).__init__(
-          test, options, user_story_setz)
+    class FoozStoryState(FooStoryState):
+      def __init__(self, test, options, storyz):
+        super(FoozStoryState, self).__init__(
+          test, options, storyz)
         fooz_init_call_counter[0] += 1
       def TearDownState(self):
         fooz_tear_down_call_counter[0] += 1
 
-    class BarzUserStoryState(BarUserStoryState):
-      def __init__(self, test, options, user_story_setz):
-        super(BarzUserStoryState, self).__init__(
-          test, options, user_story_setz)
+    class BarzStoryState(BarStoryState):
+      def __init__(self, test, options, storyz):
+        super(BarzStoryState, self).__init__(
+          test, options, storyz)
         barz_init_call_counter[0] += 1
       def TearDownState(self):
         barz_tear_down_call_counter[0] += 1
@@ -266,41 +268,42 @@
       fooz_init_call_counter[0] = 0
       fooz_tear_down_call_counter[0] = 0
 
-    uss1_list = [FoozUserStoryState, FoozUserStoryState, FoozUserStoryState,
-                 BarzUserStoryState, BarzUserStoryState]
-    uss1 = SetupUserStorySet(True, uss1_list)
-    self.RunUserStoryTest(uss1, 15)
+    story_set1_list = [FoozStoryState, FoozStoryState, FoozStoryState,
+                       BarzStoryState, BarzStoryState]
+    story_set1 = SetupStorySet(True, story_set1_list)
+    self.RunUserStoryTest(story_set1, 15)
     AssertAndCleanUpFoo()
     self.assertEquals(1, barz_init_call_counter[0])
     self.assertEquals(1, barz_tear_down_call_counter[0])
     barz_init_call_counter[0] = 0
     barz_tear_down_call_counter[0] = 0
 
-    uss2_list = [FoozUserStoryState, FoozUserStoryState, FoozUserStoryState,
-                 FoozUserStoryState]
-    uss2 = SetupUserStorySet(False, uss2_list)
-    self.RunUserStoryTest(uss2, 27)
+    story_set2_list = [FoozStoryState, FoozStoryState, FoozStoryState,
+                       FoozStoryState]
+    story_set2 = SetupStorySet(False, story_set2_list)
+    self.RunUserStoryTest(story_set2, 27)
     AssertAndCleanUpFoo()
     self.assertEquals(0, barz_init_call_counter[0])
     self.assertEquals(0, barz_tear_down_call_counter[0])
 
   def testAppCrashExceptionCausesFailureValue(self):
     self.SuppressExceptionFormatting()
-    us = user_story_set.UserStorySet()
+    story_set = story.StorySet()
     class SharedUserStoryThatCausesAppCrash(TestSharedPageState):
-      def WillRunUserStory(self, user_storyz):
+      def WillRunUserStory(self, user_story):
         raise exceptions.AppCrashException('App Foo crashes')
 
-    us.AddUserStory(DummyLocalUserStory(SharedUserStoryThatCausesAppCrash))
+    story_set.AddUserStory(DummyLocalUserStory(
+          SharedUserStoryThatCausesAppCrash))
     story_runner.Run(
-        DummyTest(), us, self.expectations, self.options, self.results)
+        DummyTest(), story_set, self.expectations, self.options, self.results)
     self.assertEquals(1, len(self.results.failures))
     self.assertEquals(0, GetNumberOfSuccessfulPageRuns(self.results))
     self.assertIn('App Foo crashes', self.fake_stdout.getvalue())
 
   def testUnknownExceptionIsFatal(self):
     self.SuppressExceptionFormatting()
-    uss = user_story_set.UserStorySet()
+    story_set = story.StorySet()
 
     class UnknownException(Exception):
       pass
@@ -323,19 +326,19 @@
 
     us1 = DummyLocalUserStory(TestSharedPageState)
     us2 = DummyLocalUserStory(TestSharedPageState)
-    uss.AddUserStory(us1)
-    uss.AddUserStory(us2)
+    story_set.AddUserStory(us1)
+    story_set.AddUserStory(us2)
     test = Test()
     with self.assertRaises(UnknownException):
       story_runner.Run(
-          test, uss, self.expectations, self.options, self.results)
+          test, story_set, self.expectations, self.options, self.results)
     self.assertEqual(set([us2]), self.results.pages_that_failed)
     self.assertEqual(set([us1]), self.results.pages_that_succeeded)
     self.assertIn('FooBarzException', self.fake_stdout.getvalue())
 
   def testRaiseBrowserGoneExceptionFromRunPage(self):
     self.SuppressExceptionFormatting()
-    us = user_story_set.UserStorySet()
+    story_set = story.StorySet()
 
     class Test(page_test.PageTest):
       def __init__(self, *args):
@@ -351,18 +354,18 @@
       def ValidateAndMeasurePage(self, page, tab, results):
         pass
 
-    us.AddUserStory(DummyLocalUserStory(TestSharedPageState))
-    us.AddUserStory(DummyLocalUserStory(TestSharedPageState))
+    story_set.AddUserStory(DummyLocalUserStory(TestSharedPageState))
+    story_set.AddUserStory(DummyLocalUserStory(TestSharedPageState))
     test = Test()
     story_runner.Run(
-        test, us, self.expectations, self.options, self.results)
+        test, story_set, self.expectations, self.options, self.results)
     self.assertEquals(2, test.run_count)
     self.assertEquals(1, len(self.results.failures))
     self.assertEquals(1, GetNumberOfSuccessfulPageRuns(self.results))
 
   def testAppCrashThenRaiseInTearDownFatal(self):
     self.SuppressExceptionFormatting()
-    us = user_story_set.UserStorySet()
+    story_set = story.StorySet()
 
     unit_test_events = []  # track what was called when
     class DidRunTestError(Exception):
@@ -389,21 +392,25 @@
       def ValidateAndMeasurePage(self, page, tab, results):
         pass
 
-    us.AddUserStory(DummyLocalUserStory(TestTearDownSharedState))
-    us.AddUserStory(DummyLocalUserStory(TestTearDownSharedState))
+    story_set.AddUserStory(DummyLocalUserStory(TestTearDownSharedState))
+    story_set.AddUserStory(DummyLocalUserStory(TestTearDownSharedState))
     test = Test()
 
     with self.assertRaises(DidRunTestError):
       story_runner.Run(
-          test, us, self.expectations, self.options, self.results)
+          test, story_set, self.expectations, self.options, self.results)
     self.assertEqual(['app-crash', 'tear-down-state'], unit_test_events)
     # The AppCrashException gets added as a failure.
     self.assertEquals(1, len(self.results.failures))
 
   def testPagesetRepeat(self):
-    us = user_story_set.UserStorySet()
-    us.AddUserStory(DummyLocalUserStory(TestSharedPageState, name='blank'))
-    us.AddUserStory(DummyLocalUserStory(TestSharedPageState, name='green'))
+    story_set = story.StorySet()
+
+    # TODO(eakuefner): Factor this out after flattening page ref in Value
+    blank_story = DummyLocalUserStory(TestSharedPageState, name='blank')
+    green_story = DummyLocalUserStory(TestSharedPageState, name='green')
+    story_set.AddUserStory(blank_story)
+    story_set.AddUserStory(green_story)
 
     class Measurement(page_test.PageTest):
       i = 0
@@ -417,72 +424,90 @@
 
     self.options.page_repeat = 1
     self.options.pageset_repeat = 2
-    self.options.output_formats = ['buildbot']
+    self.options.output_formats = []
     results = results_options.CreateResults(
       EmptyMetadataForTest(), self.options)
     story_runner.Run(
-        Measurement(), us, self.expectations, self.options, results)
-    results.PrintSummary()
-    contents = self.fake_stdout.getvalue()
+        Measurement(), story_set, self.expectations, self.options, results)
+    summary = summary_module.Summary(results.all_page_specific_values)
+    values = summary.interleaved_computed_per_page_values_and_summaries
+
+    blank_value = list_of_scalar_values.ListOfScalarValues(
+        blank_story, 'metric', 'unit', [1, 3])
+    green_value = list_of_scalar_values.ListOfScalarValues(
+        green_story, 'metric', 'unit', [2, 4])
+    merged_value = list_of_scalar_values.ListOfScalarValues(
+        None, 'metric', 'unit', [1, 2, 3, 4])
+
     self.assertEquals(4, GetNumberOfSuccessfulPageRuns(results))
     self.assertEquals(0, len(results.failures))
-    self.assertIn('RESULT metric: blank= [1,3] unit', contents)
-    self.assertIn('RESULT metric: green= [2,4] unit', contents)
-    self.assertIn('*RESULT metric: metric= [1,2,3,4] unit', contents)
+    self.assertEquals(3, len(values))
+    self.assertIn(blank_value, values)
+    self.assertIn(green_value, values)
+    self.assertIn(merged_value, values)
 
   @decorators.Disabled('chromeos')  # crbug.com/483212
   def testUpdateAndCheckArchives(self):
     usr_stub = system_stub.Override(story_runner, ['cloud_storage'])
     wpr_stub = system_stub.Override(archive_info, ['cloud_storage'])
     try:
-      uss = user_story_set.UserStorySet()
-      uss.AddUserStory(page_module.Page(
-          'http://www.testurl.com', uss, uss.base_dir))
+      story_set = story.StorySet()
+      story_set.AddUserStory(page_module.Page(
+          'http://www.testurl.com', story_set, story_set.base_dir))
       # Page set missing archive_data_file.
       self.assertRaises(
           story_runner.ArchiveError,
           story_runner._UpdateAndCheckArchives,
-          uss.archive_data_file, uss.wpr_archive_info, uss.user_stories)
+          story_set.archive_data_file,
+          story_set.wpr_archive_info,
+          story_set.user_stories)
 
-      uss = user_story_set.UserStorySet(
+      story_set = story.StorySet(
           archive_data_file='missing_archive_data_file.json')
-      uss.AddUserStory(page_module.Page(
-          'http://www.testurl.com', uss, uss.base_dir))
+      story_set.AddUserStory(page_module.Page(
+          'http://www.testurl.com', story_set, story_set.base_dir))
       # Page set missing json file specified in archive_data_file.
       self.assertRaises(
           story_runner.ArchiveError,
           story_runner._UpdateAndCheckArchives,
-          uss.archive_data_file, uss.wpr_archive_info, uss.user_stories)
+          story_set.archive_data_file,
+          story_set.wpr_archive_info,
+          story_set.user_stories)
 
-      uss = user_story_set.UserStorySet(
+      story_set = story.StorySet(
           archive_data_file='../../unittest_data/archive_files/test.json',
           cloud_storage_bucket=cloud_storage.PUBLIC_BUCKET)
-      uss.AddUserStory(page_module.Page(
-          'http://www.testurl.com', uss, uss.base_dir))
+      story_set.AddUserStory(page_module.Page(
+          'http://www.testurl.com', story_set, story_set.base_dir))
       # Page set with valid archive_data_file.
       self.assertTrue(story_runner._UpdateAndCheckArchives(
-          uss.archive_data_file, uss.wpr_archive_info, uss.user_stories))
-      uss.AddUserStory(page_module.Page(
-          'http://www.google.com', uss, uss.base_dir))
+            story_set.archive_data_file, story_set.wpr_archive_info,
+            story_set.user_stories))
+      story_set.AddUserStory(page_module.Page(
+          'http://www.google.com', story_set, story_set.base_dir))
       # Page set with an archive_data_file which exists but is missing a page.
       self.assertRaises(
           story_runner.ArchiveError,
           story_runner._UpdateAndCheckArchives,
-          uss.archive_data_file, uss.wpr_archive_info, uss.user_stories)
+          story_set.archive_data_file,
+          story_set.wpr_archive_info,
+          story_set.user_stories)
 
-      uss = user_story_set.UserStorySet(
+      story_set = story.StorySet(
           archive_data_file='../../unittest_data/test_missing_wpr_file.json',
           cloud_storage_bucket=cloud_storage.PUBLIC_BUCKET)
-      uss.AddUserStory(page_module.Page(
-          'http://www.testurl.com', uss, uss.base_dir))
-      uss.AddUserStory(page_module.Page(
-          'http://www.google.com', uss, uss.base_dir))
+      story_set.AddUserStory(page_module.Page(
+          'http://www.testurl.com', story_set, story_set.base_dir))
+      story_set.AddUserStory(page_module.Page(
+          'http://www.google.com', story_set, story_set.base_dir))
       # Page set with an archive_data_file which exists and contains all pages
       # but fails to find a wpr file.
       self.assertRaises(
           story_runner.ArchiveError,
           story_runner._UpdateAndCheckArchives,
-          uss.archive_data_file, uss.wpr_archive_info, uss.user_stories)
+          story_set.archive_data_file,
+          story_set.wpr_archive_info,
+          story_set.user_stories)
     finally:
       usr_stub.Restore()
       wpr_stub.Restore()
@@ -500,8 +525,8 @@
       def platform(self):
         return self._fake_platform
 
-      def WillRunUserStory(self, story):
-        self._current_user_story = story
+      def WillRunUserStory(self, user_story):
+        self._current_user_story = user_story
 
       def RunUserStory(self, results):
         self._current_user_story.Run()
@@ -515,7 +540,7 @@
       def TearDownState(self):
         pass
 
-    class FailingUserStory(user_story.UserStory):
+    class FailingUserStory(user_story_module.UserStory):
       def __init__(self):
         super(FailingUserStory, self).__init__(
             shared_state_class=SimpleSharedState,
@@ -528,9 +553,9 @@
 
     self.SuppressExceptionFormatting()
 
-    uss = user_story_set.UserStorySet()
+    story_set = story.StorySet()
     for _ in range(num_failing_user_stories):
-      uss.AddUserStory(FailingUserStory())
+      story_set.AddUserStory(FailingUserStory())
 
     options = _GetOptionForUnittest()
     options.output_formats = ['none']
@@ -540,12 +565,12 @@
 
     results = results_options.CreateResults(EmptyMetadataForTest(), options)
     story_runner.Run(
-        DummyTest(), uss, test_expectations.TestExpectations(), options,
+        DummyTest(), story_set, test_expectations.TestExpectations(), options,
         results, max_failures=runner_max_failures)
     self.assertEquals(0, GetNumberOfSuccessfulPageRuns(results))
     self.assertEquals(expected_num_failures, len(results.failures))
-    for ii, story in enumerate(uss.user_stories):
-      self.assertEqual(story.was_run, ii < expected_num_failures)
+    for ii, user_story in enumerate(story_set.user_stories):
+      self.assertEqual(user_story.was_run, ii < expected_num_failures)
 
   def testMaxFailuresNotSpecified(self):
     self._testMaxFailuresOptionIsRespectedAndOverridable(
diff --git a/tools/telemetry/telemetry/page/__init__.py b/tools/telemetry/telemetry/page/__init__.py
index 9e7abea..be27f47 100644
--- a/tools/telemetry/telemetry/page/__init__.py
+++ b/tools/telemetry/telemetry/page/__init__.py
@@ -12,20 +12,11 @@
 from telemetry.util import path
 
 
-def _UpdateCredentials(credentials_path):
-  # Attempt to download the credentials file.
-  try:
-    cloud_storage.GetIfChanged(credentials_path, cloud_storage.PUBLIC_BUCKET)
-  except (cloud_storage.CredentialsError, cloud_storage.PermissionError,
-          cloud_storage.CloudStorageError) as e:
-    logging.warning('Cannot retrieve credential file %s due to cloud storage '
-                    'error %s', credentials_path, str(e))
-
-
 class Page(user_story.UserStory):
   def __init__(self, url, page_set=None, base_dir=None, name='',
-               credentials_path=None, labels=None, startup_url='',
-               make_javascript_deterministic=True,
+               credentials_path=None,
+               credentials_bucket=cloud_storage.PUBLIC_BUCKET, labels=None,
+               startup_url='', make_javascript_deterministic=True,
                shared_page_state_class=shared_page_state.SharedPageState):
     self._url = url
 
@@ -43,7 +34,7 @@
     self._name = name
     if credentials_path:
       credentials_path = os.path.join(self._base_dir, credentials_path)
-      _UpdateCredentials(credentials_path)
+      cloud_storage.GetIfChanged(credentials_path, credentials_bucket)
       if not os.path.exists(credentials_path):
         logging.error('Invalid credentials path: %s' % credentials_path)
         credentials_path = None
diff --git a/tools/telemetry/telemetry/page/page_set.py b/tools/telemetry/telemetry/page/page_set.py
index b73ba41..0287c51 100644
--- a/tools/telemetry/telemetry/page/page_set.py
+++ b/tools/telemetry/telemetry/page/page_set.py
@@ -5,19 +5,19 @@
 import os
 
 from telemetry.page import page as page_module
-from telemetry.user_story import user_story_set
+from telemetry import story
 
-PUBLIC_BUCKET = user_story_set.PUBLIC_BUCKET
-PARTNER_BUCKET = user_story_set.PARTNER_BUCKET
-INTERNAL_BUCKET = user_story_set.INTERNAL_BUCKET
+PUBLIC_BUCKET = story.PUBLIC_BUCKET
+PARTNER_BUCKET = story.PARTNER_BUCKET
+INTERNAL_BUCKET = story.INTERNAL_BUCKET
 
 
-class PageSet(user_story_set.UserStorySet):
+class PageSet(story.StorySet):
   def __init__(self, file_path=None, archive_data_file='', user_agent_type=None,
                serving_dirs=None, bucket=None):
     # The default value of file_path is location of the file that define this
     # page set instance's class.
-    # TODO(aiolos): When migrating page_sets over to user_story_sets, make
+    # TODO(aiolos): When migrating page_sets over to story_sets, make
     # sure that we are passing a valid directory path in to base_dir, and not
     # a file path like we curerntly do in some cases for file_path.
     dir_name = file_path
diff --git a/tools/telemetry/telemetry/page/shared_page_state.py b/tools/telemetry/telemetry/page/shared_page_state.py
index 38a9b6e..833b694 100644
--- a/tools/telemetry/telemetry/page/shared_page_state.py
+++ b/tools/telemetry/telemetry/page/shared_page_state.py
@@ -37,15 +37,15 @@
 
   _device_type = None
 
-  def __init__(self, test, finder_options, user_story_set):
-    super(SharedPageState, self).__init__(test, finder_options, user_story_set)
+  def __init__(self, test, finder_options, story_set):
+    super(SharedPageState, self).__init__(test, finder_options, story_set)
     if isinstance(test, timeline_based_measurement.TimelineBasedMeasurement):
       # This is to avoid the cyclic-import caused by timeline_based_page_test.
       from telemetry.web_perf import timeline_based_page_test
       self._test = timeline_based_page_test.TimelineBasedPageTest(test)
     else:
       self._test = test
-    device_type = self._device_type or user_story_set.user_agent_type
+    device_type = self._device_type or story_set.user_agent_type
     _PrepareFinderOptions(finder_options, self._test, device_type)
     self.browser = None
     self._finder_options = finder_options
diff --git a/tools/telemetry/telemetry/page/shared_page_state_unittest.py b/tools/telemetry/telemetry/page/shared_page_state_unittest.py
index b65eaa6..b96cb5ef 100644
--- a/tools/telemetry/telemetry/page/shared_page_state_unittest.py
+++ b/tools/telemetry/telemetry/page/shared_page_state_unittest.py
@@ -11,8 +11,8 @@
 from telemetry.page import page_set
 from telemetry.page import page_test
 from telemetry.page import shared_page_state
+from telemetry import story
 from telemetry.unittest_util import options_for_unittests
-from telemetry.user_story import user_story_set
 
 
 def SetUpPageRunnerArguments(options):
@@ -74,9 +74,9 @@
         'http://www.google.com',
         shared_page_state_class=shared_page_state_class)
     test = DummyTest()
-    uss = user_story_set.UserStorySet()
-    uss.AddUserStory(us)
-    us.shared_state_class(test, self.options, uss)
+    story_set = story.StorySet()
+    story_set.AddUserStory(us)
+    us.shared_state_class(test, self.options, story_set)
     browser_options = self.options.browser_options
     actual_user_agent = browser_options.browser_user_agent_type
     self.assertEqual(expected_user_agent, actual_user_agent)
diff --git a/tools/telemetry/telemetry/results/csv_output_formatter.py b/tools/telemetry/telemetry/results/csv_output_formatter.py
deleted file mode 100644
index 3c10657a..0000000
--- a/tools/telemetry/telemetry/results/csv_output_formatter.py
+++ /dev/null
@@ -1,74 +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 csv
-
-from telemetry.results import output_formatter
-from telemetry.value import merge_values
-
-
-class CsvOutputFormatter(output_formatter.OutputFormatter):
-  def __init__(self, output_stream):
-    super(CsvOutputFormatter, self).__init__(output_stream)
-
-  def Format(self, page_test_results):
-    values = merge_values.MergeLikeValuesFromSamePage(
-        page_test_results.all_page_specific_values)
-    writer = csv.writer(self.output_stream)
-    header_value_names = self._OutputHeader(values, writer)
-    value_groups_by_page = merge_values.GroupStably(
-        values, lambda value: value.page.url)
-    for values_for_page in value_groups_by_page:
-      self._OutputValuesForPage(
-          header_value_names, values_for_page[0].page, values_for_page,
-          writer)
-
-  def _OutputHeader(self, values, csv_writer):
-    """Output the header rows.
-
-    This will retrieve the header string from the given values. As a
-    results, you would typically pass it all of the recorded values at
-    the end of the entire telemetry run. In cases where each page
-    produces the same set of value names, you may call this method
-    with that set of values.
-
-    Args:
-      values: A set of values from which to extract the header string,
-          which is the value name and the units.
-      writer: A csv.writer instance.
-
-    Returns:
-      The value names being output on the header, in the order of
-      output.
-    """
-    representative_values = {}
-    for value in values:
-      if value.name not in representative_values:
-        representative_values[value.name] = value
-    header_value_names = list(representative_values.keys())
-    header_value_names.sort()
-
-    row = ['page_name']
-    for value_name in header_value_names:
-      units = representative_values[value_name].units
-      row.append('%s (%s)' % (value_name, units))
-    csv_writer.writerow(row)
-    self.output_stream.flush()
-    return header_value_names
-
-  def _OutputValuesForPage(self, header_value_names, page, page_values,
-                           csv_writer):
-    row = [page.display_name]
-    values_by_value_name = {}
-    for value in page_values:
-      values_by_value_name[value.name] = value
-
-    for value_name in header_value_names:
-      value = values_by_value_name.get(value_name, None)
-      if value and value.GetRepresentativeNumber():
-        row.append('%s' % value.GetRepresentativeNumber())
-      else:
-        row.append('-')
-    csv_writer.writerow(row)
-    self.output_stream.flush()
diff --git a/tools/telemetry/telemetry/results/csv_output_formatter_unittest.py b/tools/telemetry/telemetry/results/csv_output_formatter_unittest.py
deleted file mode 100644
index 1aac38c..0000000
--- a/tools/telemetry/telemetry/results/csv_output_formatter_unittest.py
+++ /dev/null
@@ -1,122 +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 csv
-import os
-import StringIO
-import unittest
-
-from telemetry import page as page_module
-from telemetry.page import page_set
-from telemetry.results import csv_output_formatter
-from telemetry.results import page_test_results
-from telemetry.value import histogram
-from telemetry.value import scalar
-
-
-def _MakePageSet():
-  ps = page_set.PageSet(file_path=os.path.dirname(__file__))
-  ps.AddUserStory(page_module.Page('http://www.foo.com/', ps, ps.base_dir))
-  ps.AddUserStory(page_module.Page('http://www.bar.com/', ps, ps.base_dir))
-  return ps
-
-
-class CsvOutputFormatterTest(unittest.TestCase):
-  def setUp(self):
-    self._output = StringIO.StringIO()
-    self._page_set = _MakePageSet()
-    self._formatter = csv_output_formatter.CsvOutputFormatter(self._output)
-
-  @property
-  def lines(self):
-    lines = StringIO.StringIO(self._output.getvalue()).readlines()
-    return lines
-
-  @property
-  def output_header_row(self):
-    rows = list(csv.reader(self.lines))
-    return rows[0]
-
-  @property
-  def output_data_rows(self):
-    rows = list(csv.reader(self.lines))
-    return rows[1:]
-
-  def test_with_no_results_on_second_run(self):
-    results = page_test_results.PageTestResults()
-    results.WillRunPage(self._page_set[0])
-    results.AddValue(scalar.ScalarValue(self._page_set[0], 'foo', 'seconds', 3))
-    results.DidRunPage(self._page_set[0])
-
-    results.WillRunPage(self._page_set[1])
-    results.DidRunPage(self._page_set[1])
-
-    self._formatter.Format(results)
-
-    self.assertEqual(['page_name', 'foo (seconds)'], self.output_header_row)
-    # TODO(chrishenry): Is this really the right behavior? Should this
-    # not output a second row with '-' as its results?
-    expected = [[self._page_set[0].url, '3.0']]
-    self.assertEqual(expected, self.output_data_rows)
-
-  def test_fewer_results_on_second_run(self):
-    results = page_test_results.PageTestResults()
-    results.WillRunPage(self._page_set[0])
-    results.AddValue(scalar.ScalarValue(self._page_set[0], 'foo', 'seconds', 3))
-    results.AddValue(scalar.ScalarValue(self._page_set[0], 'bar', 'seconds', 4))
-    results.DidRunPage(self._page_set[0])
-
-    results.WillRunPage(self._page_set[1])
-    results.AddValue(scalar.ScalarValue(self._page_set[1], 'bar', 'seconds', 5))
-    results.DidRunPage(self._page_set[1])
-
-    self._formatter.Format(results)
-    self.assertEqual(['page_name', 'bar (seconds)', 'foo (seconds)'],
-                     self.output_header_row)
-    expected = [[self._page_set[0].url, '4.0', '3.0'],
-                [self._page_set[1].url, '5.0', '-']]
-    self.assertEqual(expected, self.output_data_rows)
-
-  def test_with_output_at_print_summary_time(self):
-    results = page_test_results.PageTestResults()
-    results.WillRunPage(self._page_set[0])
-    results.AddValue(scalar.ScalarValue(self._page_set[0], 'foo', 'seconds', 3))
-    results.DidRunPage(self._page_set[0])
-
-    results.WillRunPage(self._page_set[1])
-    results.AddValue(scalar.ScalarValue(self._page_set[1], 'bar', 'seconds', 4))
-    results.DidRunPage(self._page_set[1])
-
-    self._formatter.Format(results)
-
-    self.assertEqual(
-      self.output_header_row,
-      ['page_name', 'bar (seconds)', 'foo (seconds)'])
-
-    expected = [[self._page_set[0].display_name, '-', '3.0'],
-                [self._page_set[1].display_name, '4.0', '-']]
-    self.assertEqual(expected, self.output_data_rows)
-
-  def test_histogram(self):
-    results = page_test_results.PageTestResults()
-    results.WillRunPage(self._page_set[0])
-    results.AddValue(histogram.HistogramValue(
-        self._page_set[0], 'a', '',
-        raw_value_json='{"buckets": [{"low": 1, "high": 2, "count": 1}]}'))
-    results.DidRunPage(self._page_set[0])
-
-    results.WillRunPage(self._page_set[1])
-    results.AddValue(histogram.HistogramValue(
-        self._page_set[1], 'a', '',
-        raw_value_json='{"buckets": [{"low": 2, "high": 3, "count": 1}]}'))
-    results.DidRunPage(self._page_set[1])
-
-    self._formatter.Format(results)
-
-    self.assertEqual(
-        self.output_header_row,
-        ['page_name', 'a ()'])
-    self.assertEqual(
-        self.output_data_rows,
-        [[self._page_set[0].display_name, '1.5'],
-         [self._page_set[1].display_name, '2.5']])
diff --git a/tools/telemetry/telemetry/results/html_output_formatter.py b/tools/telemetry/telemetry/results/html_output_formatter.py
index b633702e..d9930f5 100644
--- a/tools/telemetry/telemetry/results/html_output_formatter.py
+++ b/tools/telemetry/telemetry/results/html_output_formatter.py
@@ -20,11 +20,11 @@
 
 _TEMPLATE_HTML_PATH = os.path.join(
     util.GetTelemetryDir(), 'support', 'html_output', 'results-template.html')
-_PLUGINS = [('third_party', 'flot', 'jquery.flot.min.js'),
-            ('third_party', 'WebKit', 'PerformanceTests', 'resources',
-             'jquery.tablesorter.min.js'),
-            ('third_party', 'WebKit', 'PerformanceTests', 'resources',
-             'statistics.js')]
+_JS_PLUGINS = [os.path.join('flot', 'jquery.flot.min.js'),
+               os.path.join('WebKit', 'PerformanceTests', 'resources',
+                            'jquery.tablesorter.min.js'),
+               os.path.join('WebKit', 'PerformanceTests', 'resources',
+                            'statistics.js')]
 _UNIT_JSON = ('tools', 'perf', 'unit-info.json')
 
 
@@ -59,8 +59,8 @@
 
   def _GetPlugins(self):
     plugins = ''
-    for p in _PLUGINS:
-      with open(os.path.join(util.GetChromiumSrcDir(), *p)) as f:
+    for p in _JS_PLUGINS:
+      with open(os.path.join(util.GetTelemetryThirdPartyDir(), p)) as f:
         plugins += f.read()
     return plugins
 
diff --git a/tools/telemetry/telemetry/results/page_test_results.py b/tools/telemetry/telemetry/results/page_test_results.py
index 336621c..90ac871 100644
--- a/tools/telemetry/telemetry/results/page_test_results.py
+++ b/tools/telemetry/telemetry/results/page_test_results.py
@@ -28,7 +28,7 @@
       output_stream: The output stream to use to write test results.
       output_formatters: A list of output formatters. The output
           formatters are typically used to format the test results, such
-          as CsvOutputFormatter, which output the test results as CSV.
+          as CsvPivotTableOutputFormatter, which output the test results as CSV.
       progress_reporter: An instance of progress_reporter.ProgressReporter,
           to be used to output test status/results progressively.
       trace_tag: A string to append to the buildbot trace name. Currently only
@@ -36,10 +36,10 @@
       output_dir: A string specified the directory where to store the test
           artifacts, e.g: trace, videos,...
       value_can_be_added_predicate: A function that takes two arguments:
-          a value.Value instance (except value.FailureValue & value.SkipValue)
-          and a boolean (True when the value is part of the first result for
-          the user story). It returns True if the value can be added to the
-          test results and False otherwise.
+          a value.Value instance (except failure.FailureValue, skip.SkipValue
+          or trace.TraceValue) and a boolean (True when the value is part of
+          the first result for the user story). It returns True if the value
+          can be added to the test results and False otherwise.
     """
     # TODO(chrishenry): Figure out if trace_tag is still necessary.
 
@@ -173,6 +173,7 @@
       self._current_page_run.user_story not in self._all_user_stories)
     if not (isinstance(value, skip.SkipValue) or
             isinstance(value, failure.FailureValue) or
+            isinstance(value, trace.TraceValue) or
             self._value_can_be_added_predicate(value, is_first_result)):
       return
     # TODO(eakuefner/chrishenry): Add only one skip per pagerun assert here
diff --git a/tools/telemetry/telemetry/results/results_options.py b/tools/telemetry/telemetry/results/results_options.py
index dd1cc7e..26d76bfc 100644
--- a/tools/telemetry/telemetry/results/results_options.py
+++ b/tools/telemetry/telemetry/results/results_options.py
@@ -9,7 +9,6 @@
 from telemetry.core import util
 from telemetry.results import buildbot_output_formatter
 from telemetry.results import chart_json_output_formatter
-from telemetry.results import csv_output_formatter
 from telemetry.results import csv_pivot_table_output_formatter
 from telemetry.results import gtest_progress_reporter
 from telemetry.results import html_output_formatter
@@ -18,14 +17,13 @@
 from telemetry.results import progress_reporter
 
 # Allowed output formats. The default is the first item in the list.
-_OUTPUT_FORMAT_CHOICES = ('html', 'buildbot', 'csv', 'gtest', 'json',
+_OUTPUT_FORMAT_CHOICES = ('html', 'buildbot', 'gtest', 'json',
     'chartjson', 'csv-pivot-table', 'none')
 
 
 # Filenames to use for given output formats.
 _OUTPUT_FILENAME_LOOKUP = {
     'html': 'results.html',
-    'csv': 'results.csv',
     'json': 'results.json',
     'chartjson': 'results-chart.json',
     'csv-pivot-table': 'results-pivot-table.csv'
@@ -122,10 +120,7 @@
       continue
 
     output_stream = _GetOutputStream(output_format, options.output_dir)
-    if output_format == 'csv':
-      output_formatters.append(csv_output_formatter.CsvOutputFormatter(
-          output_stream))
-    elif output_format == 'csv-pivot-table':
+    if output_format == 'csv-pivot-table':
       output_formatters.append(
           csv_pivot_table_output_formatter.CsvPivotTableOutputFormatter(
               output_stream, trace_tag=options.output_trace_tag))
diff --git a/tools/telemetry/telemetry/results/user_story_run_unittest.py b/tools/telemetry/telemetry/results/user_story_run_unittest.py
index e9d7823..c4be99c9 100644
--- a/tools/telemetry/telemetry/results/user_story_run_unittest.py
+++ b/tools/telemetry/telemetry/results/user_story_run_unittest.py
@@ -6,8 +6,8 @@
 
 from telemetry.results import user_story_run
 from telemetry.story import shared_state
+from telemetry.story import story_set
 from telemetry import user_story as user_story_module
-from telemetry.user_story import user_story_set
 from telemetry.value import failure
 from telemetry.value import scalar
 from telemetry.value import skip
@@ -24,12 +24,12 @@
 
 class UserStoryRunTest(unittest.TestCase):
   def setUp(self):
-    self.user_story_set = user_story_set.UserStorySet()
-    self.user_story_set.AddUserStory(UserStoryFoo())
+    self.story_set = story_set.StorySet()
+    self.story_set.AddUserStory(UserStoryFoo())
 
   @property
   def user_stories(self):
-    return self.user_story_set.user_stories
+    return self.story_set.user_stories
 
   def testUserStoryRunFailed(self):
     run = user_story_run.UserStoryRun(self.user_stories[0])
diff --git a/tools/telemetry/telemetry/story/__init__.py b/tools/telemetry/telemetry/story/__init__.py
index 724a1a9..27a57738 100644
--- a/tools/telemetry/telemetry/story/__init__.py
+++ b/tools/telemetry/telemetry/story/__init__.py
@@ -2,4 +2,12 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# TODO (aiolos): replace with user_story/__init__.py in subsequent cl.
+from telemetry.story.shared_state import SharedState
+from telemetry.story.story_set import StorySet
+from telemetry.story.story_filter import StoryFilter
+from telemetry.util import cloud_storage
+
+
+PUBLIC_BUCKET = cloud_storage.PUBLIC_BUCKET
+PARTNER_BUCKET = cloud_storage.PARTNER_BUCKET
+INTERNAL_BUCKET = cloud_storage.INTERNAL_BUCKET
diff --git a/tools/telemetry/telemetry/story/shared_state.py b/tools/telemetry/telemetry/story/shared_state.py
index 167d4a6..ba4169e3 100644
--- a/tools/telemetry/telemetry/story/shared_state.py
+++ b/tools/telemetry/telemetry/story/shared_state.py
@@ -9,7 +9,7 @@
 
   """
 
-  def __init__(self, test, options, user_story_set):
+  def __init__(self, test, options, story_set):
     """ This method is styled on unittest.TestCase.setUpClass.
     Override to do any action before running user stories that
     share this same state.
@@ -17,7 +17,7 @@
       test: a page_test.PageTest instance.
       options: a BrowserFinderOptions instance that contains command line
         options.
-      user_story_set: a user_story_set.UserStorySet instance.
+      story_set: a story.StorySet instance.
     """
     pass
 
diff --git a/tools/telemetry/telemetry/story/story_filter.py b/tools/telemetry/telemetry/story/story_filter.py
index 7219894..1bf530a 100644
--- a/tools/telemetry/telemetry/story/story_filter.py
+++ b/tools/telemetry/telemetry/story/story_filter.py
@@ -39,7 +39,7 @@
 
 
 class StoryFilter(command_line.ArgumentHandlerMixIn):
-  """Filters user stories in the user story set based on command-line flags."""
+  """Filters user stories in the story set based on command-line flags."""
 
   @classmethod
   def AddCommandLineArgs(cls, parser):
diff --git a/tools/telemetry/telemetry/user_story/user_story_set.py b/tools/telemetry/telemetry/story/story_set.py
similarity index 87%
rename from tools/telemetry/telemetry/user_story/user_story_set.py
rename to tools/telemetry/telemetry/story/story_set.py
index d18941c..3a2c7c7 100644
--- a/tools/telemetry/telemetry/user_story/user_story_set.py
+++ b/tools/telemetry/telemetry/story/story_set.py
@@ -6,32 +6,27 @@
 import os
 
 from telemetry import user_story as user_story_module
-from telemetry.util import cloud_storage
 from telemetry.wpr import archive_info
 
-PUBLIC_BUCKET = cloud_storage.PUBLIC_BUCKET
-PARTNER_BUCKET = cloud_storage.PARTNER_BUCKET
-INTERNAL_BUCKET = cloud_storage.INTERNAL_BUCKET
 
-
-class UserStorySet(object):
+class StorySet(object):
   """A collection of user story.
 
-  A typical usage of UserStorySet would be to subclass it and then calling
+  A typical usage of StorySet would be to subclass it and then calling
   AddUserStory for each UserStory.
   """
 
   def __init__(self, archive_data_file='', cloud_storage_bucket=None,
                base_dir=None, serving_dirs=None):
-    """Creates a new UserStorySet.
+    """Creates a new StorySet.
 
     Args:
       archive_data_file: The path to Web Page Replay's archive data, relative
           to self.base_dir.
       cloud_storage_bucket: The cloud storage bucket used to download
           Web Page Replay's archive data. Valid values are: None,
-          PUBLIC_BUCKET, PARTNER_BUCKET, or INTERNAL_BUCKET (defined
-          in telemetry.util.cloud_storage).
+          story.PUBLIC_BUCKET, story.PARTNER_BUCKET, or story.INTERNAL_BUCKET
+          (defined in telemetry.util.cloud_storage).
       serving_dirs: A set of paths, relative to self.base_dir, to directories
           containing hash files for non-wpr archive data stored in cloud
           storage.
@@ -56,7 +51,7 @@
     """True iff UserStories are allowed to have different StoryState classes.
 
     There are no checks in place for determining if SharedStates are
-    being assigned correctly to all UserStorys in a given UserStorySet. The
+    being assigned correctly to all UserStorys in a given StorySet. The
     majority of test cases should not need the ability to have multiple
     ShareduserStoryStates, and usually implies you should be writing multiple
     benchmarks instead. We provide errors to avoid accidentally assigning
@@ -73,7 +68,7 @@
   def base_dir(self):
     """The base directory to resolve archive_data_file.
 
-    This defaults to the directory containing the UserStorySet instance's class.
+    This defaults to the directory containing the StorySet instance's class.
     """
     return self._base_dir
 
@@ -114,7 +109,7 @@
 
   @classmethod
   def Name(cls):
-    """Returns the string name of this UserStorySet.
+    """Returns the string name of this StorySet.
     Note that this should be a classmethod so benchmark_runner script can match
     user story class with its name specified in the run command:
     'Run <User story test name> <User story class name>'
diff --git a/tools/telemetry/telemetry/story/story_set_unittest.py b/tools/telemetry/telemetry/story/story_set_unittest.py
new file mode 100644
index 0000000..878eed3
--- /dev/null
+++ b/tools/telemetry/telemetry/story/story_set_unittest.py
@@ -0,0 +1,82 @@
+# 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 os
+import unittest
+
+from telemetry import story
+from telemetry.story import shared_state
+from telemetry import user_story
+
+
+# pylint: disable=abstract-method
+class SharedStateBar(shared_state.SharedState):
+  pass
+
+
+class UserStoryFoo(user_story.UserStory):
+  def __init__(self, name='', labels=None):
+    super(UserStoryFoo, self).__init__(
+        SharedStateBar, name, labels)
+
+
+class StorySetFoo(story.StorySet):
+  """ StorySetFoo is a story set created for testing purpose. """
+  pass
+
+
+class StorySetTest(unittest.TestCase):
+
+  def testStorySetTestName(self):
+    self.assertEquals('story_set_unittest', StorySetFoo.Name())
+
+  def testStorySetTestDescription(self):
+    self.assertEquals(
+        ' StorySetFoo is a story set created for testing purpose. ',
+        StorySetFoo.Description())
+
+  def testBaseDir(self):
+    story_set = StorySetFoo()
+    base_dir = story_set.base_dir
+    self.assertTrue(os.path.isdir(base_dir))
+    self.assertEqual(base_dir, os.path.dirname(__file__))
+
+  def testFilePath(self):
+    story_set = StorySetFoo()
+    self.assertEqual(os.path.abspath(__file__).replace('.pyc', '.py'),
+                     story_set.file_path)
+
+  def testCloudBucket(self):
+    blank_story_set = story.StorySet()
+    self.assertEqual(blank_story_set.bucket, None)
+
+    public_story_set = story.StorySet(
+        cloud_storage_bucket=story.PUBLIC_BUCKET)
+    self.assertEqual(public_story_set.bucket, story.PUBLIC_BUCKET)
+
+    partner_story_set = story.StorySet(
+        cloud_storage_bucket=story.PARTNER_BUCKET)
+    self.assertEqual(partner_story_set.bucket, story.PARTNER_BUCKET)
+
+    internal_story_set = story.StorySet(
+        cloud_storage_bucket=story.INTERNAL_BUCKET)
+    self.assertEqual(internal_story_set.bucket, story.INTERNAL_BUCKET)
+
+    with self.assertRaises(ValueError):
+      story.StorySet(cloud_storage_bucket='garbage_bucket')
+
+  def testRemoveWithEmptySetRaises(self):
+    story_set = story.StorySet()
+    foo_story = UserStoryFoo()
+    with self.assertRaises(ValueError):
+      story_set.RemoveUserStory(foo_story)
+
+  def testBasicAddRemove(self):
+    story_set = story.StorySet()
+    foo_story = UserStoryFoo()
+    story_set.AddUserStory(foo_story)
+    self.assertEqual([foo_story], story_set.user_stories)
+
+    story_set.RemoveUserStory(foo_story)
+    self.assertEqual([], story_set.user_stories)
diff --git a/tools/telemetry/telemetry/user_story/user_story_set_unittest.py b/tools/telemetry/telemetry/user_story/user_story_set_unittest.py
deleted file mode 100644
index 5647493c..0000000
--- a/tools/telemetry/telemetry/user_story/user_story_set_unittest.py
+++ /dev/null
@@ -1,83 +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 os
-import unittest
-
-from telemetry.story import shared_state
-from telemetry import user_story
-from telemetry.user_story import user_story_set
-from telemetry.util import cloud_storage
-
-
-# pylint: disable=abstract-method
-class SharedStateBar(shared_state.SharedState):
-  pass
-
-
-class UserStoryFoo(user_story.UserStory):
-  def __init__(self, name='', labels=None):
-    super(UserStoryFoo, self).__init__(
-        SharedStateBar, name, labels)
-
-
-class UserStorySetFoo(user_story_set.UserStorySet):
-  """ UserStorySetFoo is a user story created for testing purpose. """
-  pass
-
-
-class UserStorySetTest(unittest.TestCase):
-
-  def testUserStoryTestName(self):
-    self.assertEquals('user_story_set_unittest', UserStorySetFoo.Name())
-
-  def testUserStoryTestDescription(self):
-    self.assertEquals(
-        ' UserStorySetFoo is a user story created for testing purpose. ',
-        UserStorySetFoo.Description())
-
-  def testBaseDir(self):
-    uss = UserStorySetFoo()
-    base_dir = uss.base_dir
-    self.assertTrue(os.path.isdir(base_dir))
-    self.assertEqual(base_dir, os.path.dirname(__file__))
-
-  def testFilePath(self):
-    uss = UserStorySetFoo()
-    self.assertEqual(os.path.abspath(__file__).replace('.pyc', '.py'),
-                     uss.file_path)
-
-  def testCloudBucket(self):
-    blank_uss = user_story_set.UserStorySet()
-    self.assertEqual(blank_uss.bucket, None)
-
-    public_uss = user_story_set.UserStorySet(
-        cloud_storage_bucket=cloud_storage.PUBLIC_BUCKET)
-    self.assertEqual(public_uss.bucket, cloud_storage.PUBLIC_BUCKET)
-
-    partner_uss = user_story_set.UserStorySet(
-        cloud_storage_bucket=cloud_storage.PARTNER_BUCKET)
-    self.assertEqual(partner_uss.bucket, cloud_storage.PARTNER_BUCKET)
-
-    internal_uss = user_story_set.UserStorySet(
-        cloud_storage_bucket=cloud_storage.INTERNAL_BUCKET)
-    self.assertEqual(internal_uss.bucket, cloud_storage.INTERNAL_BUCKET)
-
-    with self.assertRaises(ValueError):
-      user_story_set.UserStorySet(cloud_storage_bucket='garbage_bucket')
-
-  def testRemoveWithEmptySetRaises(self):
-    uss = user_story_set.UserStorySet()
-    foo_story = UserStoryFoo()
-    with self.assertRaises(ValueError):
-      uss.RemoveUserStory(foo_story)
-
-  def testBasicAddRemove(self):
-    uss = user_story_set.UserStorySet()
-    foo_story = UserStoryFoo()
-    uss.AddUserStory(foo_story)
-    self.assertEqual([foo_story], uss.user_stories)
-
-    uss.RemoveUserStory(foo_story)
-    self.assertEqual([], uss.user_stories)
diff --git a/tools/telemetry/telemetry/value/failure.py b/tools/telemetry/telemetry/value/failure.py
index cd614e70f..027672d 100644
--- a/tools/telemetry/telemetry/value/failure.py
+++ b/tools/telemetry/telemetry/value/failure.py
@@ -43,7 +43,7 @@
 
   def __repr__(self):
     if self.page:
-      page_name = self.page.url
+      page_name = self.page.name
     else:
       page_name = None
     return 'FailureValue(%s, %s)' % (
diff --git a/tools/telemetry/telemetry/value/histogram.py b/tools/telemetry/telemetry/value/histogram.py
index a662b2f..64766c8 100644
--- a/tools/telemetry/telemetry/value/histogram.py
+++ b/tools/telemetry/telemetry/value/histogram.py
@@ -48,7 +48,7 @@
 
   def __repr__(self):
     if self.page:
-      page_name = self.page.url
+      page_name = self.page.name
     else:
       page_name = None
     return ('HistogramValue(%s, %s, %s, raw_json_string="%s", '
diff --git a/tools/telemetry/telemetry/value/list_of_scalar_values.py b/tools/telemetry/telemetry/value/list_of_scalar_values.py
index bcbe0ba7..e061c0ff 100644
--- a/tools/telemetry/telemetry/value/list_of_scalar_values.py
+++ b/tools/telemetry/telemetry/value/list_of_scalar_values.py
@@ -30,7 +30,7 @@
 
   def __repr__(self):
     if self.page:
-      page_name = self.page.url
+      page_name = self.page.name
     else:
       page_name = None
     if self.same_page_merge_policy == value_module.CONCATENATE:
diff --git a/tools/telemetry/telemetry/value/list_of_string_values.py b/tools/telemetry/telemetry/value/list_of_string_values.py
index b5e61c5..929e449c 100644
--- a/tools/telemetry/telemetry/value/list_of_string_values.py
+++ b/tools/telemetry/telemetry/value/list_of_string_values.py
@@ -24,7 +24,7 @@
 
   def __repr__(self):
     if self.page:
-      page_name = self.page.url
+      page_name = self.page.name
     else:
       page_name = None
     if self.same_page_merge_policy == value_module.CONCATENATE:
diff --git a/tools/telemetry/telemetry/value/scalar.py b/tools/telemetry/telemetry/value/scalar.py
index a622856..8cabfa8 100644
--- a/tools/telemetry/telemetry/value/scalar.py
+++ b/tools/telemetry/telemetry/value/scalar.py
@@ -28,7 +28,7 @@
 
   def __repr__(self):
     if self.page:
-      page_name = self.page.url
+      page_name = self.page.name
     else:
       page_name = None
     return ('ScalarValue(%s, %s, %s, %s, important=%s, description=%s, '
diff --git a/tools/telemetry/telemetry/value/skip.py b/tools/telemetry/telemetry/value/skip.py
index 326c768..4f418e9 100644
--- a/tools/telemetry/telemetry/value/skip.py
+++ b/tools/telemetry/telemetry/value/skip.py
@@ -18,7 +18,7 @@
     self._reason = reason
 
   def __repr__(self):
-    page_name = self.page.url
+    page_name = self.page.name
     return 'SkipValue(%s, %s)' % (page_name, self._reason)
 
   @property
diff --git a/tools/telemetry/telemetry/value/string.py b/tools/telemetry/telemetry/value/string.py
index 091dd99..8568dd40 100644
--- a/tools/telemetry/telemetry/value/string.py
+++ b/tools/telemetry/telemetry/value/string.py
@@ -26,7 +26,7 @@
 
   def __repr__(self):
     if self.page:
-      page_name = self.page.url
+      page_name = self.page.name
     else:
       page_name = None
     return ('StringValue(%s, %s, %s, %s, important=%s, description=%s, '
diff --git a/tools/telemetry/telemetry/value/trace.py b/tools/telemetry/telemetry/value/trace.py
index a31be2c..c522f9c6 100644
--- a/tools/telemetry/telemetry/value/trace.py
+++ b/tools/telemetry/telemetry/value/trace.py
@@ -56,7 +56,7 @@
 
   def __repr__(self):
     if self.page:
-      page_name = self.page.url
+      page_name = self.page.name
     else:
       page_name = None
     return 'TraceValue(%s, %s)' % (page_name, self.name)
diff --git a/tools/telemetry/telemetry/wpr/archive_info.py b/tools/telemetry/telemetry/wpr/archive_info.py
index e7a8bb43..9abce276 100644
--- a/tools/telemetry/telemetry/wpr/archive_info.py
+++ b/tools/telemetry/telemetry/wpr/archive_info.py
@@ -73,7 +73,7 @@
     """
     # Download all .wpr files.
     if not self._bucket:
-      logging.warning('User story set in %s has no bucket specified, and '
+      logging.warning('Story set in %s has no bucket specified, and '
                       'cannot be downloaded from cloud_storage.', )
       return
     assert 'archives' in self._data, 'Invalid data format in %s. \'archives\'' \
@@ -137,7 +137,7 @@
     # Upload to cloud storage
     if upload_to_cloud_storage:
       if not self._bucket:
-        logging.warning('UserStorySet must have bucket specified to upload '
+        logging.warning('StorySet must have bucket specified to upload '
                         'user stories to cloud storage.')
         return
       try:
@@ -172,7 +172,7 @@
     """Writes the metadata into the file passed as constructor parameter."""
     metadata = dict()
     metadata['description'] = (
-        'Describes the Web Page Replay archives for a user story set. '
+        'Describes the Web Page Replay archives for a story set. '
         'Don\'t edit by hand! Use record_wpr for updating.')
     metadata['archives'] = self._wpr_file_to_user_story_names.copy()
     # Don't write data for abandoned archives.
@@ -203,7 +203,7 @@
       base = match.groupdict()['BASE']
     if not base:
       # If we're creating a completely new info file, use the base name of the
-      # user story set file.
+      # story set file.
       base = os.path.splitext(os.path.basename(self._file_path))[0]
     new_filename = '%s_%03d.wpr' % (base, highest_number + 1)
     return new_filename, self._WprFileNameToPath(new_filename)
diff --git a/tools/telemetry/telemetry/wpr/archive_info_unittest.py b/tools/telemetry/telemetry/wpr/archive_info_unittest.py
index 29e61a8..97f8768 100644
--- a/tools/telemetry/telemetry/wpr/archive_info_unittest.py
+++ b/tools/telemetry/telemetry/wpr/archive_info_unittest.py
@@ -38,9 +38,9 @@
   def setUp(self):
     self.tmp_dir = tempfile.mkdtemp()
     # Write the metadata.
-    self.user_story_set_archive_info_file = os.path.join(
+    self.story_set_archive_info_file = os.path.join(
         self.tmp_dir, 'info.json')
-    with open(self.user_story_set_archive_info_file, 'w') as f:
+    with open(self.story_set_archive_info_file, 'w') as f:
       f.write(archive_info_contents)
 
     # Write the existing .wpr files.
@@ -50,7 +50,7 @@
 
     # Create the PageSetArchiveInfo object to be tested.
     self.archive_info = archive_info.WprArchiveInfo.FromFile(
-        self.user_story_set_archive_info_file, cloud_storage.PUBLIC_BUCKET)
+        self.story_set_archive_info_file, cloud_storage.PUBLIC_BUCKET)
     # Use cloud_storage system stub.
     self.overrides = system_stub.Override(archive_info, ['cloud_storage'])
 
@@ -98,7 +98,7 @@
     """Ensures that the archive info file is updated correctly."""
 
     expected_archive_file_contents = {
-        u'description': (u'Describes the Web Page Replay archives for a user'
+        u'description': (u'Describes the Web Page Replay archives for a'
                          u' story set. Don\'t edit by hand! Use record_wpr for'
                          u' updating.'),
         u'archives': {
@@ -117,7 +117,7 @@
     self.archive_info.AddNewTemporaryRecording(new_temp_recording)
     self.archive_info.AddRecordedUserStories([page2, page3])
 
-    with open(self.user_story_set_archive_info_file, 'r') as f:
+    with open(self.story_set_archive_info_file, 'r') as f:
       archive_file_contents = json.load(f)
       self.assertEquals(expected_archive_file_contents, archive_file_contents)
 
@@ -170,7 +170,7 @@
 
   def testCreatingNewArchiveInfo(self):
     # Write only the page set without the corresponding metadata file.
-    user_story_set_contents = ("""
+    story_set_contents = ("""
     {
         archive_data_file": "new_archive_info.json",
         "pages": [
@@ -180,11 +180,11 @@
         ]
     }""" % page1.url)
 
-    user_story_set_file = os.path.join(self.tmp_dir, 'new_user_story_set.json')
-    with open(user_story_set_file, 'w') as f:
-      f.write(user_story_set_contents)
+    story_set_file = os.path.join(self.tmp_dir, 'new_story_set.json')
+    with open(story_set_file, 'w') as f:
+      f.write(story_set_contents)
 
-    self.user_story_set_archive_info_file = os.path.join(self.tmp_dir,
+    self.story_set_archive_info_file = os.path.join(self.tmp_dir,
                                                    'new_archive_info.json')
 
     expected_archive_file_path = os.path.join(self.tmp_dir,
@@ -194,7 +194,7 @@
 
     # Create the WprArchiveInfo object to be tested.
     self.archive_info = archive_info.WprArchiveInfo.FromFile(
-        self.user_story_set_archive_info_file, cloud_storage.PUBLIC_BUCKET)
+        self.story_set_archive_info_file, cloud_storage.PUBLIC_BUCKET)
 
     # Add a recording for all the pages.
     new_temp_recording = os.path.join(self.tmp_dir, 'recording.wpr')
@@ -216,8 +216,8 @@
     self.assertCorrectHashFile(new_recording)
 
     # Check that the archive info was written correctly.
-    self.assertTrue(os.path.exists(self.user_story_set_archive_info_file))
+    self.assertTrue(os.path.exists(self.story_set_archive_info_file))
     read_archive_info = archive_info.WprArchiveInfo.FromFile(
-        self.user_story_set_archive_info_file, cloud_storage.PUBLIC_BUCKET)
+        self.story_set_archive_info_file, cloud_storage.PUBLIC_BUCKET)
     self.assertEquals(new_recording,
                       read_archive_info.WprFilePathForUserStory(page1))
diff --git a/tools/telemetry/third_party/WebKit/LICENSE b/tools/telemetry/third_party/WebKit/LICENSE
new file mode 100644
index 0000000..70bcb8a
--- /dev/null
+++ b/tools/telemetry/third_party/WebKit/LICENSE
@@ -0,0 +1,30 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+//
+// The Chromium Authors can be found at
+// http://src.chromium.org/svn/trunk/src/AUTHORS
+//
+// 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.
diff --git a/tools/telemetry/third_party/WebKit/PerformanceTests/resources/jquery.tablesorter.min.js b/tools/telemetry/third_party/WebKit/PerformanceTests/resources/jquery.tablesorter.min.js
new file mode 100644
index 0000000..19d7359
--- /dev/null
+++ b/tools/telemetry/third_party/WebKit/PerformanceTests/resources/jquery.tablesorter.min.js
@@ -0,0 +1,4 @@
+
+(function($){$.extend({tablesorter:new
+function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",cssChildRow:"expand-child",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,sortLocaleCompare:true,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'/\.|\,/g',onRenderHeader:null,selectorHeaders:'thead th',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}if(table.tBodies.length==0)return;var rows=table.tBodies[0].rows;if(rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i<l;i++){var p=false;if($.metadata&&($($headers[i]).metadata()&&$($headers[i]).metadata().sorter)){p=getParserById($($headers[i]).metadata().sorter);}else if((table.config.headers[i]&&table.config.headers[i].sorter)){p=getParserById(table.config.headers[i].sorter);}if(!p){p=detectParserForColumn(table,rows,-1,i);}if(table.config.debug){parsersDebug+="column:"+i+" parser:"+p.id+"\n";}list.push(p);}}if(table.config.debug){log(parsersDebug);}return list;};function detectParserForColumn(table,rows,rowIndex,cellIndex){var l=parsers.length,node=false,nodeValue=false,keepLooking=true;while(nodeValue==''&&keepLooking){rowIndex++;if(rows[rowIndex]){node=getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex);nodeValue=trimAndGetNodeText(table.config,node);if(table.config.debug){log('Checking if value was empty on row:'+rowIndex);}}else{keepLooking=false;}}for(var i=1;i<l;i++){if(parsers[i].is(nodeValue,table,node)){return parsers[i];}}return parsers[0];}function getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex){return rows[rowIndex].cells[cellIndex];}function trimAndGetNodeText(config,node){return $.trim(getElementText(config,node));}function getParserById(name){var l=parsers.length;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==name.toLowerCase()){return parsers[i];}}return false;}function buildCache(table){if(table.config.debug){var cacheTime=new Date();}var totalRows=(table.tBodies[0]&&table.tBodies[0].rows.length)||0,totalCells=(table.tBodies[0].rows[0]&&table.tBodies[0].rows[0].cells.length)||0,parsers=table.config.parsers,cache={row:[],normalized:[]};for(var i=0;i<totalRows;++i){var c=$(table.tBodies[0].rows[i]),cols=[];if(c.hasClass(table.config.cssChildRow)){cache.row[cache.row.length-1]=cache.row[cache.row.length-1].add(c);continue;}cache.row.push(c);for(var j=0;j<totalCells;++j){cols.push(parsers[j].format(getElementText(table.config,c[0].cells[j]),table,c[0].cells[j]));}cols.push(cache.normalized.length);cache.normalized.push(cols);cols=null;};if(table.config.debug){benchmark("Building cache for "+totalRows+" rows:",cacheTime);}return cache;};function getElementText(config,node){var text="";if(!node)return"";if(!config.supportsTextContent)config.supportsTextContent=node.textContent||false;if(config.textExtraction=="simple"){if(config.supportsTextContent){text=node.textContent;}else{if(node.childNodes[0]&&node.childNodes[0].hasChildNodes()){text=node.childNodes[0].innerHTML;}else{text=node.innerHTML;}}}else{if(typeof(config.textExtraction)=="function"){text=config.textExtraction(node);}else{text=$(node).text();}}return text;}function appendToTable(table,cache){if(table.config.debug){var appendTime=new Date()}var c=cache,r=c.row,n=c.normalized,totalRows=n.length,checkCell=(n[0].length-1),tableBody=$(table.tBodies[0]),rows=[];for(var i=0;i<totalRows;i++){var pos=n[i][checkCell];rows.push(r[pos]);if(!table.config.appender){var l=r[pos].length;for(var j=0;j<l;j++){tableBody[0].appendChild(r[pos][j]);}}}if(table.config.appender){table.config.appender(table,rows);}rows=null;if(table.config.debug){benchmark("Rebuilt table:",appendTime);}applyWidget(table);setTimeout(function(){$(table).trigger("sortEnd");},0);};function buildHeaders(table){if(table.config.debug){var time=new Date();}var meta=($.metadata)?true:false;var header_index=computeTableHeaderCellIndexes(table);$tableHeaders=$(table.config.selectorHeaders,table).each(function(index){this.column=header_index[this.parentNode.rowIndex+"-"+this.cellIndex];this.order=formatSortingOrder(table.config.sortInitialOrder);this.count=this.order;if(checkHeaderMetadata(this)||checkHeaderOptions(table,index))this.sortDisabled=true;if(checkHeaderOptionsSortingLocked(table,index))this.order=this.lockedOrder=checkHeaderOptionsSortingLocked(table,index);if(!this.sortDisabled){var $th=$(this).addClass(table.config.cssHeader);if(table.config.onRenderHeader)table.config.onRenderHeader.apply($th);}table.config.headerList[index]=this;});if(table.config.debug){benchmark("Built headers:",time);log($tableHeaders);}return $tableHeaders;};function computeTableHeaderCellIndexes(t){var matrix=[];var lookup={};var thead=t.getElementsByTagName('THEAD')[0];var trs=thead.getElementsByTagName('TR');for(var i=0;i<trs.length;i++){var cells=trs[i].cells;for(var j=0;j<cells.length;j++){var c=cells[j];var rowIndex=c.parentNode.rowIndex;var cellId=rowIndex+"-"+c.cellIndex;var rowSpan=c.rowSpan||1;var colSpan=c.colSpan||1
+var firstAvailCol;if(typeof(matrix[rowIndex])=="undefined"){matrix[rowIndex]=[];}for(var k=0;k<matrix[rowIndex].length+1;k++){if(typeof(matrix[rowIndex][k])=="undefined"){firstAvailCol=k;break;}}lookup[cellId]=firstAvailCol;for(var k=rowIndex;k<rowIndex+rowSpan;k++){if(typeof(matrix[k])=="undefined"){matrix[k]=[];}var matrixrow=matrix[k];for(var l=firstAvailCol;l<firstAvailCol+colSpan;l++){matrixrow[l]="x";}}}}return lookup;}function checkCellColSpan(table,rows,row){var arr=[],r=table.tHead.rows,c=r[row].cells;for(var i=0;i<c.length;i++){var cell=c[i];if(cell.colSpan>1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function checkHeaderOptionsSortingLocked(table,i){if((table.config.headers[i])&&(table.config.headers[i].lockedOrder))return table.config.headers[i].lockedOrder;return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i<l;i++){getWidgetById(c[i]).format(table);}}function getWidgetById(name){var l=widgets.length;for(var i=0;i<l;i++){if(widgets[i].id.toLowerCase()==name.toLowerCase()){return widgets[i];}}};function formatSortingOrder(v){if(typeof(v)!="Number"){return(v.toLowerCase()=="desc")?1:0;}else{return(v==1)?1:0;}}function isValueInArray(v,a){var l=a.length;for(var i=0;i<l;i++){if(a[i][0]==v){return true;}}return false;}function setHeadersCss(table,$headers,list,css){$headers.removeClass(css[0]).removeClass(css[1]);var h=[];$headers.each(function(offset){if(!this.sortDisabled){h[this.column]=$(this);}});var l=list.length;for(var i=0;i<l;i++){h[list[i][0]].addClass(css[list[i][1]]);}}function fixColumnWidth(table,$headers){var c=table.config;if(c.widthFixed){var colgroup=$('<colgroup>');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('<col>').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i<l;i++){var s=sortList[i],o=c.headerList[s[0]];o.count=s[1];o.count++;}}function multisort(table,sortList,cache){if(table.config.debug){var sortTime=new Date();}var dynamicExp="var sortWrapper = function(a,b) {",l=sortList.length;for(var i=0;i<l;i++){var c=sortList[i][0];var order=sortList[i][1];var s=(table.config.parsers[c].type=="text")?((order==0)?makeSortFunction("text","asc",c):makeSortFunction("text","desc",c)):((order==0)?makeSortFunction("numeric","asc",c):makeSortFunction("numeric","desc",c));var e="e"+i;dynamicExp+="var "+e+" = "+s;dynamicExp+="if("+e+") { return "+e+"; } ";dynamicExp+="else { ";}var orgOrderCol=cache.normalized[0].length-1;dynamicExp+="return a["+orgOrderCol+"]-b["+orgOrderCol+"];";for(var i=0;i<l;i++){dynamicExp+="}; ";}dynamicExp+="return 0; ";dynamicExp+="}; ";if(table.config.debug){benchmark("Evaling expression:"+dynamicExp,new Date());}eval(dynamicExp);cache.normalized.sort(sortWrapper);if(table.config.debug){benchmark("Sorting on "+sortList.toString()+" and dir "+order+" time:",sortTime);}return cache;};function makeSortFunction(type,direction,index){var a="a["+index+"]",b="b["+index+"]";if(type=='text'&&direction=='asc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+a+" < "+b+") ? -1 : 1 )));";}else if(type=='text'&&direction=='desc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+b+" < "+a+") ? -1 : 1 )));";}else if(type=='numeric'&&direction=='asc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+a+" - "+b+"));";}else if(type=='numeric'&&direction=='desc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+b+" - "+a+"));";}};function makeSortText(i){return"((a["+i+"] < b["+i+"]) ? -1 : ((a["+i+"] > b["+i+"]) ? 1 : 0));";};function makeSortTextDesc(i){return"((b["+i+"] < a["+i+"]) ? -1 : ((b["+i+"] > a["+i+"]) ? 1 : 0));";};function makeSortNumeric(i){return"a["+i+"]-b["+i+"];";};function makeSortNumericDesc(i){return"b["+i+"]-a["+i+"];";};function sortText(a,b){if(table.config.sortLocaleCompare)return a.localeCompare(b);return((a<b)?-1:((a>b)?1:0));};function sortTextDesc(a,b){if(table.config.sortLocaleCompare)return b.localeCompare(a);return((b<a)?-1:((b>a)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$.data(this,"tablesorter",config);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){$this.trigger("sortStart");var $cell=$(this);var i=this.column;this.order=this.count++%2;if(this.lockedOrder)this.order=this.lockedOrder;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j<a.length;j++){if(a[j][0]!=i){config.sortList.push(a[j]);}}}config.sortList.push([i,this.order]);}else{if(isValueInArray(i,config.sortList)){for(var j=0;j<config.sortList.length;j++){var s=config.sortList[j],o=config.headerList[s[0]];if(s[0]==i){o.count=s[1];o.count++;s[1]=o.count%2;}}}else{config.sortList.push([i,this.order]);}};setTimeout(function(){setHeadersCss($this[0],$headers,config.sortList,sortCSS);appendToTable($this[0],multisort($this[0],config.sortList,cache));},1);return false;}}).mousedown(function(){if(config.cancelSelection){this.onselectstart=function(){return false};return false;}});$this.bind("update",function(){var me=this;setTimeout(function(){me.config.parsers=buildParserCache(me,$headers);cache=buildCache(me);},1);}).bind("updateCell",function(e,cell){var config=this.config;var pos=[(cell.parentNode.rowIndex-1),cell.cellIndex];cache.normalized[pos[0]][pos[1]]=config.parsers[pos[1]].format(getElementText(config,cell),cell);}).bind("sorton",function(e,list){$(this).trigger("sortStart");config.sortList=list;var sortList=config.sortList;updateHeaderSortCount(this,sortList);setHeadersCss(this,$headers,sortList,sortCSS);appendToTable(this,multisort(this,sortList,cache));}).bind("appendCache",function(){appendToTable(this,cache);}).bind("applyWidgetId",function(e,id){getWidgetById(id).format(this);}).bind("applyWidgets",function(){applyWidget(this);});if($.metadata&&($(this).metadata()&&$(this).metadata().sortlist)){config.sortList=$(this).metadata().sortlist;}if(config.sortList.length>0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==parser.id.toLowerCase()){a=false;}}if(a){parsers.push(parser);};};this.addWidget=function(widget){widgets.push(widget);};this.formatFloat=function(s){var i=parseFloat(s);return(isNaN(i))?0:i;};this.formatInt=function(s){var i=parseInt(s);return(isNaN(i))?0:i;};this.isDigit=function(s,config){return/^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g,'')));};this.clearTableBody=function(table){if($.browser.msie){function empty(){while(this.firstChild)this.removeChild(this.firstChild);}empty.apply(table.tBodies[0]);}else{table.tBodies[0].innerHTML="";}};}});$.fn.extend({tablesorter:$.tablesorter.construct});var ts=$.tablesorter;ts.addParser({id:"text",is:function(s){return true;},format:function(s){return $.trim(s.toLocaleLowerCase());},type:"text"});ts.addParser({id:"digit",is:function(s,table){var c=table.config;return $.tablesorter.isDigit(s,c);},format:function(s){return $.tablesorter.formatFloat(s);},type:"numeric"});ts.addParser({id:"currency",is:function(s){return/^[£$€?.]/.test(s);},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g),""));},type:"numeric"});ts.addParser({id:"ipAddress",is:function(s){return/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);},format:function(s){var a=s.split("."),r="",l=a.length;for(var i=0;i<l;i++){var item=a[i];if(item.length==2){r+="0"+item;}else{r+=item;}}return $.tablesorter.formatFloat(r);},type:"numeric"});ts.addParser({id:"url",is:function(s){return/^(https?|ftp|file):\/\/$/.test(s);},format:function(s){return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));},type:"text"});ts.addParser({id:"isoDate",is:function(s){return/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);},format:function(s){return $.tablesorter.formatFloat((s!="")?new Date(s.replace(new RegExp(/-/g),"/")).getTime():"0");},type:"numeric"});ts.addParser({id:"percent",is:function(s){return/\%$/.test($.trim(s));},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));},type:"numeric"});ts.addParser({id:"usLongDate",is:function(s){return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));},format:function(s){return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"shortDate",is:function(s){return/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);},format:function(s,table){var c=table.config;s=s.replace(/\-/g,"/");if(c.dateFormat=="us"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$1/$2");}else if(c.dateFormat=="uk"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$2/$1");}else if(c.dateFormat=="dd/mm/yy"||c.dateFormat=="dd-mm-yy"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/,"$1/$2/$3");}return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"time",is:function(s){return/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);},format:function(s){return $.tablesorter.formatFloat(new Date("2000/01/01 "+s).getTime());},type:"numeric"});ts.addParser({id:"metadata",is:function(s){return false;},format:function(s,table,cell){var c=table.config,p=(!c.parserMetadataName)?'sortValue':c.parserMetadataName;return $(cell).metadata()[p];},type:"numeric"});ts.addWidget({id:"zebra",format:function(table){if(table.config.debug){var time=new Date();}var $tr,row=-1,odd;$("tr:visible",table.tBodies[0]).each(function(i){$tr=$(this);if(!$tr.hasClass(table.config.cssChildRow))row++;odd=(row%2==0);$tr.removeClass(table.config.widgetZebra.css[odd?0:1]).addClass(table.config.widgetZebra.css[odd?1:0])});if(table.config.debug){$.tablesorter.benchmark("Applying Zebra widget",time);}}});})(jQuery);
diff --git a/tools/telemetry/third_party/WebKit/PerformanceTests/resources/statistics.js b/tools/telemetry/third_party/WebKit/PerformanceTests/resources/statistics.js
new file mode 100644
index 0000000..f5269c2
--- /dev/null
+++ b/tools/telemetry/third_party/WebKit/PerformanceTests/resources/statistics.js
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2012, 2013 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+var Statistics = new (function () {
+
+    this.max = function (values) {
+        var maxVal = values[0];
+        for (var i = 1; i < values.length; i++) {
+            maxVal = Math.max(maxVal, values[i]);
+        }
+        return maxVal;
+    }
+
+    this.min = function (values) {
+        var minVal = values[0];
+        for (var i = 1; i < values.length; i++) {
+            minVal = Math.min(minVal, values[i]);
+        }
+        return minVal;
+    }
+
+    this.sum = function (values) {
+        return values.reduce(function (a, b) { return a + b; }, 0);
+    }
+
+    this.squareSum = function (values) {
+        return values.reduce(function (sum, value) { return sum + value * value;}, 0);
+    }
+
+    // With sum and sum of squares, we can compute the sample standard deviation in O(1).
+    // See https://rniwa.com/2012-11-10/sample-standard-deviation-in-terms-of-sum-and-square-sum-of-samples/
+    this.sampleStandardDeviation = function (numberOfSamples, sum, squareSum) {
+        if (numberOfSamples < 2)
+            return 0;
+        return Math.sqrt(squareSum / (numberOfSamples - 1)
+            - sum * sum / (numberOfSamples - 1) / numberOfSamples);
+    }
+
+    this.supportedConfidenceLevels = function () {
+        var supportedLevels = [];
+        for (var quantile in tDistributionInverseCDF)
+            supportedLevels.push((1 - (1 - quantile) * 2).toFixed(2));
+        return supportedLevels;
+    }
+
+    // Computes the delta d s.t. (mean - d, mean + d) is the confidence interval with the specified confidence level in O(1).
+    this.confidenceIntervalDelta = function (confidenceLevel, numberOfSamples, sum, squareSum) {
+        var probability = (1 - (1 - confidenceLevel) / 2);
+        if (!(probability in tDistributionInverseCDF)) {
+            console.warn('We only support ' + this.supportedConfidenceLevels().map(
+                function (level) { return level * 100 + '%'; } ).join(', ') + ' confidence intervals.');
+            return NaN;
+        }
+        if (numberOfSamples < 2)
+            return Number.POSITIVE_INFINITY;
+
+        var cdfForProbability = tDistributionInverseCDF[probability];
+        var degreesOfFreedom = numberOfSamples - 1;
+
+        // tDistributionQuantile(degreesOfFreedom, confidenceLevel) * sampleStandardDeviation / sqrt(numberOfSamples) * S/sqrt(numberOfSamples)
+        if (degreesOfFreedom <= 100)
+          var quantile = cdfForProbability[degreesOfFreedom - 1]; // The first entry is for the one degree of freedom.
+        else if (degreesOfFreedom <= 300)
+          var quantile = cdfForProbability[Math.round(degreesOfFreedom / 10) + 100 - 10 - 1];
+        else if (degreesOfFreedom <= 1300)
+          var quantile = cdfForProbability[Math.round(degreesOfFreedom / 100) + 120 - 3 - 1];
+        else
+          var quantile = cdfForProbability[cdfForProbability.length - 1];
+        return quantile * this.sampleStandardDeviation(numberOfSamples, sum, squareSum) / Math.sqrt(numberOfSamples);
+    }
+
+    this.confidenceInterval = function (values, probability) {
+        var sum = this.sum(values);
+        var mean = sum / values.length;
+        var delta = this.confidenceIntervalDelta(probability || 0.95, values.length, sum, this.squareSum(values));
+        return [mean - delta, mean + delta];
+    }
+
+    // See http://en.wikipedia.org/wiki/Student's_t-distribution#Table_of_selected_values
+    // This table contains one sided (a.k.a. tail) values.
+    // Use TINV((1 - probability) * 2, df) in your favorite spreadsheet software to compute these.
+    // The spacing of the values with df greater than 100 maintains error less than 0.8%.
+    var tDistributionInverseCDF = {
+        0.9: [
+            // 1 - 100 step 1
+            3.077684, 1.885618, 1.637744, 1.533206, 1.475884, 1.439756, 1.414924, 1.396815, 1.383029, 1.372184,
+            1.363430, 1.356217, 1.350171, 1.345030, 1.340606, 1.336757, 1.333379, 1.330391, 1.327728, 1.325341,
+            1.323188, 1.321237, 1.319460, 1.317836, 1.316345, 1.314972, 1.313703, 1.312527, 1.311434, 1.310415,
+            1.309464, 1.308573, 1.307737, 1.306952, 1.306212, 1.305514, 1.304854, 1.304230, 1.303639, 1.303077,
+            1.302543, 1.302035, 1.301552, 1.301090, 1.300649, 1.300228, 1.299825, 1.299439, 1.299069, 1.298714,
+            1.298373, 1.298045, 1.297730, 1.297426, 1.297134, 1.296853, 1.296581, 1.296319, 1.296066, 1.295821,
+            1.295585, 1.295356, 1.295134, 1.294920, 1.294712, 1.294511, 1.294315, 1.294126, 1.293942, 1.293763,
+            1.293589, 1.293421, 1.293256, 1.293097, 1.292941, 1.292790, 1.292643, 1.292500, 1.292360, 1.292224,
+            1.292091, 1.291961, 1.291835, 1.291711, 1.291591, 1.291473, 1.291358, 1.291246, 1.291136, 1.291029,
+            1.290924, 1.290821, 1.290721, 1.290623, 1.290527, 1.290432, 1.290340, 1.290250, 1.290161, 1.290075,
+            // 110 - 300 step 10
+            1.289295, 1.288646, 1.288098, 1.287628, 1.287221, 1.286865, 1.286551, 1.286272, 1.286023, 1.285799,
+            1.285596, 1.285411, 1.285243, 1.285089, 1.284947, 1.284816, 1.284695, 1.284582, 1.284478, 1.284380,
+            // 400 - 1300 step 100
+            1.283672, 1.283247, 1.282964, 1.282762, 1.282611, 1.282493, 1.282399, 1.282322, 1.282257, 1.282203,
+            // Infinity
+            1.281548],
+        0.95: [
+            // 1 - 100 step 1
+            6.313752, 2.919986, 2.353363, 2.131847, 2.015048, 1.943180, 1.894579, 1.859548, 1.833113, 1.812461,
+            1.795885, 1.782288, 1.770933, 1.761310, 1.753050, 1.745884, 1.739607, 1.734064, 1.729133, 1.724718,
+            1.720743, 1.717144, 1.713872, 1.710882, 1.708141, 1.705618, 1.703288, 1.701131, 1.699127, 1.697261,
+            1.695519, 1.693889, 1.692360, 1.690924, 1.689572, 1.688298, 1.687094, 1.685954, 1.684875, 1.683851,
+            1.682878, 1.681952, 1.681071, 1.680230, 1.679427, 1.678660, 1.677927, 1.677224, 1.676551, 1.675905,
+            1.675285, 1.674689, 1.674116, 1.673565, 1.673034, 1.672522, 1.672029, 1.671553, 1.671093, 1.670649,
+            1.670219, 1.669804, 1.669402, 1.669013, 1.668636, 1.668271, 1.667916, 1.667572, 1.667239, 1.666914,
+            1.666600, 1.666294, 1.665996, 1.665707, 1.665425, 1.665151, 1.664885, 1.664625, 1.664371, 1.664125,
+            1.663884, 1.663649, 1.663420, 1.663197, 1.662978, 1.662765, 1.662557, 1.662354, 1.662155, 1.661961,
+            1.661771, 1.661585, 1.661404, 1.661226, 1.661052, 1.660881, 1.660715, 1.660551, 1.660391, 1.660234,
+            // 110 - 300 step 10
+            1.658824, 1.657651, 1.656659, 1.655811, 1.655076, 1.654433, 1.653866, 1.653363, 1.652913, 1.652508,
+            1.652142, 1.651809, 1.651506, 1.651227, 1.650971, 1.650735, 1.650517, 1.650314, 1.650125, 1.649949,
+            // 400 - 1300 step 100
+            1.648672, 1.647907, 1.647397, 1.647033, 1.646761, 1.646548, 1.646379, 1.646240, 1.646124, 1.646027,
+            // Infinity
+            1.644847],
+        0.975: [
+            // 1 - 100 step 1
+            12.706205, 4.302653, 3.182446, 2.776445, 2.570582, 2.446912, 2.364624, 2.306004, 2.262157, 2.228139,
+            2.200985, 2.178813, 2.160369, 2.144787, 2.131450, 2.119905, 2.109816, 2.100922, 2.093024, 2.085963,
+            2.079614, 2.073873, 2.068658, 2.063899, 2.059539, 2.055529, 2.051831, 2.048407, 2.045230, 2.042272,
+            2.039513, 2.036933, 2.034515, 2.032245, 2.030108, 2.028094, 2.026192, 2.024394, 2.022691, 2.021075,
+            2.019541, 2.018082, 2.016692, 2.015368, 2.014103, 2.012896, 2.011741, 2.010635, 2.009575, 2.008559,
+            2.007584, 2.006647, 2.005746, 2.004879, 2.004045, 2.003241, 2.002465, 2.001717, 2.000995, 2.000298,
+            1.999624, 1.998972, 1.998341, 1.997730, 1.997138, 1.996564, 1.996008, 1.995469, 1.994945, 1.994437,
+            1.993943, 1.993464, 1.992997, 1.992543, 1.992102, 1.991673, 1.991254, 1.990847, 1.990450, 1.990063,
+            1.989686, 1.989319, 1.988960, 1.988610, 1.988268, 1.987934, 1.987608, 1.987290, 1.986979, 1.986675,
+            1.986377, 1.986086, 1.985802, 1.985523, 1.985251, 1.984984, 1.984723, 1.984467, 1.984217, 1.983972,
+            // 110 - 300 step 10
+            1.981765, 1.979930, 1.978380, 1.977054, 1.975905, 1.974902, 1.974017, 1.973231, 1.972528, 1.971896,
+            1.971325, 1.970806, 1.970332, 1.969898, 1.969498, 1.969130, 1.968789, 1.968472, 1.968178, 1.967903,
+            // 400 - 1300 step 100
+            1.965912, 1.964720, 1.963926, 1.963359, 1.962934, 1.962603, 1.962339, 1.962123, 1.961943, 1.961790,
+            // Infinity
+            1.959964],
+        0.99: [
+            // 1 - 100 step 1
+            31.820516, 6.964557, 4.540703, 3.746947, 3.364930, 3.142668, 2.997952, 2.896459, 2.821438, 2.763769,
+            2.718079, 2.680998, 2.650309, 2.624494, 2.602480, 2.583487, 2.566934, 2.552380, 2.539483, 2.527977,
+            2.517648, 2.508325, 2.499867, 2.492159, 2.485107, 2.478630, 2.472660, 2.467140, 2.462021, 2.457262,
+            2.452824, 2.448678, 2.444794, 2.441150, 2.437723, 2.434494, 2.431447, 2.428568, 2.425841, 2.423257,
+            2.420803, 2.418470, 2.416250, 2.414134, 2.412116, 2.410188, 2.408345, 2.406581, 2.404892, 2.403272,
+            2.401718, 2.400225, 2.398790, 2.397410, 2.396081, 2.394801, 2.393568, 2.392377, 2.391229, 2.390119,
+            2.389047, 2.388011, 2.387008, 2.386037, 2.385097, 2.384186, 2.383302, 2.382446, 2.381615, 2.380807,
+            2.380024, 2.379262, 2.378522, 2.377802, 2.377102, 2.376420, 2.375757, 2.375111, 2.374482, 2.373868,
+            2.373270, 2.372687, 2.372119, 2.371564, 2.371022, 2.370493, 2.369977, 2.369472, 2.368979, 2.368497,
+            2.368026, 2.367566, 2.367115, 2.366674, 2.366243, 2.365821, 2.365407, 2.365002, 2.364606, 2.364217,
+            // 110 - 300 step 10
+            2.360726, 2.357825, 2.355375, 2.353278, 2.351465, 2.349880, 2.348483, 2.347243, 2.346134, 2.345137,
+            2.344236, 2.343417, 2.342670, 2.341985, 2.341356, 2.340775, 2.340238, 2.339739, 2.339275, 2.338842,
+            // 400 - 1300 step 100
+            2.335706, 2.333829, 2.332579, 2.331687, 2.331018, 2.330498, 2.330083, 2.329743, 2.329459, 2.329220,
+            // Infinity
+            2.326348],
+    };
+
+})();
+
+if (typeof module != 'undefined') {
+    for (var key in Statistics)
+        module.exports[key] = Statistics[key];
+}
diff --git a/tools/telemetry/third_party/WebKit/README.chromium b/tools/telemetry/third_party/WebKit/README.chromium
new file mode 100644
index 0000000..e56bb28d
--- /dev/null
+++ b/tools/telemetry/third_party/WebKit/README.chromium
@@ -0,0 +1,11 @@
+Name: Blink javascript libraries.
+Short Name: Blink
+URL: http://www.chromium.org/blink
+Version: N/A
+License: BSD license
+License File: LICENSE
+Security Critical: no
+Description: Blink javascripts libraries are used for visualize performance
+metrics.
+Local Modifications: All the files not needed by telemetry are removed. Only keep
+jquery.tablesorter.min.js and statistics.js
diff --git a/tools/telemetry/third_party/flot/LICENSE.txt b/tools/telemetry/third_party/flot/LICENSE.txt
new file mode 100644
index 0000000..67f4625
--- /dev/null
+++ b/tools/telemetry/third_party/flot/LICENSE.txt
@@ -0,0 +1,22 @@
+Copyright (c) 2007-2013 IOLA and Ole Laursen
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/tools/telemetry/third_party/flot/README.chromium b/tools/telemetry/third_party/flot/README.chromium
new file mode 100644
index 0000000..01bf60df
--- /dev/null
+++ b/tools/telemetry/third_party/flot/README.chromium
@@ -0,0 +1,10 @@
+Name: Flot Javascript/JQuery library for creating graphs
+Short Name: Flot
+URL: code.google.com/p/flot and http://drupal.org/project/flot
+Version: 0.8.1
+License: MIT
+License File: LICENSE.txt
+Security Critical: yes
+Description: Flot is used in the webui for performance monitor and the visualizer for Deep Memory Profiler to draw charts of performance metrics.
+Local Modifications: All the files not needed by telemetry are removed. Only keep
+jquery.flot.min.js.
diff --git a/tools/telemetry/third_party/flot/jquery.flot.min.js b/tools/telemetry/third_party/flot/jquery.flot.min.js
new file mode 100644
index 0000000..3706512
--- /dev/null
+++ b/tools/telemetry/third_party/flot/jquery.flot.min.js
@@ -0,0 +1,29 @@
+/* Javascript plotting library for jQuery, version 0.8.1.
+
+Copyright (c) 2007-2013 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+*/// first an inline dependency, jquery.colorhelpers.js, we inline it here
+// for convenience
+/* Plugin for jQuery for working with colors.
+ *
+ * Version 1.1.
+ *
+ * Inspiration from jQuery color animation plugin by John Resig.
+ *
+ * Released under the MIT license by Ole Laursen, October 2009.
+ *
+ * Examples:
+ *
+ *   $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString()
+ *   var c = $.color.extract($("#mydiv"), 'background-color');
+ *   console.log(c.r, c.g, c.b, c.a);
+ *   $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)"
+ *
+ * Note that .scale() and .add() return the same modified object
+ * instead of making a new one.
+ *
+ * V. 1.1: Fix error handling so e.g. parsing an empty string does
+ * produce a color rather than just crashing.
+ */(function(e){e.color={},e.color.make=function(t,n,r,i){var s={};return s.r=t||0,s.g=n||0,s.b=r||0,s.a=i!=null?i:1,s.add=function(e,t){for(var n=0;n<e.length;++n)s[e.charAt(n)]+=t;return s.normalize()},s.scale=function(e,t){for(var n=0;n<e.length;++n)s[e.charAt(n)]*=t;return s.normalize()},s.toString=function(){return s.a>=1?"rgb("+[s.r,s.g,s.b].join(",")+")":"rgba("+[s.r,s.g,s.b,s.a].join(",")+")"},s.normalize=function(){function e(e,t,n){return t<e?e:t>n?n:t}return s.r=e(0,parseInt(s.r),255),s.g=e(0,parseInt(s.g),255),s.b=e(0,parseInt(s.b),255),s.a=e(0,s.a,1),s},s.clone=function(){return e.color.make(s.r,s.b,s.g,s.a)},s.normalize()},e.color.extract=function(t,n){var r;do{r=t.css(n).toLowerCase();if(r!=""&&r!="transparent")break;t=t.parent()}while(!e.nodeName(t.get(0),"body"));return r=="rgba(0, 0, 0, 0)"&&(r="transparent"),e.color.parse(r)},e.color.parse=function(n){var r,i=e.color.make;if(r=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(n))return i(parseInt(r[1],10),parseInt(r[2],10),parseInt(r[3],10));if(r=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(n))return i(parseInt(r[1],10),parseInt(r[2],10),parseInt(r[3],10),parseFloat(r[4]));if(r=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(n))return i(parseFloat(r[1])*2.55,parseFloat(r[2])*2.55,parseFloat(r[3])*2.55);if(r=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(n))return i(parseFloat(r[1])*2.55,parseFloat(r[2])*2.55,parseFloat(r[3])*2.55,parseFloat(r[4]));if(r=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(n))return i(parseInt(r[1],16),parseInt(r[2],16),parseInt(r[3],16));if(r=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(n))return i(parseInt(r[1]+r[1],16),parseInt(r[2]+r[2],16),parseInt(r[3]+r[3],16));var s=e.trim(n).toLowerCase();return s=="transparent"?i(255,255,255,0):(r=t[s]||[0,0,0],i(r[0],r[1],r[2]))};var t={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery),function(e){function n(t,n){var r=n.children("."+t)[0];if(r==null){r=document.createElement("canvas"),r.className=t,e(r).css({direction:"ltr",position:"absolute",left:0,top:0}).appendTo(n);if(!r.getContext){if(!window.G_vmlCanvasManager)throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode.");r=window.G_vmlCanvasManager.initElement(r)}}this.element=r;var i=this.context=r.getContext("2d"),s=window.devicePixelRatio||1,o=i.webkitBackingStorePixelRatio||i.mozBackingStorePixelRatio||i.msBackingStorePixelRatio||i.oBackingStorePixelRatio||i.backingStorePixelRatio||1;this.pixelRatio=s/o,this.resize(n.width(),n.height()),this.textContainer=null,this.text={},this._textCache={}}function r(t,r,s,o){function E(e,t){t=[w].concat(t);for(var n=0;n<e.length;++n)e[n].apply(this,t)}function S(){var t={Canvas:n};for(var r=0;r<o.length;++r){var i=o[r];i.init(w,t),i.options&&e.extend(!0,a,i.options)}}function x(n){e.extend(!0,a,n),n&&n.colors&&(a.colors=n.colors),a.xaxis.color==null&&(a.xaxis.color=e.color.parse(a.grid.color).scale("a",.22).toString()),a.yaxis.color==null&&(a.yaxis.color=e.color.parse(a.grid.color).scale("a",.22).toString()),a.xaxis.tickColor==null&&(a.xaxis.tickColor=a.grid.tickColor||a.xaxis.color),a.yaxis.tickColor==null&&(a.yaxis.tickColor=a.grid.tickColor||a.yaxis.color),a.grid.borderColor==null&&(a.grid.borderColor=a.grid.color),a.grid.tickColor==null&&(a.grid.tickColor=e.color.parse(a.grid.color).scale("a",.22).toString());var r,i,s,o={style:t.css("font-style"),size:Math.round(.8*(+t.css("font-size").replace("px","")||13)),variant:t.css("font-variant"),weight:t.css("font-weight"),family:t.css("font-family")};o.lineHeight=o.size*1.15,s=a.xaxes.length||1;for(r=0;r<s;++r)i=a.xaxes[r],i&&!i.tickColor&&(i.tickColor=i.color),i=e.extend(!0,{},a.xaxis,i),a.xaxes[r]=i,i.font&&(i.font=e.extend({},o,i.font),i.font.color||(i.font.color=i.color));s=a.yaxes.length||1;for(r=0;r<s;++r)i=a.yaxes[r],i&&!i.tickColor&&(i.tickColor=i.color),i=e.extend(!0,{},a.yaxis,i),a.yaxes[r]=i,i.font&&(i.font=e.extend({},o,i.font),i.font.color||(i.font.color=i.color));a.xaxis.noTicks&&a.xaxis.ticks==null&&(a.xaxis.ticks=a.xaxis.noTicks),a.yaxis.noTicks&&a.yaxis.ticks==null&&(a.yaxis.ticks=a.yaxis.noTicks),a.x2axis&&(a.xaxes[1]=e.extend(!0,{},a.xaxis,a.x2axis),a.xaxes[1].position="top"),a.y2axis&&(a.yaxes[1]=e.extend(!0,{},a.yaxis,a.y2axis),a.yaxes[1].position="right"),a.grid.coloredAreas&&(a.grid.markings=a.grid.coloredAreas),a.grid.coloredAreasColor&&(a.grid.markingsColor=a.grid.coloredAreasColor),a.lines&&e.extend(!0,a.series.lines,a.lines),a.points&&e.extend(!0,a.series.points,a.points),a.bars&&e.extend(!0,a.series.bars,a.bars),a.shadowSize!=null&&(a.series.shadowSize=a.shadowSize),a.highlightColor!=null&&(a.series.highlightColor=a.highlightColor);for(r=0;r<a.xaxes.length;++r)O(d,r+1).options=a.xaxes[r];for(r=0;r<a.yaxes.length;++r)O(v,r+1).options=a.yaxes[r];for(var u in b)a.hooks[u]&&a.hooks[u].length&&(b[u]=b[u].concat(a.hooks[u]));E(b.processOptions,[a])}function T(e){u=N(e),M(),_()}function N(t){var n=[];for(var r=0;r<t.length;++r){var i=e.extend(!0,{},a.series);t[r].data!=null?(i.data=t[r].data,delete t[r].data,e.extend(!0,i,t[r]),t[r].data=i.data):i.data=t[r],n.push(i)}return n}function C(e,t){var n=e[t+"axis"];return typeof n=="object"&&(n=n.n),typeof n!="number"&&(n=1),n}function k(){return e.grep(d.concat(v),function(e){return e})}function L(e){var t={},n,r;for(n=0;n<d.length;++n)r=d[n],r&&r.used&&(t["x"+r.n]=r.c2p(e.left));for(n=0;n<v.length;++n)r=v[n],r&&r.used&&(t["y"+r.n]=r.c2p(e.top));return t.x1!==undefined&&(t.x=t.x1),t.y1!==undefined&&(t.y=t.y1),t}function A(e){var t={},n,r,i;for(n=0;n<d.length;++n){r=d[n];if(r&&r.used){i="x"+r.n,e[i]==null&&r.n==1&&(i="x");if(e[i]!=null){t.left=r.p2c(e[i]);break}}}for(n=0;n<v.length;++n){r=v[n];if(r&&r.used){i="y"+r.n,e[i]==null&&r.n==1&&(i="y");if(e[i]!=null){t.top=r.p2c(e[i]);break}}}return t}function O(t,n){return t[n-1]||(t[n-1]={n:n,direction:t==d?"x":"y",options:e.extend(!0,{},t==d?a.xaxis:a.yaxis)}),t[n-1]}function M(){var t=u.length,n=-1,r;for(r=0;r<u.length;++r){var i=u[r].color;i!=null&&(t--,typeof i=="number"&&i>n&&(n=i))}t<=n&&(t=n+1);var s,o=[],f=a.colors,l=f.length,c=0;for(r=0;r<t;r++)s=e.color.parse(f[r%l]||"#666"),r%l==0&&r&&(c>=0?c<.5?c=-c-.2:c=0:c=-c),o[r]=s.scale("rgb",1+c);var h=0,p;for(r=0;r<u.length;++r){p=u[r],p.color==null?(p.color=o[h].toString(),++h):typeof p.color=="number"&&(p.color=o[p.color].toString());if(p.lines.show==null){var m,g=!0;for(m in p)if(p[m]&&p[m].show){g=!1;break}g&&(p.lines.show=!0)}p.lines.zero==null&&(p.lines.zero=!!p.lines.fill),p.xaxis=O(d,C(p,"x")),p.yaxis=O(v,C(p,"y"))}}function _(){function x(e,t,n){t<e.datamin&&t!=-r&&(e.datamin=t),n>e.datamax&&n!=r&&(e.datamax=n)}var t=Number.POSITIVE_INFINITY,n=Number.NEGATIVE_INFINITY,r=Number.MAX_VALUE,i,s,o,a,f,l,c,h,p,d,v,m,g,y,w,S;e.each(k(),function(e,r){r.datamin=t,r.datamax=n,r.used=!1});for(i=0;i<u.length;++i)l=u[i],l.datapoints={points:[]},E(b.processRawData,[l,l.data,l.datapoints]);for(i=0;i<u.length;++i){l=u[i],w=l.data,S=l.datapoints.format;if(!S){S=[],S.push({x:!0,number:!0,required:!0}),S.push({y:!0,number:!0,required:!0});if(l.bars.show||l.lines.show&&l.lines.fill){var T=!!(l.bars.show&&l.bars.zero||l.lines.show&&l.lines.zero);S.push({y:!0,number:!0,required:!1,defaultValue:0,autoscale:T}),l.bars.horizontal&&(delete S[S.length-1].y,S[S.length-1].x=!0)}l.datapoints.format=S}if(l.datapoints.pointsize!=null)continue;l.datapoints.pointsize=S.length,h=l.datapoints.pointsize,c=l.datapoints.points;var N=l.lines.show&&l.lines.steps;l.xaxis.used=l.yaxis.used=!0;for(s=o=0;s<w.length;++s,o+=h){y=w[s];var C=y==null;if(!C)for(a=0;a<h;++a)m=y[a],g=S[a],g&&(g.number&&m!=null&&(m=+m,isNaN(m)?m=null:m==Infinity?m=r:m==-Infinity&&(m=-r)),m==null&&(g.required&&(C=!0),g.defaultValue!=null&&(m=g.defaultValue))),c[o+a]=m;if(C)for(a=0;a<h;++a)m=c[o+a],m!=null&&(g=S[a],g.autoscale&&(g.x&&x(l.xaxis,m,m),g.y&&x(l.yaxis,m,m))),c[o+a]=null;else if(N&&o>0&&c[o-h]!=null&&c[o-h]!=c[o]&&c[o-h+1]!=c[o+1]){for(a=0;a<h;++a)c[o+h+a]=c[o+a];c[o+1]=c[o-h+1],o+=h}}}for(i=0;i<u.length;++i)l=u[i],E(b.processDatapoints,[l,l.datapoints]);for(i=0;i<u.length;++i){l=u[i],c=l.datapoints.points,h=l.datapoints.pointsize,S=l.datapoints.format;var L=t,A=t,O=n,M=n;for(s=0;s<c.length;s+=h){if(c[s]==null)continue;for(a=0;a<h;++a){m=c[s+a],g=S[a];if(!g||g.autoscale===!1||m==r||m==-r)continue;g.x&&(m<L&&(L=m),m>O&&(O=m)),g.y&&(m<A&&(A=m),m>M&&(M=m))}}if(l.bars.show){var _;switch(l.bars.align){case"left":_=0;break;case"right":_=-l.bars.barWidth;break;case"center":_=-l.bars.barWidth/2;break;default:throw new Error("Invalid bar alignment: "+l.bars.align)}l.bars.horizontal?(A+=_,M+=_+l.bars.barWidth):(L+=_,O+=_+l.bars.barWidth)}x(l.xaxis,L,O),x(l.yaxis,A,M)}e.each(k(),function(e,r){r.datamin==t&&(r.datamin=null),r.datamax==n&&(r.datamax=null)})}function D(){t.css("padding",0).children(":not(.flot-base,.flot-overlay)").remove(),t.css("position")=="static"&&t.css("position","relative"),f=new n("flot-base",t),l=new n("flot-overlay",t),h=f.context,p=l.context,c=e(l.element).unbind();var r=t.data("plot");r&&(r.shutdown(),l.clear()),t.data("plot",w)}function P(){a.grid.hoverable&&(c.mousemove(at),c.bind("mouseleave",ft)),a.grid.clickable&&c.click(lt),E(b.bindEvents,[c])}function H(){ot&&clearTimeout(ot),c.unbind("mousemove",at),c.unbind("mouseleave",ft),c.unbind("click",lt),E(b.shutdown,[c])}function B(e){function t(e){return e}var n,r,i=e.options.transform||t,s=e.options.inverseTransform;e.direction=="x"?(n=e.scale=g/Math.abs(i(e.max)-i(e.min)),r=Math.min(i(e.max),i(e.min))):(n=e.scale=y/Math.abs(i(e.max)-i(e.min)),n=-n,r=Math.max(i(e.max),i(e.min))),i==t?e.p2c=function(e){return(e-r)*n}:e.p2c=function(e){return(i(e)-r)*n},s?e.c2p=function(e){return s(r+e/n)}:e.c2p=function(e){return r+e/n}}function j(e){var t=e.options,n=e.ticks||[],r=t.labelWidth||0,i=t.labelHeight||0,s=r||e.direction=="x"?Math.floor(f.width/(n.length||1)):null;legacyStyles=e.direction+"Axis "+e.direction+e.n+"Axis",layer="flot-"+e.direction+"-axis flot-"+e.direction+e.n+"-axis "+legacyStyles,font=t.font||"flot-tick-label tickLabel";for(var o=0;o<n.length;++o){var u=n[o];if(!u.label)continue;var a=f.getTextInfo(layer,u.label,font,null,s);r=Math.max(r,a.width),i=Math.max(i,a.height)}e.labelWidth=t.labelWidth||r,e.labelHeight=t.labelHeight||i}function F(t){var n=t.labelWidth,r=t.labelHeight,i=t.options.position,s=t.options.tickLength,o=a.grid.axisMargin,u=a.grid.labelMargin,l=t.direction=="x"?d:v,c,h,p=e.grep(l,function(e){return e&&e.options.position==i&&e.reserveSpace});e.inArray(t,p)==p.length-1&&(o=0);if(s==null){var g=e.grep(l,function(e){return e&&e.reserveSpace});h=e.inArray(t,g)==0,h?s="full":s=5}isNaN(+s)||(u+=+s),t.direction=="x"?(r+=u,i=="bottom"?(m.bottom+=r+o,t.box={top:f.height-m.bottom,height:r}):(t.box={top:m.top+o,height:r},m.top+=r+o)):(n+=u,i=="left"?(t.box={left:m.left+o,width:n},m.left+=n+o):(m.right+=n+o,t.box={left:f.width-m.right,width:n})),t.position=i,t.tickLength=s,t.box.padding=u,t.innermost=h}function I(e){e.direction=="x"?(e.box.left=m.left-e.labelWidth/2,e.box.width=f.width-m.left-m.right+e.labelWidth):(e.box.top=m.top-e.labelHeight/2,e.box.height=f.height-m.bottom-m.top+e.labelHeight)}function q(){var t=a.grid.minBorderMargin,n={x:0,y:0},r,i;if(t==null){t=0;for(r=0;r<u.length;++r)t=Math.max(t,2*(u[r].points.radius+u[r].points.lineWidth/2))}n.x=n.y=Math.ceil(t),e.each(k(),function(e,t){var r=t.direction;t.reserveSpace&&(n[r]=Math.ceil(Math.max(n[r],(r=="x"?t.labelWidth:t.labelHeight)/2)))}),m.left=Math.max(n.x,m.left),m.right=Math.max(n.x,m.right),m.top=Math.max(n.y,m.top),m.bottom=Math.max(n.y,m.bottom)}function R(){var t,n=k(),r=a.grid.show;for(var i in m){var s=a.grid.margin||0;m[i]=typeof s=="number"?s:s[i]||0}E(b.processOffset,[m]);for(var i in m)typeof a.grid.borderWidth=="object"?m[i]+=r?a.grid.borderWidth[i]:0:m[i]+=r?a.grid.borderWidth:0;e.each(n,function(e,t){t.show=t.options.show,t.show==null&&(t.show=t.used),t.reserveSpace=t.show||t.options.reserveSpace,U(t)});if(r){var o=e.grep(n,function(e){return e.reserveSpace});e.each(o,function(e,t){z(t),W(t),X(t,t.ticks),j(t)});for(t=o.length-1;t>=0;--t)F(o[t]);q(),e.each(o,function(e,t){I(t)})}g=f.width-m.left-m.right,y=f.height-m.bottom-m.top,e.each(n,function(e,t){B(t)}),r&&G(),it()}function U(e){var t=e.options,n=+(t.min!=null?t.min:e.datamin),r=+(t.max!=null?t.max:e.datamax),i=r-n;if(i==0){var s=r==0?1:.01;t.min==null&&(n-=s);if(t.max==null||t.min!=null)r+=s}else{var o=t.autoscaleMargin;o!=null&&(t.min==null&&(n-=i*o,n<0&&e.datamin!=null&&e.datamin>=0&&(n=0)),t.max==null&&(r+=i*o,r>0&&e.datamax!=null&&e.datamax<=0&&(r=0)))}e.min=n,e.max=r}function z(t){var n=t.options,r;typeof n.ticks=="number"&&n.ticks>0?r=n.ticks:r=.3*Math.sqrt(t.direction=="x"?f.width:f.height);var s=(t.max-t.min)/r,o=-Math.floor(Math.log(s)/Math.LN10),u=n.tickDecimals;u!=null&&o>u&&(o=u);var a=Math.pow(10,-o),l=s/a,c;l<1.5?c=1:l<3?(c=2,l>2.25&&(u==null||o+1<=u)&&(c=2.5,++o)):l<7.5?c=5:c=10,c*=a,n.minTickSize!=null&&c<n.minTickSize&&(c=n.minTickSize),t.delta=s,t.tickDecimals=Math.max(0,u!=null?u:o),t.tickSize=n.tickSize||c;if(n.mode=="time"&&!t.tickGenerator)throw new Error("Time mode requires the flot.time plugin.");t.tickGenerator||(t.tickGenerator=function(e){var t=[],n=i(e.min,e.tickSize),r=0,s=Number.NaN,o;do o=s,s=n+r*e.tickSize,t.push(s),++r;while(s<e.max&&s!=o);return t},t.tickFormatter=function(e,t){var n=t.tickDecimals?Math.pow(10,t.tickDecimals):1,r=""+Math.round(e*n)/n;if(t.tickDecimals!=null){var i=r.indexOf("."),s=i==-1?0:r.length-i-1;if(s<t.tickDecimals)return(s?r:r+".")+(""+n).substr(1,t.tickDecimals-s)}return r}),e.isFunction(n.tickFormatter)&&(t.tickFormatter=function(e,t){return""+n.tickFormatter(e,t)});if(n.alignTicksWithAxis!=null){var h=(t.direction=="x"?d:v)[n.alignTicksWithAxis-1];if(h&&h.used&&h!=t){var p=t.tickGenerator(t);p.length>0&&(n.min==null&&(t.min=Math.min(t.min,p[0])),n.max==null&&p.length>1&&(t.max=Math.max(t.max,p[p.length-1]))),t.tickGenerator=function(e){var t=[],n,r;for(r=0;r<h.ticks.length;++r)n=(h.ticks[r].v-h.min)/(h.max-h.min),n=e.min+n*(e.max-e.min),t.push(n);return t};if(!t.mode&&n.tickDecimals==null){var m=Math.max(0,-Math.floor(Math.log(t.delta)/Math.LN10)+1),g=t.tickGenerator(t);g.length>1&&/\..*0$/.test((g[1]-g[0]).toFixed(m))||(t.tickDecimals=m)}}}}function W(t){var n=t.options.ticks,r=[];n==null||typeof n=="number"&&n>0?r=t.tickGenerator(t):n&&(e.isFunction(n)?r=n(t):r=n);var i,s;t.ticks=[];for(i=0;i<r.length;++i){var o=null,u=r[i];typeof u=="object"?(s=+u[0],u.length>1&&(o=u[1])):s=+u,o==null&&(o=t.tickFormatter(s,t)),isNaN(s)||t.ticks.push({v:s,label:o})}}function X(e,t){e.options.autoscaleMargin&&t.length>0&&(e.options.min==null&&(e.min=Math.min(e.min,t[0].v)),e.options.max==null&&t.length>1&&(e.max=Math.max(e.max,t[t.length-1].v)))}function V(){f.clear(),E(b.drawBackground,[h]);var e=a.grid;e.show&&e.backgroundColor&&K(),e.show&&!e.aboveData&&Q();for(var t=0;t<u.length;++t)E(b.drawSeries,[h,u[t]]),Y(u[t]);E(b.draw,[h]),e.show&&e.aboveData&&Q(),f.render(),ht()}function J(e,t){var n,r,i,s,o=k();for(var u=0;u<o.length;++u){n=o[u];if(n.direction==t){s=t+n.n+"axis",!e[s]&&n.n==1&&(s=t+"axis");if(e[s]){r=e[s].from,i=e[s].to;break}}}e[s]||(n=t=="x"?d[0]:v[0],r=e[t+"1"],i=e[t+"2"]);if(r!=null&&i!=null&&r>i){var a=r;r=i,i=a}return{from:r,to:i,axis:n}}function K(){h.save(),h.translate(m.left,m.top),h.fillStyle=bt(a.grid.backgroundColor,y,0,"rgba(255, 255, 255, 0)"),h.fillRect(0,0,g,y),h.restore()}function Q(){var t,n,r,i;h.save(),h.translate(m.left,m.top);var s=a.grid.markings;if(s){e.isFunction(s)&&(n=w.getAxes(),n.xmin=n.xaxis.min,n.xmax=n.xaxis.max,n.ymin=n.yaxis.min,n.ymax=n.yaxis.max,s=s(n));for(t=0;t<s.length;++t){var o=s[t],u=J(o,"x"),f=J(o,"y");u.from==null&&(u.from=u.axis.min),u.to==null&&(u.to=u.axis.max),f.from==null&&(f.from=f.axis.min),f.to==null&&(f.to=f.axis.max);if(u.to<u.axis.min||u.from>u.axis.max||f.to<f.axis.min||f.from>f.axis.max)continue;u.from=Math.max(u.from,u.axis.min),u.to=Math.min(u.to,u.axis.max),f.from=Math.max(f.from,f.axis.min),f.to=Math.min(f.to,f.axis.max);if(u.from==u.to&&f.from==f.to)continue;u.from=u.axis.p2c(u.from),u.to=u.axis.p2c(u.to),f.from=f.axis.p2c(f.from),f.to=f.axis.p2c(f.to),u.from==u.to||f.from==f.to?(h.beginPath(),h.strokeStyle=o.color||a.grid.markingsColor,h.lineWidth=o.lineWidth||a.grid.markingsLineWidth,h.moveTo(u.from,f.from),h.lineTo(u.to,f.to),h.stroke()):(h.fillStyle=o.color||a.grid.markingsColor,h.fillRect(u.from,f.to,u.to-u.from,f.from-f.to))}}n=k(),r=a.grid.borderWidth;for(var l=0;l<n.length;++l){var c=n[l],p=c.box,d=c.tickLength,v,b,E,S;if(!c.show||c.ticks.length==0)continue;h.lineWidth=1,c.direction=="x"?(v=0,d=="full"?b=c.position=="top"?0:y:b=p.top-m.top+(c.position=="top"?p.height:0)):(b=0,d=="full"?v=c.position=="left"?0:g:v=p.left-m.left+(c.position=="left"?p.width:0)),c.innermost||(h.strokeStyle=c.options.color,h.beginPath(),E=S=0,c.direction=="x"?E=g+1:S=y+1,h.lineWidth==1&&(c.direction=="x"?b=Math.floor(b)+.5:v=Math.floor(v)+.5),h.moveTo(v,b),h.lineTo(v+E,b+S),h.stroke()),h.strokeStyle=c.options.tickColor,h.beginPath();for(t=0;t<c.ticks.length;++t){var x=c.ticks[t].v;E=S=0;if(isNaN(x)||x<c.min||x>c.max||d=="full"&&(typeof r=="object"&&r[c.position]>0||r>0)&&(x==c.min||x==c.max))continue;c.direction=="x"?(v=c.p2c(x),S=d=="full"?-y:d,c.position=="top"&&(S=-S)):(b=c.p2c(x),E=d=="full"?-g:d,c.position=="left"&&(E=-E)),h.lineWidth==1&&(c.direction=="x"?v=Math.floor(v)+.5:b=Math.floor(b)+.5),h.moveTo(v,b),h.lineTo(v+E,b+S)}h.stroke()}r&&(i=a.grid.borderColor,typeof r=="object"||typeof i=="object"?(typeof r!="object"&&(r={top:r,right:r,bottom:r,left:r}),typeof i!="object"&&(i={top:i,right:i,bottom:i,left:i}),r.top>0&&(h.strokeStyle=i.top,h.lineWidth=r.top,h.beginPath(),h.moveTo(0-r.left,0-r.top/2),h.lineTo(g,0-r.top/2),h.stroke()),r.right>0&&(h.strokeStyle=i.right,h.lineWidth=r.right,h.beginPath(),h.moveTo(g+r.right/2,0-r.top),h.lineTo(g+r.right/2,y),h.stroke()),r.bottom>0&&(h.strokeStyle=i.bottom,h.lineWidth=r.bottom,h.beginPath(),h.moveTo(g+r.right,y+r.bottom/2),h.lineTo(0,y+r.bottom/2),h.stroke()),r.left>0&&(h.strokeStyle=i.left,h.lineWidth=r.left,h.beginPath(),h.moveTo(0-r.left/2,y+r.bottom),h.lineTo(0-r.left/2,0),h.stroke())):(h.lineWidth=r,h.strokeStyle=a.grid.borderColor,h.strokeRect(-r/2,-r/2,g+r,y+r))),h.restore()}function G(){e.each(k(),function(e,t){if(!t.show||t.ticks.length==0)return;var n=t.box,r=t.direction+"Axis "+t.direction+t.n+"Axis",i="flot-"+t.direction+"-axis flot-"+t.direction+t.n+"-axis "+r,s=t.options.font||"flot-tick-label tickLabel",o,u,a,l,c;f.removeText(i);for(var h=0;h<t.ticks.length;++h){o=t.ticks[h];if(!o.label||o.v<t.min||o.v>t.max)continue;t.direction=="x"?(l="center",u=m.left+t.p2c(o.v),t.position=="bottom"?a=n.top+n.padding:(a=n.top+n.height-n.padding,c="bottom")):(c="middle",a=m.top+t.p2c(o.v),t.position=="left"?(u=n.left+n.width-n.padding,l="right"):u=n.left+n.padding),f.addText(i,u,a,o.label,s,null,null,l,c)}})}function Y(e){e.lines.show&&Z(e),e.bars.show&&nt(e),e.points.show&&et(e)}function Z(e){function t(e,t,n,r,i){var s=e.points,o=e.pointsize,u=null,a=null;h.beginPath();for(var f=o;f<s.length;f+=o){var l=s[f-o],c=s[f-o+1],p=s[f],d=s[f+1];if(l==null||p==null)continue;if(c<=d&&c<i.min){if(d<i.min)continue;l=(i.min-c)/(d-c)*(p-l)+l,c=i.min}else if(d<=c&&d<i.min){if(c<i.min)continue;p=(i.min-c)/(d-c)*(p-l)+l,d=i.min}if(c>=d&&c>i.max){if(d>i.max)continue;l=(i.max-c)/(d-c)*(p-l)+l,c=i.max}else if(d>=c&&d>i.max){if(c>i.max)continue;p=(i.max-c)/(d-c)*(p-l)+l,d=i.max}if(l<=p&&l<r.min){if(p<r.min)continue;c=(r.min-l)/(p-l)*(d-c)+c,l=r.min}else if(p<=l&&p<r.min){if(l<r.min)continue;d=(r.min-l)/(p-l)*(d-c)+c,p=r.min}if(l>=p&&l>r.max){if(p>r.max)continue;c=(r.max-l)/(p-l)*(d-c)+c,l=r.max}else if(p>=l&&p>r.max){if(l>r.max)continue;d=(r.max-l)/(p-l)*(d-c)+c,p=r.max}(l!=u||c!=a)&&h.moveTo(r.p2c(l)+t,i.p2c(c)+n),u=p,a=d,h.lineTo(r.p2c(p)+t,i.p2c(d)+n)}h.stroke()}function n(e,t,n){var r=e.points,i=e.pointsize,s=Math.min(Math.max(0,n.min),n.max),o=0,u,a=!1,f=1,l=0,c=0;for(;;){if(i>0&&o>r.length+i)break;o+=i;var p=r[o-i],d=r[o-i+f],v=r[o],m=r[o+f];if(a){if(i>0&&p!=null&&v==null){c=o,i=-i,f=2;continue}if(i<0&&o==l+i){h.fill(),a=!1,i=-i,f=1,o=l=c+i;continue}}if(p==null||v==null)continue;if(p<=v&&p<t.min){if(v<t.min)continue;d=(t.min-p)/(v-p)*(m-d)+d,p=t.min}else if(v<=p&&v<t.min){if(p<t.min)continue;m=(t.min-p)/(v-p)*(m-d)+d,v=t.min}if(p>=v&&p>t.max){if(v>t.max)continue;d=(t.max-p)/(v-p)*(m-d)+d,p=t.max}else if(v>=p&&v>t.max){if(p>t.max)continue;m=(t.max-p)/(v-p)*(m-d)+d,v=t.max}a||(h.beginPath(),h.moveTo(t.p2c(p),n.p2c(s)),a=!0);if(d>=n.max&&m>=n.max){h.lineTo(t.p2c(p),n.p2c(n.max)),h.lineTo(t.p2c(v),n.p2c(n.max));continue}if(d<=n.min&&m<=n.min){h.lineTo(t.p2c(p),n.p2c(n.min)),h.lineTo(t.p2c(v),n.p2c(n.min));continue}var g=p,y=v;d<=m&&d<n.min&&m>=n.min?(p=(n.min-d)/(m-d)*(v-p)+p,d=n.min):m<=d&&m<n.min&&d>=n.min&&(v=(n.min-d)/(m-d)*(v-p)+p,m=n.min),d>=m&&d>n.max&&m<=n.max?(p=(n.max-d)/(m-d)*(v-p)+p,d=n.max):m>=d&&m>n.max&&d<=n.max&&(v=(n.max-d)/(m-d)*(v-p)+p,m=n.max),p!=g&&h.lineTo(t.p2c(g),n.p2c(d)),h.lineTo(t.p2c(p),n.p2c(d)),h.lineTo(t.p2c(v),n.p2c(m)),v!=y&&(h.lineTo(t.p2c(v),n.p2c(m)),h.lineTo(t.p2c(y),n.p2c(m)))}}h.save(),h.translate(m.left,m.top),h.lineJoin="round";var r=e.lines.lineWidth,i=e.shadowSize;if(r>0&&i>0){h.lineWidth=i,h.strokeStyle="rgba(0,0,0,0.1)";var s=Math.PI/18;t(e.datapoints,Math.sin(s)*(r/2+i/2),Math.cos(s)*(r/2+i/2),e.xaxis,e.yaxis),h.lineWidth=i/2,t(e.datapoints,Math.sin(s)*(r/2+i/4),Math.cos(s)*(r/2+i/4),e.xaxis,e.yaxis)}h.lineWidth=r,h.strokeStyle=e.color;var o=rt(e.lines,e.color,0,y);o&&(h.fillStyle=o,n(e.datapoints,e.xaxis,e.yaxis)),r>0&&t(e.datapoints,0,0,e.xaxis,e.yaxis),h.restore()}function et(e){function t(e,t,n,r,i,s,o,u){var a=e.points,f=e.pointsize;for(var l=0;l<a.length;l+=f){var c=a[l],p=a[l+1];if(c==null||c<s.min||c>s.max||p<o.min||p>o.max)continue;h.beginPath(),c=s.p2c(c),p=o.p2c(p)+r,u=="circle"?h.arc(c,p,t,0,i?Math.PI:Math.PI*2,!1):u(h,c,p,t,i),h.closePath(),n&&(h.fillStyle=n,h.fill()),h.stroke()}}h.save(),h.translate(m.left,m.top);var n=e.points.lineWidth,r=e.shadowSize,i=e.points.radius,s=e.points.symbol;n==0&&(n=1e-4);if(n>0&&r>0){var o=r/2;h.lineWidth=o,h.strokeStyle="rgba(0,0,0,0.1)",t(e.datapoints,i,null,o+o/2,!0,e.xaxis,e.yaxis,s),h.strokeStyle="rgba(0,0,0,0.2)",t(e.datapoints,i,null,o/2,!0,e.xaxis,e.yaxis,s)}h.lineWidth=n,h.strokeStyle=e.color,t(e.datapoints,i,rt(e.points,e.color),0,!1,e.xaxis,e.yaxis,s),h.restore()}function tt(e,t,n,r,i,s,o,u,a,f,l,c){var h,p,d,v,m,g,y,b,w;l?(b=g=y=!0,m=!1,h=n,p=e,v=t+r,d=t+i,p<h&&(w=p,p=h,h=w,m=!0,g=!1)):(m=g=y=!0,b=!1,h=e+r,p=e+i,d=n,v=t,v<d&&(w=v,v=d,d=w,b=!0,y=!1));if(p<u.min||h>u.max||v<a.min||d>a.max)return;h<u.min&&(h=u.min,m=!1),p>u.max&&(p=u.max,g=!1),d<a.min&&(d=a.min,b=!1),v>a.max&&(v=a.max,y=!1),h=u.p2c(h),d=a.p2c(d),p=u.p2c(p),v=a.p2c(v),o&&(f.beginPath(),f.moveTo(h,d),f.lineTo(h,v),f.lineTo(p,v),f.lineTo(p,d),f.fillStyle=o(d,v),f.fill()),c>0&&(m||g||y||b)&&(f.beginPath(),f.moveTo(h,d+s),m?f.lineTo(h,v+s):f.moveTo(h,v+s),y?f.lineTo(p,v+s):f.moveTo(p,v+s),g?f.lineTo(p,d+s):f.moveTo(p,d+s),b?f.lineTo(h,d+s):f.moveTo(h,d+s),f.stroke())}function nt(e){function t(t,n,r,i,s,o,u){var a=t.points,f=t.pointsize;for(var l=0;l<a.length;l+=f){if(a[l]==null)continue;tt(a[l],a[l+1],a[l+2],n,r,i,s,o,u,h,e.bars.horizontal,e.bars.lineWidth)}}h.save(),h.translate(m.left,m.top),h.lineWidth=e.bars.lineWidth,h.strokeStyle=e.color;var n;switch(e.bars.align){case"left":n=0;break;case"right":n=-e.bars.barWidth;break;case"center":n=-e.bars.barWidth/2;break;default:throw new Error("Invalid bar alignment: "+e.bars.align)}var r=e.bars.fill?function(t,n){return rt(e.bars,e.color,t,n)}:null;t(e.datapoints,n,n+e.bars.barWidth,0,r,e.xaxis,e.yaxis),h.restore()}function rt(t,n,r,i){var s=t.fill;if(!s)return null;if(t.fillColor)return bt(t.fillColor,r,i,n);var o=e.color.parse(n);return o.a=typeof s=="number"?s:.4,o.normalize(),o.toString()}function it(){t.find(".legend").remove();if(!a.legend.show)return;var n=[],r=[],i=!1,s=a.legend.labelFormatter,o,f;for(var l=0;l<u.length;++l)o=u[l],o.label&&(f=s?s(o.label,o):o.label,f&&r.push({label:f,color:o.color}));if(a.legend.sorted)if(e.isFunction(a.legend.sorted))r.sort(a.legend.sorted);else if(a.legend.sorted=="reverse")r.reverse();else{var c=a.legend.sorted!="descending";r.sort(function(e,t){return e.label==t.label?0:e.label<t.label!=c?1:-1})}for(var l=0;l<r.length;++l){var h=r[l];l%a.legend.noColumns==0&&(i&&n.push("</tr>"),n.push("<tr>"),i=!0),n.push('<td class="legendColorBox"><div style="border:1px solid '+a.legend.labelBoxBorderColor+';padding:1px"><div style="width:4px;height:0;border:5px solid '+h.color+';overflow:hidden"></div></div></td>'+'<td class="legendLabel">'+h.label+"</td>")}i&&n.push("</tr>");if(n.length==0)return;var p='<table style="font-size:smaller;color:'+a.grid.color+'">'+n.join("")+"</table>";if(a.legend.container!=null)e(a.legend.container).html(p);else{var d="",v=a.legend.position,g=a.legend.margin;g[0]==null&&(g=[g,g]),v.charAt(0)=="n"?d+="top:"+(g[1]+m.top)+"px;":v.charAt(0)=="s"&&(d+="bottom:"+(g[1]+m.bottom)+"px;"),v.charAt(1)=="e"?d+="right:"+(g[0]+m.right)+"px;":v.charAt(1)=="w"&&(d+="left:"+(g[0]+m.left)+"px;");var y=e('<div class="legend">'+p.replace('style="','style="position:absolute;'+d+";")+"</div>").appendTo(t);if(a.legend.backgroundOpacity!=0){var b=a.legend.backgroundColor;b==null&&(b=a.grid.backgroundColor,b&&typeof b=="string"?b=e.color.parse(b):b=e.color.extract(y,"background-color"),b.a=1,b=b.toString());var w=y.children();e('<div style="position:absolute;width:'+w.width()+"px;height:"+w.height()+"px;"+d+"background-color:"+b+';"> </div>').prependTo(y).css("opacity",a.legend.backgroundOpacity)}}}function ut(e,t,n){var r=a.grid.mouseActiveRadius,i=r*r+1,s=null,o=!1,f,l,c;for(f=u.length-1;f>=0;--f){if(!n(u[f]))continue;var h=u[f],p=h.xaxis,d=h.yaxis,v=h.datapoints.points,m=p.c2p(e),g=d.c2p(t),y=r/p.scale,b=r/d.scale;c=h.datapoints.pointsize,p.options.inverseTransform&&(y=Number.MAX_VALUE),d.options.inverseTransform&&(b=Number.MAX_VALUE);if(h.lines.show||h.points.show)for(l=0;l<v.length;l+=c){var w=v[l],E=v[l+1];if(w==null)continue;if(w-m>y||w-m<-y||E-g>b||E-g<-b)continue;var S=Math.abs(p.p2c(w)-e),x=Math.abs(d.p2c(E)-t),T=S*S+x*x;T<i&&(i=T,s=[f,l/c])}if(h.bars.show&&!s){var N=h.bars.align=="left"?0:-h.bars.barWidth/2,C=N+h.bars.barWidth;for(l=0;l<v.length;l+=c){var w=v[l],E=v[l+1],k=v[l+2];if(w==null)continue;if(u[f].bars.horizontal?m<=Math.max(k,w)&&m>=Math.min(k,w)&&g>=E+N&&g<=E+C:m>=w+N&&m<=w+C&&g>=Math.min(k,E)&&g<=Math.max(k,E))s=[f,l/c]}}}return s?(f=s[0],l=s[1],c=u[f].datapoints.pointsize,{datapoint:u[f].datapoints.points.slice(l*c,(l+1)*c),dataIndex:l,series:u[f],seriesIndex:f}):null}function at(e){a.grid.hoverable&&ct("plothover",e,function(e){return e["hoverable"]!=0})}function ft(e){a.grid.hoverable&&ct("plothover",e,function(e){return!1})}function lt(e){ct("plotclick",e,function(e){return e["clickable"]!=0})}function ct(e,n,r){var i=c.offset(),s=n.pageX-i.left-m.left,o=n.pageY-i.top-m.top,u=L({left:s,top:o});u.pageX=n.pageX,u.pageY=n.pageY;var f=ut(s,o,r);f&&(f.pageX=parseInt(f.series.xaxis.p2c(f.datapoint[0])+i.left+m.left,10),f.pageY=parseInt(f.series.yaxis.p2c(f.datapoint[1])+i.top+m.top,10));if(a.grid.autoHighlight){for(var l=0;l<st.length;++l){var h=st[l];h.auto==e&&(!f||h.series!=f.series||h.point[0]!=f.datapoint[0]||h.point[1]!=f.datapoint[1])&&vt(h.series,h.point)}f&&dt(f.series,f.datapoint,e)}t.trigger(e,[u,f])}function ht(){var e=a.interaction.redrawOverlayInterval;if(e==-1){pt();return}ot||(ot=setTimeout(pt,e))}function pt(){ot=null,p.save(),l.clear(),p.translate(m.left,m.top);var e,t;for(e=0;e<st.length;++e)t=st[e],t.series.bars.show?yt(t.series,t.point):gt(t.series,t.point);p.restore(),E(b.drawOverlay,[p])}function dt(e,t,n){typeof e=="number"&&(e=u[e]);if(typeof t=="number"){var r=e.datapoints.pointsize;t=e.datapoints.points.slice(r*t,r*(t+1))}var i=mt(e,t);i==-1?(st.push({series:e,point:t,auto:n}),ht()):n||(st[i].auto=!1)}function vt(e,t){if(e==null&&t==null){st=[],ht();return}typeof e=="number"&&(e=u[e]);if(typeof t=="number"){var n=e.datapoints.pointsize;t=e.datapoints.points.slice(n*t,n*(t+1))}var r=mt(e,t);r!=-1&&(st.splice(r,1),ht())}function mt(e,t){for(var n=0;n<st.length;++n){var r=st[n];if(r.series==e&&r.point[0]==t[0]&&r.point[1]==t[1])return n}return-1}function gt(t,n){var r=n[0],i=n[1],s=t.xaxis,o=t.yaxis,u=typeof t.highlightColor=="string"?t.highlightColor:e.color.parse(t.color).scale("a",.5).toString();if(r<s.min||r>s.max||i<o.min||i>o.max)return;var a=t.points.radius+t.points.lineWidth/2;p.lineWidth=a,p.strokeStyle=u;var f=1.5*a;r=s.p2c(r),i=o.p2c(i),p.beginPath(),t.points.symbol=="circle"?p.arc(r,i,f,0,2*Math.PI,!1):t.points.symbol(p,r,i,f,!1),p.closePath(),p.stroke()}function yt(t,n){var r=typeof t.highlightColor=="string"?t.highlightColor:e.color.parse(t.color).scale("a",.5).toString(),i=r,s=t.bars.align=="left"?0:-t.bars.barWidth/2;p.lineWidth=t.bars.lineWidth,p.strokeStyle=r,tt(n[0],n[1],n[2]||0,s,s+t.bars.barWidth,0,function(){return i},t.xaxis,t.yaxis,p,t.bars.horizontal,t.bars.lineWidth)}function bt(t,n,r,i){if(typeof t=="string")return t;var s=h.createLinearGradient(0,r,0,n);for(var o=0,u=t.colors.length;o<u;++o){var a=t.colors[o];if(typeof a!="string"){var f=e.color.parse(i);a.brightness!=null&&(f=f.scale("rgb",a.brightness)),a.opacity!=null&&(f.a*=a.opacity),a=f.toString()}s.addColorStop(o/(u-1),a)}return s}var u=[],a={colors:["#edc240","#afd8f8","#cb4b4b","#4da74d","#9440ed"],legend:{show:!0,noColumns:1,labelFormatter:null,labelBoxBorderColor:"#ccc",container:null,position:"ne",margin:5,backgroundColor:null,backgroundOpacity:.85,sorted:null},xaxis:{show:null,position:"bottom",mode:null,font:null,color:null,tickColor:null,transform:null,inverseTransform:null,min:null,max:null,autoscaleMargin:null,ticks:null,tickFormatter:null,labelWidth:null,labelHeight:null,reserveSpace:null,tickLength:null,alignTicksWithAxis:null,tickDecimals:null,tickSize:null,minTickSize:null},yaxis:{autoscaleMargin:.02,position:"left"},xaxes:[],yaxes:[],series:{points:{show:!1,radius:3,lineWidth:2,fill:!0,fillColor:"#ffffff",symbol:"circle"},lines:{lineWidth:2,fill:!1,fillColor:null,steps:!1},bars:{show:!1,lineWidth:2,barWidth:1,fill:!0,fillColor:null,align:"left",horizontal:!1,zero:!0},shadowSize:3,highlightColor:null},grid:{show:!0,aboveData:!1,color:"#545454",backgroundColor:null,borderColor:null,tickColor:null,margin:0,labelMargin:5,axisMargin:8,borderWidth:2,minBorderMargin:null,markings:null,markingsColor:"#f4f4f4",markingsLineWidth:2,clickable:!1,hoverable:!1,autoHighlight:!0,mouseActiveRadius:10},interaction:{redrawOverlayInterval:1e3/60},hooks:{}},f=null,l=null,c=null,h=null,p=null,d=[],v=[],m={left:0,right:0,top:0,bottom
+:0},g=0,y=0,b={processOptions:[],processRawData:[],processDatapoints:[],processOffset:[],drawBackground:[],drawSeries:[],draw:[],bindEvents:[],drawOverlay:[],shutdown:[]},w=this;w.setData=T,w.setupGrid=R,w.draw=V,w.getPlaceholder=function(){return t},w.getCanvas=function(){return f.element},w.getPlotOffset=function(){return m},w.width=function(){return g},w.height=function(){return y},w.offset=function(){var e=c.offset();return e.left+=m.left,e.top+=m.top,e},w.getData=function(){return u},w.getAxes=function(){var t={},n;return e.each(d.concat(v),function(e,n){n&&(t[n.direction+(n.n!=1?n.n:"")+"axis"]=n)}),t},w.getXAxes=function(){return d},w.getYAxes=function(){return v},w.c2p=L,w.p2c=A,w.getOptions=function(){return a},w.highlight=dt,w.unhighlight=vt,w.triggerRedrawOverlay=ht,w.pointOffset=function(e){return{left:parseInt(d[C(e,"x")-1].p2c(+e.x)+m.left,10),top:parseInt(v[C(e,"y")-1].p2c(+e.y)+m.top,10)}},w.shutdown=H,w.resize=function(){var e=t.width(),n=t.height();f.resize(e,n),l.resize(e,n)},w.hooks=b,S(w),x(s),D(),T(r),R(),V(),P();var st=[],ot=null}function i(e,t){return t*Math.floor(e/t)}var t=Object.prototype.hasOwnProperty;n.prototype.resize=function(e,t){if(e<=0||t<=0)throw new Error("Invalid dimensions for plot, width = "+e+", height = "+t);var n=this.element,r=this.context,i=this.pixelRatio;this.width!=e&&(n.width=e*i,n.style.width=e+"px",this.width=e),this.height!=t&&(n.height=t*i,n.style.height=t+"px",this.height=t),r.restore(),r.save(),r.scale(i,i)},n.prototype.clear=function(){this.context.clearRect(0,0,this.width,this.height)},n.prototype.render=function(){var e=this._textCache;for(var n in e)if(t.call(e,n)){var r=this.getTextLayer(n),i=e[n];r.hide();for(var s in i)if(t.call(i,s)){var o=i[s];for(var u in o)if(t.call(o,u)){var a=o[u].positions;for(var f=0,l;l=a[f];f++)l.active?l.rendered||(r.append(l.element),l.rendered=!0):(a.splice(f--,1),l.rendered&&l.element.detach());a.length==0&&delete o[u]}}r.show()}},n.prototype.getTextLayer=function(t){var n=this.text[t];return n==null&&(this.textContainer==null&&(this.textContainer=e("<div class='flot-text'></div>").css({position:"absolute",top:0,left:0,bottom:0,right:0,"font-size":"smaller",color:"#545454"}).insertAfter(this.element)),n=this.text[t]=e("<div></div>").addClass(t).css({position:"absolute",top:0,left:0,bottom:0,right:0}).appendTo(this.textContainer)),n},n.prototype.getTextInfo=function(t,n,r,i,s){var o,u,a,f;n=""+n,typeof r=="object"?o=r.style+" "+r.variant+" "+r.weight+" "+r.size+"px/"+r.lineHeight+"px "+r.family:o=r,u=this._textCache[t],u==null&&(u=this._textCache[t]={}),a=u[o],a==null&&(a=u[o]={}),f=a[n];if(f==null){var l=e("<div></div>").html(n).css({position:"absolute","max-width":s,top:-9999}).appendTo(this.getTextLayer(t));typeof r=="object"?l.css({font:o,color:r.color}):typeof r=="string"&&l.addClass(r),f=a[n]={width:l.outerWidth(!0),height:l.outerHeight(!0),element:l,positions:[]},l.detach()}return f},n.prototype.addText=function(e,t,n,r,i,s,o,u,a){var f=this.getTextInfo(e,r,i,s,o),l=f.positions;u=="center"?t-=f.width/2:u=="right"&&(t-=f.width),a=="middle"?n-=f.height/2:a=="bottom"&&(n-=f.height);for(var c=0,h;h=l[c];c++)if(h.x==t&&h.y==n){h.active=!0;return}h={active:!0,rendered:!1,element:l.length?f.element.clone():f.element,x:t,y:n},l.push(h),h.element.css({top:Math.round(n),left:Math.round(t),"text-align":u})},n.prototype.removeText=function(e,n,r,i,s,o){if(i==null){var u=this._textCache[e];if(u!=null)for(var a in u)if(t.call(u,a)){var f=u[a];for(var l in f)if(t.call(f,l)){var c=f[l].positions;for(var h=0,p;p=c[h];h++)p.active=!1}}}else{var c=this.getTextInfo(e,i,s,o).positions;for(var h=0,p;p=c[h];h++)p.x==n&&p.y==r&&(p.active=!1)}},e.plot=function(t,n,i){var s=new r(e(t),n,i,e.plot.plugins);return s},e.plot.version="0.8.1",e.plot.plugins=[],e.fn.plot=function(t,n){return this.each(function(){e.plot(this,t,n)})}}(jQuery);
\ No newline at end of file
diff --git a/tools/telemetry/unittest_data/webview_app/background.js b/tools/telemetry/unittest_data/webview_app/background.js
new file mode 100644
index 0000000..5f284a8
--- /dev/null
+++ b/tools/telemetry/unittest_data/webview_app/background.js
@@ -0,0 +1,5 @@
+// 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.window.create('main.html');
diff --git a/tools/telemetry/unittest_data/webview_app/main.html b/tools/telemetry/unittest_data/webview_app/main.html
new file mode 100644
index 0000000..0294246
--- /dev/null
+++ b/tools/telemetry/unittest_data/webview_app/main.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+This is the simple telemetry webapp main page with a &lt;webview&gt; element.
+<webview id="foo" src="data:text/html;charset=utf-8,<html><body><input id='test_input_id' type='text'></body></html>" style="width:640px; height:480px" autosize="on" minwidth="576" minheight="432">
+</webview>
+</body>
+</html>
diff --git a/tools/telemetry/unittest_data/webview_app/manifest.json b/tools/telemetry/unittest_data/webview_app/manifest.json
new file mode 100644
index 0000000..b24438e
--- /dev/null
+++ b/tools/telemetry/unittest_data/webview_app/manifest.json
@@ -0,0 +1,14 @@
+{
+  "description": "Simple Telemetry Test WebApp Containing <webview> Element",
+  "name": "Simple <webview> Telemetry Test WebApp",
+  "app": {
+    "background": {
+      "scripts": ["background.js"]
+    }
+  },
+  "permissions": [
+    "webview"
+  ],
+  "manifest_version": 2,
+  "version": "1.0"
+}
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt
index 2faa716..28e73ca5 100644
--- a/tools/valgrind/drmemory/suppressions.txt
+++ b/tools/valgrind/drmemory/suppressions.txt
@@ -571,18 +571,6 @@
 *!media::AudioDeviceThread::Thread::Run
 *!media::AudioDeviceThread::Thread::ThreadMain
 
-HANDLE LEAK
-name=http://crbug.com/383408
-system call NtCreateEvent
-...
-*!base::internal::LockImpl::Lock
-*!mojo::system::MessagePipe::RemoveWaiter
-*!mojo::system::MessagePipeDispatcher::RemoveWaiterImplNoLock
-*!mojo::system::Dispatcher::RemoveWaiter
-*!mojo::system::Core::WaitManyInternal
-*!mojo::system::Core::WaitMany
-*!MojoWaitMany
-
 UNADDRESSABLE ACCESS
 name=IntentionalCrashPluginTest.plugin_client.cc
 npapi_test_plugin.dll!NP_Initialize
@@ -781,8 +769,6 @@
 HANDLE LEAK
 name=http://crbug.com/487500
 system call NtCreateEvent
-...
-v8.dll!v8::base::Mutex::Lock
-base.dll!base::`anonymous namespace'::WorkItemCallback
-ntdll.dll!vsnprintf
-ntdll.dll!TpCallbackIndependent
+ntdll.dll!RtlDosPathNameToNtPathName_U_WithStatus
+ntdll.dll!RtlDosPathNameToNtPathName_U_WithStatus
+ntdll.dll!RtlIntegerToUnicodeString
diff --git a/tools/valgrind/drmemory/suppressions_full.txt b/tools/valgrind/drmemory/suppressions_full.txt
index b4cb03b..ce7802b 100644
--- a/tools/valgrind/drmemory/suppressions_full.txt
+++ b/tools/valgrind/drmemory/suppressions_full.txt
@@ -1033,46 +1033,6 @@
 ...
 *!base::LazyInstance*::Pointer
 
-LEAK
-name=http://crbug.com/79933 (2)
-...
-*!TestURLRequestContext::TestURLRequestContext
-*!TestURLRequestContextGetter::GetURLRequestContext
-*!notifier::SingleLoginAttempt::SingleLoginAttempt
-*!notifier::Login::StartConnection
-*!syncer::InvalidationNotifier::UpdateCredentials
-*!syncer::NonBlockingInvalidationNotifier::Core::UpdateCredentials
-
-LEAK
-name=http://crbug.com/79933 (3)
-...
-*!TestURLRequestContext::TestURLRequestContext
-*!TestURLRequestContextGetter::GetURLRequestContext
-*!URLFetcher::Core::StartURLRequest
-
-LEAK
-name=http://crbug.com/79933 (4)
-*!generic_cpp_alloc
-*!operator new
-*!std::_Allocate<>
-*!std::allocator<>::allocate
-*!std::vector<>::_Insert_n
-*!std::vector<>::insert
-*!std::vector<>::push_back
-*!base::ObserverListBase<>::AddObserver
-...
-*!net::HttpNetworkSession::HttpNetworkSession
-*!notifier::ProxyResolvingClientSocket::ProxyResolvingClientSocket
-*!notifier::XmppClientSocketFactory::CreateTransportClientSocket
-*!notifier::ChromeAsyncSocket::Connect
-*!buzz::XmppClient::ProcessStartXmppLogin
-*!buzz::XmppClient::Process
-*!talk_base::Task::Step
-*!talk_base::TaskRunner::InternalRunTasks
-*!talk_base::TaskRunner::RunTasks
-*!notifier::TaskPump::CheckAndRunTasks
-*!base::internal::RunnableAdapter<>::Run
-
 # Test intentionally leaks an object.
 LEAK
 name=http://crbug.com/86301
@@ -1094,6 +1054,13 @@
 ...
 *!testing::*::PrintBytesInObjectTo*
 
+# This is an EXPECT_DEATH() that hits a RELEASE_ASSERT(),
+# which intentionally writes to NULL in order to crash.
+UNADDRESSABLE ACCESS
+name=https://crbug.com/497344
+blink_platform.dll!blink::SecurityOrigin::addSuborigin
+*!blink::SecurityOriginTest_Suborigins_Test::TestBody
+
 ###############################################################
 # Proactively borrowed from memcheck/suppressions.txt.
 # We have not yet seen these, but we are expanding the sets of tests
@@ -1507,40 +1474,6 @@
 ...
 *!GenericInfoViewTest_GenericInfoView_Test::TestBody
 
-LEAK
-name=http://crbug.com/117427 a
-...
-*!net::HostCache::Set
-*!net::HostResolverImpl::CacheResult
-*!net::HostResolverImpl::Job::CompleteRequests
-*!net::HostResolverImpl::Job::OnProcTaskComplete
-*!base::internal::RunnableAdapter<>::Run
-
-# Probably related to 117427.  Someone is not tearing down DNS resolution during
-# testing.
-LEAK
-name=http://crbug.com/117427 b
-*!generic_cpp_alloc
-*!operator new
-*!base::internal::WeakReferenceOwner::GetRef
-*!base::SupportsWeakPtr<>::AsWeakPtr
-*!net::HostResolverImpl::Job::Job
-*!net::HostResolverImpl::Resolve
-*!net::SingleRequestHostResolver::Resolve
-*!net::TransportConnectJob::DoResolveHost
-*!net::TransportConnectJob::DoLoop
-*!net::TransportConnectJob::ConnectInternal
-*!net::ConnectJob::Connect
-*!net::internal::ClientSocketPoolBaseHelper::RequestSocketInternal
-*!net::internal::ClientSocketPoolBaseHelper::RequestSocket
-*!net::ClientSocketPoolBase<>::RequestSocket
-*!net::TransportClientSocketPool::RequestSocket
-*!net::ClientSocketHandle::Init<>
-*!net::`anonymous namespace'::InitSocketPoolHelper
-*!net::InitSocketHandleForRawConnect
-*!notifier::ProxyResolvingClientSocket::ProcessProxyResolveDone
-*!base::internal::RunnableAdapter<>::Run
-
 # IE frame possible leak of COM object.
 LEAK
 name=http://crbug.com/122399
@@ -1844,9 +1777,7 @@
 KERNEL32.dll!CreateWaitableTimerW
 content.dll!rtc::Timing::Timing
 content.dll!content::RenderProcessHostImpl::CreateMessageFilters
-...
-content.dll!content::RenderViewHostImpl::CreateRenderView
-content.dll!content::WebContentsImpl::CreateRenderViewForRenderManager
+content.dll!content::RenderProcessHostImpl::Init
 ...
 content.dll!content::NavigationControllerImpl::LoadEntry
 ...
diff --git a/tools/valgrind/gtest_exclude/media_unittests.gtest.txt b/tools/valgrind/gtest_exclude/media_unittests.gtest.txt
index 368398e..e369e57 100644
--- a/tools/valgrind/gtest_exclude/media_unittests.gtest.txt
+++ b/tools/valgrind/gtest_exclude/media_unittests.gtest.txt
@@ -5,6 +5,10 @@
 # Flaky under all Valgrind-based tools, see http://crbug.com/298771
 PipelineIntegrationTest.MediaSource_Opus_Seeking_WebM
 
+# Flaky under valgrind, http://crbug.com/492882
+PipelineIntegrationTest.BasicPlaybackHashed
+PipelineIntegrationTest.BasicPlaybackLive
+
 # crbug.com/409485, cannot revert due to git migration,
 # exclude the test now
 AudioInputTest.Record
diff --git a/tools/valgrind/gtest_exclude/remoting_unittests.gtest.txt b/tools/valgrind/gtest_exclude/remoting_unittests.gtest.txt
index c322014..4f136a9 100644
--- a/tools/valgrind/gtest_exclude/remoting_unittests.gtest.txt
+++ b/tools/valgrind/gtest_exclude/remoting_unittests.gtest.txt
@@ -1,2 +1,5 @@
 # http://crbug.com/241856
 VideoSchedulerTest.StartAndStop
+
+# https://crbug.com/496910
+BackoffTimer.Basic
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index c16c7946..f9634acc 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -2540,14 +2540,6 @@
   fun:*content*ScreenshotData*EncodeOnWorker*
 }
 {
-  bug_363819
-  Memcheck:Uninitialized
-  fun:strlen
-  fun:*
-  fun:_ZN3net12_GLOBAL__N_114TestHttpClient4ReadEPSs
-  fun:_ZN3net*HttpServerTest*
-}
-{
   bug_364274
   Memcheck:Uninitialized
   fun:_ZN5blink21RenderLayerCompositor14updateIfNeededEv
diff --git a/tools/vim/mojom/ftdetect/mojomfiletype.vim b/tools/vim/mojom/ftdetect/mojomfiletype.vim
new file mode 100644
index 0000000..cff7ce6
--- /dev/null
+++ b/tools/vim/mojom/ftdetect/mojomfiletype.vim
@@ -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.
+
+" We take care to preserve the user's fileencodings and fileformats,
+" because those settings are global (not buffer local), yet we want
+" to override them for loading mojom files, which should be UTF-8.
+
+let s:current_fileformats = ''
+let s:current_fileencodings = ''
+
+" define fileencodings to open as utf-8 encoding even if it's ascii.
+function! s:mojomfiletype_pre()
+  let s:current_fileformats = &g:fileformats
+  let s:current_fileencodings = &g:fileencodings
+  set fileencodings=utf-8 fileformats=unix
+  setlocal filetype=mojom
+endfunction
+
+" restore fileencodings as others
+function! s:mojomfiletype_post()
+  let &g:fileformats = s:current_fileformats
+  let &g:fileencodings = s:current_fileencodings
+endfunction
+
+au BufNewFile *.mojom setlocal filetype=mojom fileencoding=utf-8 fileformat=unix
+au BufRead *.mojom call s:mojomfiletype_pre()
+au BufReadPost *.mojom call s:mojomfiletype_post()
diff --git a/tools/vim/mojom.vim b/tools/vim/mojom/syntax/mojom.vim
similarity index 61%
rename from tools/vim/mojom.vim
rename to tools/vim/mojom/syntax/mojom.vim
index 76a0ee3..cdd3f7e7 100644
--- a/tools/vim/mojom.vim
+++ b/tools/vim/mojom/syntax/mojom.vim
@@ -1,23 +1,22 @@
+" 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.
+
 " Vim syntax file " Language: Mojom
 " To get syntax highlighting for .mojom files, add the following to your .vimrc
 " file:
-"     source /path/to/src/tools/vim/mojom.vim
+"     set runtimepath^=/path/to/src/tools/vim/mojom
 
-if !exists("g:main_syntax")
-  if version < 600
-    syntax clear
-  elseif exists("b:current_syntax")
-    finish
-  endif
-  let g:main_syntax = 'mojom'
-  syntax region mojomFold start="{" end="}" transparent fold
-endif
+syn case match
+
+syntax region mojomFold start="{" end="}" transparent fold
 
 " keyword definitions
-syntax keyword mojomType        bool int8 int16 int32 int64 uint8 uint16 uint32 uint64 float double
+syntax keyword mojomType        bool int8 int16 int32 int64 uint8 uint16 uint32 uint64 float double array
 syntax match mojomImport        "^\(import\)\s"
-syntax keyword mojomModule      module
-syntax keyword mojomKeyword     interface enum struct union
+syntax keyword mojomKeyword     const module interface enum struct union
+syntax match mojomOperator      /=>/
+syntax match mojomOperator      /?/
 
 " Comments
 syntax keyword mojomTodo           contained TODO FIXME XXX
@@ -26,6 +25,10 @@
 syntax match   mojomLineDocComment "///.*" contains=mojomTodo,mojomDocLink,@Spell
 syntax region  mojomDocLink        contained start=+\[+ end=+\]+
 
+" Strings
+syn region mojomString start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=@Spell
+hi def link mojomString            String
+
 " The default highlighting.
 highlight default link mojomTodo            Todo
 highlight default link mojomComment         Comment
@@ -35,10 +38,11 @@
 highlight default link mojomType            Type
 highlight default link mojomImport          Include
 highlight default link mojomKeyword         Keyword
+highlight default link mojomOperator        Operator
 
 let b:current_syntax = "mojom"
 let b:spell_options = "contained"
 
-if g:main_syntax is# 'mojom'
-  unlet g:main_syntax
-endif
+syn sync minlines=500
+
+let b:current_syntax = "mojom"
diff --git a/tools/vim/ninja-build.vim b/tools/vim/ninja-build.vim
index 6e14cba2..70e5a83 100644
--- a/tools/vim/ninja-build.vim
+++ b/tools/vim/ninja-build.vim
@@ -74,7 +74,11 @@
 fun! s:MakeWithCustomCommand(build_cmd)
   let l:oldmakepgr = &makeprg
   let &makeprg=a:build_cmd
-  silent make | cwindow
+  if exists(':Make') == 2
+    Make
+  else
+    silent make | cwindow
+  endif
   if !has('gui_running')
     redraw!
   endif
diff --git a/ui/accelerated_widget_mac/BUILD.gn b/ui/accelerated_widget_mac/BUILD.gn
index e95ef54..0c066dd 100644
--- a/ui/accelerated_widget_mac/BUILD.gn
+++ b/ui/accelerated_widget_mac/BUILD.gn
@@ -12,6 +12,8 @@
     "io_surface_context.mm",
     "io_surface_layer.h",
     "io_surface_layer.mm",
+    "io_surface_ns_gl_context.h",
+    "io_surface_ns_gl_context.mm",
     "io_surface_texture.h",
     "io_surface_texture.mm",
     "software_layer.h",
diff --git a/ui/accelerated_widget_mac/DEPS b/ui/accelerated_widget_mac/DEPS
index 32be787d..ae409b79 100644
--- a/ui/accelerated_widget_mac/DEPS
+++ b/ui/accelerated_widget_mac/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+third_party/skia",
   "+ui/base/cocoa",
+  "+ui/base",
   "+ui/events",
   "+ui/gfx/geometry",
   "+ui/gfx/native_widget_types.h",
diff --git a/ui/accelerated_widget_mac/accelerated_widget_mac.gyp b/ui/accelerated_widget_mac/accelerated_widget_mac.gyp
index f149d7c..d46b2e629 100644
--- a/ui/accelerated_widget_mac/accelerated_widget_mac.gyp
+++ b/ui/accelerated_widget_mac/accelerated_widget_mac.gyp
@@ -19,6 +19,8 @@
         'io_surface_context.mm',
         'io_surface_layer.h',
         'io_surface_layer.mm',
+        "io_surface_ns_gl_surface.h",
+        "io_surface_ns_gl_surface.mm",
         'io_surface_texture.h',
         'io_surface_texture.mm',
         'software_layer.h',
diff --git a/ui/accelerated_widget_mac/accelerated_widget_mac.h b/ui/accelerated_widget_mac/accelerated_widget_mac.h
index bf78433..d4646bf5 100644
--- a/ui/accelerated_widget_mac/accelerated_widget_mac.h
+++ b/ui/accelerated_widget_mac/accelerated_widget_mac.h
@@ -10,6 +10,7 @@
 
 #include "ui/accelerated_widget_mac/accelerated_widget_mac_export.h"
 #include "ui/events/latency_info.h"
+#include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/native_widget_types.h"
 
@@ -30,6 +31,7 @@
 namespace ui {
 
 class AcceleratedWidgetMac;
+class IOSurfaceNSGLSurface;
 
 // A class through which an AcceleratedWidget may be bound to draw the contents
 // of an NSView. An AcceleratedWidget may be bound to multiple different views
@@ -77,8 +79,9 @@
   void GotAcceleratedFrame(
       uint64 surface_handle,
       const std::vector<ui::LatencyInfo>& latency_info,
-      gfx::Size pixel_size,
+      const gfx::Size& pixel_size,
       float scale_factor,
+      const gfx::Rect& pixel_damage_rect,
       const base::Closure& drawn_callback);
 
   void GotSoftwareFrame(float scale_factor, SkCanvas* canvas);
@@ -89,11 +92,17 @@
   void IOSurfaceLayerDidDrawFrame() override;
   void IOSurfaceLayerHitError() override;
 
-  void GotAcceleratedCAContextFrame(
-      CAContextID ca_context_id, gfx::Size pixel_size, float scale_factor);
+  void GotAcceleratedCAContextFrame(CAContextID ca_context_id,
+                                    const gfx::Size& pixel_size,
+                                    float scale_factor);
 
-  void GotAcceleratedIOSurfaceFrame(
-      IOSurfaceID io_surface_id, gfx::Size pixel_size, float scale_factor);
+  void GotAcceleratedIOSurfaceFrame(IOSurfaceID io_surface_id,
+                                    const gfx::Size& pixel_size,
+                                    float scale_factor);
+
+  void GotAcceleratedIOSurfaceFrameNSGL(
+      IOSurfaceID io_surface_id, const gfx::Size& pixel_size,
+      float scale_factor, const gfx::Rect& pixel_damage_rect);
 
   void AcknowledgeAcceleratedFrame();
 
@@ -131,6 +140,9 @@
   // The locally drawn software layer.
   base::scoped_nsobject<SoftwareLayer> software_layer_;
 
+  // The locally drawn NSOpenGLContext.
+  scoped_ptr<IOSurfaceNSGLSurface> io_surface_ns_gl_surface_;
+
   // If an accelerated frame has come in which has not yet been drawn and acked
   // then this is the latency info and the callback to make when the frame is
   // drawn. If there is no such frame then the callback is null.
@@ -153,7 +165,9 @@
 void AcceleratedWidgetMacGotAcceleratedFrame(
     gfx::AcceleratedWidget widget, uint64 surface_handle,
     const std::vector<ui::LatencyInfo>& latency_info,
-    gfx::Size pixel_size, float scale_factor,
+    const gfx::Size& pixel_size,
+    float scale_factor,
+    const gfx::Rect& pixel_damage_rect,
     const base::Closure& drawn_callback,
     bool* disable_throttling, int* renderer_id);
 
diff --git a/ui/accelerated_widget_mac/accelerated_widget_mac.mm b/ui/accelerated_widget_mac/accelerated_widget_mac.mm
index f8cd0c4..19beee03 100644
--- a/ui/accelerated_widget_mac/accelerated_widget_mac.mm
+++ b/ui/accelerated_widget_mac/accelerated_widget_mac.mm
@@ -6,13 +6,16 @@
 
 #include <map>
 
+#include "base/command_line.h"
 #include "base/lazy_instance.h"
 #include "base/message_loop/message_loop.h"
 #include "base/trace_event/trace_event.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "ui/accelerated_widget_mac/io_surface_layer.h"
+#include "ui/accelerated_widget_mac/io_surface_ns_gl_surface.h"
 #include "ui/accelerated_widget_mac/surface_handle_types.h"
 #include "ui/base/cocoa/animation_utils.h"
+#include "ui/base/ui_base_switches.h"
 #include "ui/gfx/geometry/dip_util.h"
 #include "ui/gl/scoped_cgl.h"
 
@@ -94,6 +97,7 @@
   DestroyIOSurfaceLayer(io_surface_layer_);
   DestroyCAContextLayer(ca_context_layer_);
   DestroySoftwareLayer();
+  io_surface_ns_gl_surface_.reset();
 
   last_swap_size_dip_ = gfx::Size();
   view_ = NULL;
@@ -127,8 +131,14 @@
 void AcceleratedWidgetMac::GotAcceleratedFrame(
     uint64 surface_handle,
     const std::vector<ui::LatencyInfo>& latency_info,
-    gfx::Size pixel_size, float scale_factor,
+    const gfx::Size& pixel_size,
+    float scale_factor,
+    const gfx::Rect& pixel_damage_rect,
     const base::Closure& drawn_callback) {
+  static bool use_ns_gl_surfaces =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableNSGLSurfaces);
+
   // Record the surface and latency info to use when acknowledging this frame.
   DCHECK(accelerated_frame_drawn_callback_.is_null());
   accelerated_frame_drawn_callback_ = drawn_callback;
@@ -148,7 +158,12 @@
   switch (GetSurfaceHandleType(surface_handle)) {
     case kSurfaceHandleTypeIOSurface: {
       IOSurfaceID io_surface_id = IOSurfaceIDFromSurfaceHandle(surface_handle);
-      GotAcceleratedIOSurfaceFrame(io_surface_id, pixel_size, scale_factor);
+      if (use_ns_gl_surfaces) {
+        GotAcceleratedIOSurfaceFrameNSGL(
+            io_surface_id, pixel_size, scale_factor, pixel_damage_rect);
+      } else {
+        GotAcceleratedIOSurfaceFrame(io_surface_id, pixel_size, scale_factor);
+      }
       break;
     }
     case kSurfaceHandleTypeCAContext: {
@@ -164,7 +179,7 @@
 
 void AcceleratedWidgetMac::GotAcceleratedCAContextFrame(
     CAContextID ca_context_id,
-    gfx::Size pixel_size,
+    const gfx::Size& pixel_size,
     float scale_factor) {
   // In the layer is replaced, keep the old one around until after the new one
   // is installed to avoid flashes.
@@ -195,9 +210,30 @@
   DestroySoftwareLayer();
 }
 
+void AcceleratedWidgetMac::GotAcceleratedIOSurfaceFrameNSGL(
+    IOSurfaceID io_surface_id,
+    const gfx::Size& pixel_size,
+    float scale_factor,
+    const gfx::Rect& pixel_damage_rect) {
+  if (!io_surface_ns_gl_surface_) {
+    io_surface_ns_gl_surface_.reset(
+        IOSurfaceNSGLSurface::Create(view_->AcceleratedWidgetGetNSView()));
+  }
+
+  if (!io_surface_ns_gl_surface_) {
+    LOG(ERROR) << "Failed to create IOSurfaceNSGLSurface";
+    AcknowledgeAcceleratedFrame();
+    return;
+  }
+
+  io_surface_ns_gl_surface_->GotFrame(
+      io_surface_id, pixel_size, scale_factor, pixel_damage_rect);
+  AcknowledgeAcceleratedFrame();
+}
+
 void AcceleratedWidgetMac::GotAcceleratedIOSurfaceFrame(
     IOSurfaceID io_surface_id,
-    gfx::Size pixel_size,
+    const gfx::Size& pixel_size,
     float scale_factor) {
   // In the layer is replaced, keep the old one around until after the new one
   // is installed to avoid flashes.
@@ -359,14 +395,17 @@
 void AcceleratedWidgetMacGotAcceleratedFrame(
     gfx::AcceleratedWidget widget, uint64 surface_handle,
     const std::vector<ui::LatencyInfo>& latency_info,
-    gfx::Size pixel_size, float scale_factor,
+    const gfx::Size& pixel_size,
+    float scale_factor,
+    const gfx::Rect& pixel_damage_rect,
     const base::Closure& drawn_callback,
     bool* disable_throttling, int* renderer_id) {
   AcceleratedWidgetMac* accelerated_widget_mac =
       GetHelperFromAcceleratedWidget(widget);
   if (accelerated_widget_mac) {
     accelerated_widget_mac->GotAcceleratedFrame(
-        surface_handle, latency_info, pixel_size, scale_factor, drawn_callback);
+        surface_handle, latency_info, pixel_size, scale_factor,
+        pixel_damage_rect, drawn_callback);
     *disable_throttling =
         accelerated_widget_mac->IsRendererThrottlingDisabled();
     *renderer_id = accelerated_widget_mac->GetRendererID();
diff --git a/ui/accelerated_widget_mac/io_surface_ns_gl_surface.h b/ui/accelerated_widget_mac/io_surface_ns_gl_surface.h
new file mode 100644
index 0000000..7cfb4969
--- /dev/null
+++ b/ui/accelerated_widget_mac/io_surface_ns_gl_surface.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 UI_ACCELERATED_WIDGET_MAC_IO_SURFACE_NS_GL_SURFACE_H_
+#define UI_ACCELERATED_WIDGET_MAC_IO_SURFACE_NS_GL_SURFACE_H_
+
+#include <Cocoa/Cocoa.h>
+#include <OpenGL/OpenGL.h>
+
+#include "base/mac/scoped_nsobject.h"
+#include "ui/accelerated_widget_mac/io_surface_context.h"
+#include "ui/accelerated_widget_mac/io_surface_texture.h"
+
+namespace ui {
+
+class IOSurfaceNSGLSurface {
+ public:
+  static IOSurfaceNSGLSurface* Create(NSView* view);
+  ~IOSurfaceNSGLSurface();
+
+  // Called on the UI thread.
+  bool GotFrame(IOSurfaceID io_surface_id,
+                gfx::Size pixel_size,
+                float scale_factor,
+                gfx::Rect pixel_damage_rect);
+
+ private:
+  explicit IOSurfaceNSGLSurface(
+      NSView* view,
+      base::scoped_nsobject<NSOpenGLContext> ns_gl_context,
+      scoped_refptr<ui::IOSurfaceTexture> iosurface);
+  NSView* view_;
+  scoped_refptr<ui::IOSurfaceTexture> iosurface_;
+  base::scoped_nsobject<NSOpenGLContext> ns_gl_context_;
+};
+
+}  // namespace ui
+
+#endif  // UI_ACCELERATED_WIDGET_MAC_IO_SURFACE_NS_GL_SURFACE_H_
diff --git a/ui/accelerated_widget_mac/io_surface_ns_gl_surface.mm b/ui/accelerated_widget_mac/io_surface_ns_gl_surface.mm
new file mode 100644
index 0000000..68d00bdf
--- /dev/null
+++ b/ui/accelerated_widget_mac/io_surface_ns_gl_surface.mm
@@ -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 "ui/accelerated_widget_mac/io_surface_ns_gl_surface.h"
+
+#include <OpenGL/GL.h>
+
+#include "base/callback_helpers.h"
+#include "base/mac/bind_objc_block.h"
+#include "base/mac/sdk_forward_declarations.h"
+#include "ui/base/cocoa/animation_utils.h"
+#include "ui/gfx/geometry/dip_util.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gl/gpu_switching_manager.h"
+
+namespace ui {
+
+IOSurfaceNSGLSurface* IOSurfaceNSGLSurface::Create(NSView* view) {
+  scoped_refptr<IOSurfaceTexture> iosurface = IOSurfaceTexture::Create(false);
+  if (!iosurface)
+    return NULL;
+
+  std::vector<NSOpenGLPixelFormatAttribute> attribs;
+  attribs.push_back(NSOpenGLPFAColorSize);
+  attribs.push_back(24);
+  attribs.push_back(NSOpenGLPFAAlphaSize);
+  attribs.push_back(8);
+  attribs.push_back(NSOpenGLPFAAccelerated);
+  if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus())
+    attribs.push_back(NSOpenGLPFAAllowOfflineRenderers);
+  attribs.push_back(0);
+  base::scoped_nsobject<NSOpenGLPixelFormat> pixel_format(
+      [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs.front()]);
+  if (!pixel_format) {
+    LOG(ERROR) << "Failed to create pixel format object.";
+    return NULL;
+  }
+
+  base::scoped_nsobject<NSOpenGLContext> ns_gl_context(
+      [[NSOpenGLContext alloc] initWithFormat:pixel_format shareContext:nil]);
+  if (!ns_gl_context) {
+    LOG(ERROR) << "Failed to create context object.";
+    return NULL;
+  }
+
+  return new IOSurfaceNSGLSurface(view, ns_gl_context, iosurface);
+}
+
+IOSurfaceNSGLSurface::IOSurfaceNSGLSurface(
+    NSView* view,
+    base::scoped_nsobject<NSOpenGLContext> ns_gl_context,
+    scoped_refptr<ui::IOSurfaceTexture> iosurface)
+    : view_(view), iosurface_(iosurface), ns_gl_context_(ns_gl_context) {
+  [[view_ layer] setContentsGravity:kCAGravityTopLeft];
+  [ns_gl_context_ setView:view_];
+}
+
+IOSurfaceNSGLSurface::~IOSurfaceNSGLSurface() {
+  [ns_gl_context_ makeCurrentContext];
+  iosurface_ = NULL;
+  [NSOpenGLContext clearCurrentContext];
+  [ns_gl_context_ clearDrawable];
+}
+
+bool IOSurfaceNSGLSurface::GotFrame(IOSurfaceID io_surface_id,
+                                    gfx::Size frame_pixel_size,
+                                    float frame_scale_factor,
+                                    gfx::Rect pixel_damage_rect) {
+  // The OpenGL framebuffer's scale factor and pixel size are updated to match
+  // the CALayer's contentsScale and bounds at setView. The pixel size is the
+  // stored in the GL_VIEWPORT state of the context.
+  gfx::Size contents_pixel_size;
+  float contents_scale_factor = [[view_ layer] contentsScale];
+  {
+    [ns_gl_context_ makeCurrentContext];
+    GLint viewport[4];
+    glGetIntegerv(GL_VIEWPORT, viewport);
+    [NSOpenGLContext clearCurrentContext];
+    contents_pixel_size = gfx::Size(viewport[2], viewport[3]);
+  }
+
+  // If the OpenGL framebuffer does not match the frame in scale factor or
+  // pixel size, then re-latch them. Note that they will latch to the layer's
+  // bounds, which will not necessarily match the frame's pixel size.
+  bool full_damage = false;
+  if (frame_pixel_size != contents_pixel_size ||
+      frame_scale_factor != contents_scale_factor) {
+    ScopedCAActionDisabler disabler;
+    [ns_gl_context_ clearDrawable];
+    [[view_ layer] setContentsScale:frame_scale_factor];
+    [ns_gl_context_ setView:view_];
+
+    // The front buffer may have been destroyed at re-creation, so re-draw
+    // everything.
+    full_damage = true;
+  }
+
+  bool result = true;
+  [ns_gl_context_ makeCurrentContext];
+  result &= iosurface_->SetIOSurface(io_surface_id, frame_pixel_size);
+  if (full_damage)
+    result &= iosurface_->DrawIOSurface();
+  else
+    result &= iosurface_->DrawIOSurfaceWithDamageRect(pixel_damage_rect);
+  glFlush();
+  [NSOpenGLContext clearCurrentContext];
+  return result;
+}
+
+};
diff --git a/ui/accelerated_widget_mac/io_surface_texture.h b/ui/accelerated_widget_mac/io_surface_texture.h
index 473e69cb..2cdd235 100644
--- a/ui/accelerated_widget_mac/io_surface_texture.h
+++ b/ui/accelerated_widget_mac/io_surface_texture.h
@@ -40,7 +40,6 @@
 class IOSurfaceTexture
     : public base::RefCounted<IOSurfaceTexture> {
  public:
-  // Returns NULL if IOSurfaceTexture or GL API calls fail.
   static scoped_refptr<IOSurfaceTexture> Create(
       bool needs_gl_finish_workaround);
 
@@ -54,6 +53,7 @@
   // larger than the IOSurface, the remaining right and bottom edges will be
   // white. |window_scale_factor| is 1 in normal views, 2 in HiDPI views.
   bool DrawIOSurface() WARN_UNUSED_RESULT;
+  bool DrawIOSurfaceWithDamageRect(gfx::Rect damage_rect) WARN_UNUSED_RESULT;
 
   // Returns true if the offscreen context used by this surface has been
   // poisoned.
@@ -67,6 +67,10 @@
       bool needs_gl_finish_workaround);
   ~IOSurfaceTexture();
 
+  // Draw the sepecified rect of the IOSurface. If |draw_boundary| is true,
+  // clear any overflow regions with white.
+  bool DrawIOSurfaceInternal(gfx::Rect damage_rect, bool draw_boundary);
+
   // Unref the IOSurfaceTexture and delete the associated GL texture. If the GPU
   // process is no longer referencing it, this will delete the IOSurface.
   void ReleaseIOSurfaceAndTexture();
diff --git a/ui/accelerated_widget_mac/io_surface_texture.mm b/ui/accelerated_widget_mac/io_surface_texture.mm
index 4ac7792..d3898a4 100644
--- a/ui/accelerated_widget_mac/io_surface_texture.mm
+++ b/ui/accelerated_widget_mac/io_surface_texture.mm
@@ -12,6 +12,7 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback_helpers.h"
+#include "base/command_line.h"
 #include "base/logging.h"
 #include "base/mac/bind_objc_block.h"
 #include "base/message_loop/message_loop.h"
@@ -19,6 +20,7 @@
 #include "base/trace_event/trace_event.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/accelerated_widget_mac/io_surface_context.h"
+#include "ui/base/ui_base_switches.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gl/gl_context.h"
@@ -28,14 +30,18 @@
 // static
 scoped_refptr<IOSurfaceTexture> IOSurfaceTexture::Create(
     bool needs_gl_finish_workaround) {
-  scoped_refptr<IOSurfaceContext> offscreen_context =
-      IOSurfaceContext::Get(
-          IOSurfaceContext::kOffscreenContext);
-  if (!offscreen_context.get()) {
-    LOG(ERROR) << "Failed to create context for offscreen operations";
-    return NULL;
+  static bool use_ns_gl_surfaces =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableNSGLSurfaces);
+  scoped_refptr<IOSurfaceContext> offscreen_context;
+  if (!use_ns_gl_surfaces) {
+    offscreen_context = IOSurfaceContext::Get(
+        IOSurfaceContext::kOffscreenContext);
+    if (!offscreen_context.get()) {
+      LOG(ERROR) << "Failed to create context for offscreen operations";
+      return NULL;
+    }
   }
-
   return new IOSurfaceTexture(offscreen_context, needs_gl_finish_workaround);
 }
 
@@ -48,7 +54,6 @@
       eviction_queue_iterator_(eviction_queue_.Get().end()),
       eviction_has_been_drawn_since_updated_(false),
       needs_gl_finish_workaround_(needs_gl_finish_workaround) {
-  CHECK(offscreen_context_.get());
 }
 
 IOSurfaceTexture::~IOSurfaceTexture() {
@@ -58,7 +63,17 @@
 }
 
 bool IOSurfaceTexture::DrawIOSurface() {
-  TRACE_EVENT0("browser", "IOSurfaceTexture::DrawIOSurface");
+  return DrawIOSurfaceInternal(gfx::Rect(pixel_size_), true);
+}
+
+bool IOSurfaceTexture::DrawIOSurfaceWithDamageRect(gfx::Rect damage_rect) {
+  return DrawIOSurfaceInternal(damage_rect, false);
+}
+
+bool IOSurfaceTexture::DrawIOSurfaceInternal(
+    gfx::Rect damage_rect, bool draw_boundary) {
+  TRACE_EVENT0("browser", "IOSurfaceTexture::DrawIOSurfaceInternal");
+  DCHECK(CGLGetCurrentContext());
 
   // If we have release the IOSurface, clear the screen to light grey and
   // early-out.
@@ -73,12 +88,13 @@
   GLint viewport[4];
   glGetIntegerv(GL_VIEWPORT, viewport);
   gfx::Rect viewport_rect(viewport[0], viewport[1], viewport[2], viewport[3]);
-  DCHECK_EQ(pixel_size_.ToString(), viewport_rect.size().ToString());
 
   // Set the projection matrix to match 1 unit to 1 pixel.
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
-  glOrtho(0, viewport_rect.width(), 0, viewport_rect.height(), -1, 1);
+  glOrtho(0, viewport_rect.width(),
+          pixel_size_.height() - viewport_rect.height(), pixel_size_.height(),
+          -1, 1);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
 
@@ -87,14 +103,14 @@
   glEnable(GL_TEXTURE_RECTANGLE_ARB);
   glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
   glBegin(GL_QUADS);
-  glTexCoord2f(0, 0);
-  glVertex2f(0, 0);
-  glTexCoord2f(pixel_size_.width(), 0);
-  glVertex2f(pixel_size_.width(), 0);
-  glTexCoord2f(pixel_size_.width(), pixel_size_.height());
-  glVertex2f(pixel_size_.width(), pixel_size_.height());
-  glTexCoord2f(0, pixel_size_.height());
-  glVertex2f(0, pixel_size_.height());
+  glTexCoord2f(damage_rect.x(), damage_rect.y());
+  glVertex2f(damage_rect.x(), damage_rect.y());
+  glTexCoord2f(damage_rect.right(), damage_rect.y());
+  glVertex2f(damage_rect.right(), damage_rect.y());
+  glTexCoord2f(damage_rect.right(), damage_rect.bottom());
+  glVertex2f(damage_rect.right(), damage_rect.bottom());
+  glTexCoord2f(damage_rect.x(), damage_rect.bottom());
+  glVertex2f(damage_rect.x(), damage_rect.bottom());
   glEnd();
   glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
   glDisable(GL_TEXTURE_RECTANGLE_ARB);
@@ -105,6 +121,28 @@
   glBegin(GL_TRIANGLES);
   glEnd();
 
+  // If the viewport is larger than the texture, clear out the overflow to
+  // white.
+  if (draw_boundary) {
+    if (pixel_size_.width() < viewport_rect.width()) {
+      glBegin(GL_QUADS);
+      glVertex2f(pixel_size_.width(), 0);
+      glVertex2f(pixel_size_.width(), viewport_rect.height());
+      glVertex2f(viewport_rect.width(), viewport_rect.height());
+      glVertex2f(viewport_rect.width(), 0);
+      glEnd();
+    }
+    if (pixel_size_.height() < viewport_rect.height()) {
+      int non_surface_height = viewport_rect.height() - pixel_size_.height();
+      glBegin(GL_QUADS);
+      glVertex2f(0, 0);
+      glVertex2f(0, non_surface_height);
+      glVertex2f(pixel_size_.width(), non_surface_height);
+      glVertex2f(pixel_size_.width(), 0);
+      glEnd();
+    }
+  }
+
   if (needs_gl_finish_workaround_) {
     TRACE_EVENT0("gpu", "glFinish");
     glFinish();
@@ -165,8 +203,14 @@
   // Create the GL texture and set it to be backed by the IOSurface.
   CGLError cgl_error = kCGLNoError;
   {
-    gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
-        offscreen_context_->cgl_context());
+    scoped_ptr<gfx::ScopedCGLSetCurrentContext> scoped_set_current_context;
+    if (offscreen_context_) {
+      scoped_set_current_context.reset(new gfx::ScopedCGLSetCurrentContext(
+          offscreen_context_->cgl_context()));
+    } else {
+      DCHECK(CGLGetCurrentContext());
+    }
+
     glGenTextures(1, &texture_);
     glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
     glTexParameterf(
@@ -174,7 +218,7 @@
     glTexParameterf(
         GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     cgl_error = CGLTexImageIOSurface2D(
-        offscreen_context_->cgl_context(),
+        CGLGetCurrentContext(),
         GL_TEXTURE_RECTANGLE_ARB,
         GL_RGBA,
         rounded_size.width(),
@@ -202,8 +246,13 @@
 }
 
 void IOSurfaceTexture::ReleaseIOSurfaceAndTexture() {
-  gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
-      offscreen_context_->cgl_context());
+  scoped_ptr<gfx::ScopedCGLSetCurrentContext> scoped_set_current_context;
+  if (offscreen_context_) {
+    scoped_set_current_context.reset(new gfx::ScopedCGLSetCurrentContext(
+        offscreen_context_->cgl_context()));
+  } else {
+    DCHECK(CGLGetCurrentContext());
+  }
 
   if (texture_) {
     glDeleteTextures(1, &texture_);
@@ -216,7 +265,9 @@
 }
 
 bool IOSurfaceTexture::HasBeenPoisoned() const {
-  return offscreen_context_->HasBeenPoisoned();
+  if (offscreen_context_)
+    return offscreen_context_->HasBeenPoisoned();
+  return false;
 }
 
 GLenum IOSurfaceTexture::GetAndSaveGLError() {
@@ -274,6 +325,11 @@
     if (!surface->eviction_has_been_drawn_since_updated_)
       continue;
 
+    // Don't evict anything that doesn't have an offscreen context (as we have
+    // context in which to delete the texture).
+    if (!surface->offscreen_context_)
+      continue;
+
     // Evict the surface.
     surface->ReleaseIOSurfaceAndTexture();
   }
diff --git a/ui/accessibility/extensions/colorenhancer/src/cvd.js b/ui/accessibility/extensions/colorenhancer/src/cvd.js
index 7b12e3e..1bf7daa6 100644
--- a/ui/accessibility/extensions/colorenhancer/src/cvd.js
+++ b/ui/accessibility/extensions/colorenhancer/src/cvd.js
@@ -2,448 +2,446 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// ======= Global state =======
-
-var curDelta = 0;
-var curSeverity = 0;
-var curType = 'PROTANOMALY';
-var curSimulate = false;
-var curEnable = false;
-var curFilter = 0;
-
-
-// ======= 3x3 matrix ops =======
-
-/**
- * The 3x3 identity matrix.
- * @const {object}
- */
-var IDENTITY_MATRIX_3x3 = [
-  [1, 0, 0],
-  [0, 1, 0],
-  [0, 0, 1]
-];
-
-
-/**
- * Adds two matrices.
- * @param {!object} m1 A 3x3 matrix.
- * @param {!object} m2 A 3x3 matrix.
- * @return {!object} The 3x3 matrix m1 + m2.
- */
-function add3x3(m1, m2) {
-  var result = [];
-  for (var i = 0; i < 3; i++) {
-    result[i] = [];
-    for (var j = 0; j < 3; j++) {
-      result[i].push(m1[i][j] + m2[i][j]);
-    }
-  }
-  return result;
-}
-
-
-/**
- * Subtracts one matrix from another.
- * @param {!object} m1 A 3x3 matrix.
- * @param {!object} m2 A 3x3 matrix.
- * @return {!object} The 3x3 matrix m1 - m2.
- */
-function sub3x3(m1, m2) {
-  var result = [];
-  for (var i = 0; i < 3; i++) {
-    result[i] = [];
-    for (var j = 0; j < 3; j++) {
-      result[i].push(m1[i][j] - m2[i][j]);
-    }
-  }
-  return result;
-}
-
-
-/**
- * Multiplies one matrix with another.
- * @param {!object} m1 A 3x3 matrix.
- * @param {!object} m2 A 3x3 matrix.
- * @return {!object} The 3x3 matrix m1 * m2.
- */
-function mul3x3(m1, m2) {
-  var result = [];
-  for (var i = 0; i < 3; i++) {
-    result[i] = [];
-    for (var j = 0; j < 3; j++) {
-      var sum = 0;
-      for (var k = 0; k < 3; k++) {
-        sum += m1[i][k] * m2[k][j];
-      }
-      result[i].push(sum);
-    }
-  }
-  return result;
-}
-
-
-/**
- * Multiplies a matrix with a number.
- * @param {!object} m A 3x3 matrix.
- * @param {!number} k A scalar multiplier.
- * @return {!object} The 3x3 matrix m * k.
- */
-function mul3x3Scalar(m, k) {
-  var result = [];
-  for (var i = 0; i < 3; i++) {
-    result[i] = [];
-    for (var j = 0; j < 3; j++) {
-      result[i].push(k * m[i][j]);
-    }
-  }
-  return result;
-}
-
-
-// ======= 3x3 matrix utils =======
-
-/**
- * Makes the SVG matrix string (of 20 values) for a given matrix.
- * @param {!object} m A 3x3 matrix.
- * @return {!string} The SVG matrix string for m.
- */
-function svgMatrixStringFrom3x3(m) {
-  var outputRows = [];
-  for (var i = 0; i < 3; i++) {
-    outputRows.push(m[i].join(' ') + ' 0 0');
-  }
-  // Add the alpha row
-  outputRows.push('0 0 0 1 0');
-  return outputRows.join(' ');
-}
-
-
-/**
- * Makes a human readable string for a given matrix.
- * @param {!object} m A 3x3 matrix.
- * @return {!string} A human-readable string for m.
- */
-function humanReadbleStringFrom3x3(m) {
-    var result = '';
-    for (var i = 0; i < 3; i++) {
-        result += (i ? ', ' : '') + '[';
-        for (var j = 0; j < 3; j++) {
-            result += (j ? ', ' : '') + m[i][j].toFixed(2);
-        }
-        result += ']';
-    }
-    return result;
-}
-
-
-// ======= CVD parameters =======
-/**
- * Parameters for simulating color vision deficiency.
- * Source:
- *     http://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/CVD_Simulation.html
- * Original Research Paper:
- *     http://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/Machado_Oliveira_Fernandes_CVD_Vis2009_final.pdf
- *
- * @enum {string}
- */
-var cvdSimulationParams = {
-  PROTANOMALY: [
-    [0.4720, -1.2946, 0.9857],
-    [-0.6128, 1.6326, 0.0187],
-    [0.1407, -0.3380, -0.0044],
-    [-0.1420, 0.2488, 0.0044],
-    [0.1872, -0.3908, 0.9942],
-    [-0.0451, 0.1420, 0.0013],
-    [0.0222, -0.0253, -0.0004],
-    [-0.0290, -0.0201, 0.0006],
-    [0.0068, 0.0454, 0.9990]
-  ],
-  DEUTERANOMALY: [
-    [0.5442, -1.1454, 0.9818],
-    [-0.7091, 1.5287, 0.0238],
-    [0.1650, -0.3833, -0.0055],
-    [-0.1664, 0.4368, 0.0056],
-    [0.2178, -0.5327, 0.9927],
-    [-0.0514, 0.0958, 0.0017],
-    [0.0180, -0.0288, -0.0006],
-    [-0.0232, -0.0649, 0.0007],
-    [0.0052, 0.0360, 0.9998]
-  ],
-  TRITANOMALY: [
-    [0.4275, -0.0181, 0.9307],
-    [-0.2454, 0.0013, 0.0827],
-    [-0.1821, 0.0168, -0.0134],
-    [-0.1280, 0.0047, 0.0202],
-    [0.0233, -0.0398, 0.9728],
-    [0.1048, 0.0352, 0.0070],
-    [-0.0156, 0.0061, 0.0071],
-    [0.3841, 0.2947, 0.0151],
-    [-0.3685, -0.3008, 0.9778]
-  ]
-};
-
-
-// TODO(mustaq): This should be nuked, see getCvdCorrectionMatrix().
-var cvdCorrectionParams = {
-  PROTANOMALY: {
-    addendum: [
-      [0.0, 0.0, 0.0],
-      [0.7, 1.0, 0.0],
-      [0.7, 0.0, 1.0]
-    ],
-    delta_factor: [
-      [0.0, 0.0, 0.0],
-      [0.3, 0.0, 0.0],
-      [-0.3, 0.0, 0.0]
-    ]
-  },
-  DEUTERANOMALY: {
-    addendum: [
-      [0.0, 0.0, 0.0],
-      [0.7, 1.0, 0.0],
-      [0.7, 0.0, 1.0]
-    ],
-    delta_factor: [
-      [0.0, 0.0, 0.0],
-      [0.3, 0.0, 0.0],
-      [-0.3, 0.0, 0.0]
-    ]
-  },
-  TRITANOMALY: {
-    addendum: [
-      [1.0, 0.0, 0.7],
-      [0.0, 1.0, 0.7],
-      [0.0, 0.0, 0.0]
-    ],
-    delta_factor: [
-      [0.0, 0.0, 0.3],
-      [0.0, 0.0, -0.3],
-      [0.0, 0.0, 0.0]
-    ]
-  }
-};
-
-
-// =======  CVD matrix builders =======
-
-/**
- * Returns a 3x3 matrix for simulating the given type of CVD with the given
- * severity.
- * @param {string} cvdType Type of CVD, either "PROTANOMALY" or "DEUTERANOMALY"
- *     or "TRITANOMALY".
- * @param {number} severity A real number in [0,1] denoting severity.
- */
-function getCvdSimulationMatrix(cvdType, severity) {
-  var cvdSimulationParam = cvdSimulationParams[cvdType];
-  var severity2 = severity * severity;
-  var matrix = [];
-  for (var i = 0; i < 3; i++) {
-    var row = [];
-    for (var j = 0; j < 3; j++) {
-      var paramRow = i*3+j;
-      var val = cvdSimulationParam[paramRow][0] * severity2
-              + cvdSimulationParam[paramRow][1] * severity
-              + cvdSimulationParam[paramRow][2];
-      row.push(val);
-    }
-    matrix.push(row);
-  }
-  return matrix;
-}
-
-
-/**
- * Returns a 3x3 matrix for correcting the given type of CVD using the given
- * color adjustment.
- * @param {string} cvdType Type of CVD, either "PROTANOMALY" or "DEUTERANOMALY"
- *     or "TRITANOMALY".
- * @param {number} delta A real number in [0,1] denoting color adjustment.
- */
-function getCvdCorrectionMatrix(cvdType, delta) {
-  cvdCorrectionParam = cvdCorrectionParams[cvdType];
-  // TODO(mustaq): Perhaps nuke full-matrix operations after experiment.
-  return add3x3(cvdCorrectionParam['addendum'],
-                mul3x3Scalar(cvdCorrectionParam['delta_factor'], delta));
-}
-
-
-/**
- * Returns the 3x3 matrix to be used for the given settings.
- * @param {string} cvdType Type of CVD, either "PROTANOMALY" or "DEUTERANOMALY"
- *     or "TRITANOMALY".
- * @param {number} severity A real number in [0,1] denoting severity.
- * @param {number} delta A real number in [0,1] denoting color adjustment.
- * @param {boolean} simulate Whether to simulate the CVD type.
- * @param {boolean} enable Whether to enable color filtering.
- */
-function getEffectiveCvdMatrix(cvdType, severity, delta, simulate, enable) {
-  if (!enable) {
-    //TODO(mustaq): we should remove matrices at the svg level
-    return IDENTITY_MATRIX_3x3;
-  }
-
-  var effectiveMatrix = getCvdSimulationMatrix(cvdType, severity);
-
-  if (!simulate) {
-    var cvdCorrectionMatrix = getCvdCorrectionMatrix(cvdType, delta);
-    var tmpProduct = mul3x3(cvdCorrectionMatrix, effectiveMatrix);
-
-    effectiveMatrix = sub3x3(
-        add3x3(IDENTITY_MATRIX_3x3, cvdCorrectionMatrix),
-        tmpProduct);
-  }
-
-  return effectiveMatrix;
-}
-
-
-// ======= Page linker =======
-
-/** @const {string} */
-var SVG_DEFAULT_MATRIX =
-  '1 0 0 0 0 ' +
-  '0 1 0 0 0 ' +
-  '0 0 1 0 0 ' +
-  '0 0 0 1 0';
-
-var svgContent =
-  '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">' +
-  '  <defs>' +
-  '    <filter id="cvd_extension_0">' +
-  '      <feColorMatrix id="cvd_matrix_0" type="matrix" values="' +
-      SVG_DEFAULT_MATRIX + '"/>' +
-  '    </filter>' +
-  '    <filter id="cvd_extension_1">' +
-  '      <feColorMatrix id="cvd_matrix_1" type="matrix" values="' +
-      SVG_DEFAULT_MATRIX + '"/>' +
-  '    </filter>' +
-  '  </defs>' +
-  '</svg>';
-
-/**
- * Checks for svg filter matrix presence and append to DOM if not present.
- */
-function addSvgIfMissing() {
-  var wrap = document.getElementById('cvd_extension_svg_filter');
-  if (!wrap) {
-    wrap = document.createElement('span');
-    wrap.id = 'cvd_extension_svg_filter';
-    wrap.setAttribute('hidden', '');
-    wrap.innerHTML = svgContent;
-    document.body.appendChild(wrap);
-  }
-}
-
-/**
- * Updates the SVG filter based on the RGB correction/simulation matrix.
- * @param {!Object} matrix  3x3 RGB transformation matrix.
- */
-function setFilter(matrix) {
-  addSvgIfMissing();
-  var next = 1 - curFilter;
-
-  debugPrint('update: matrix#' + next + '=' +
-      humanReadbleStringFrom3x3(matrix));
-
-  var matrixElem = document.getElementById('cvd_matrix_' + next);
-  matrixElem.setAttribute('values', svgMatrixStringFrom3x3(matrix));
-
-  var html = document.documentElement;
-  html.classList.remove('filter' + curFilter);
-  html.classList.add('filter' + next);
-
-  curFilter = next;
-}
-
-/**
- * Updates the SVG matrix using the current settings.
- */
-function update() {
-  if (!document.body) {
-    document.addEventListener('DOMContentLoaded', update);
-    return;
-  }
-
-  var effectiveMatrix = getEffectiveCvdMatrix(
-      curType, curSeverity, curDelta * 2 - 1, curSimulate, curEnable);
-
-  setFilter(effectiveMatrix);
-
-  // TODO(wnwen): Figure out whether this hack is still necessary.
-  // TODO(kevers): Check if a call to getComputedStyle is sufficient to force an
-  // update.
-  window.scrollBy(0, 1);
-  window.scrollBy(0, -1);
-}
-
-
-/**
- * Process request from background page.
- * @param {!object} request An object containing color filter parameters.
- */
-function onExtensionMessage(request) {
-  debugPrint('onExtensionMessage: ' + JSON.stringify(request));
-  var changed = false;
-
-  if (request['type'] !== undefined) {
-    var type = request.type;
-    if (curType != type) {
-      curType = type;
-      changed = true;
-    }
-  }
-
-  if (request['severity'] !== undefined) {
-    var severity = request.severity;
-    if (curSeverity != severity) {
-      curSeverity = severity;
-      changed = true;
-    }
-  }
-
-  if (request['delta'] !== undefined) {
-    var delta = request.delta;
-    if (curDelta != delta) {
-      curDelta = delta;
-      changed = true;
-    }
-  }
-
-  if (request['simulate'] !== undefined) {
-    var simulate = request.simulate;
-    if (curSimulate != simulate) {
-      curSimulate = simulate;
-      changed = true;
-    }
-  }
-
-  if (request['enable'] !== undefined) {
-    var enable = request.enable;
-    if (curEnable != enable) {
-      curEnable = enable;
-      changed = true;
-    }
-  }
-
-  if (changed)
-    update();
-}
-
-
-/**
- * Prepare to process background messages and let it know to send initial
- * values.
- */
-(function initialize() {
-  chrome.extension.onRequest.addListener(onExtensionMessage);
-  chrome.extension.sendRequest({'init': true}, onExtensionMessage);
-})();
 
 /**
  * Global exports.  Used by popup to show effect of filter during setup.
  */
 (function(exports) {
+  var curDelta = 0;
+  var curSeverity = 0;
+  var curType = 'PROTANOMALY';
+  var curSimulate = false;
+  var curEnable = false;
+  var curFilter = 0;
+
+
+  // ======= 3x3 matrix ops =======
+
+  /**
+   * The 3x3 identity matrix.
+   * @const {object}
+   */
+  var IDENTITY_MATRIX_3x3 = [
+    [1, 0, 0],
+    [0, 1, 0],
+    [0, 0, 1]
+  ];
+
+
+  /**
+   * Adds two matrices.
+   * @param {!object} m1 A 3x3 matrix.
+   * @param {!object} m2 A 3x3 matrix.
+   * @return {!object} The 3x3 matrix m1 + m2.
+   */
+  function add3x3(m1, m2) {
+    var result = [];
+    for (var i = 0; i < 3; i++) {
+      result[i] = [];
+      for (var j = 0; j < 3; j++) {
+        result[i].push(m1[i][j] + m2[i][j]);
+      }
+    }
+    return result;
+  }
+
+
+  /**
+   * Subtracts one matrix from another.
+   * @param {!object} m1 A 3x3 matrix.
+   * @param {!object} m2 A 3x3 matrix.
+   * @return {!object} The 3x3 matrix m1 - m2.
+   */
+  function sub3x3(m1, m2) {
+    var result = [];
+    for (var i = 0; i < 3; i++) {
+      result[i] = [];
+      for (var j = 0; j < 3; j++) {
+        result[i].push(m1[i][j] - m2[i][j]);
+      }
+    }
+    return result;
+  }
+
+
+  /**
+   * Multiplies one matrix with another.
+   * @param {!object} m1 A 3x3 matrix.
+   * @param {!object} m2 A 3x3 matrix.
+   * @return {!object} The 3x3 matrix m1 * m2.
+   */
+  function mul3x3(m1, m2) {
+    var result = [];
+    for (var i = 0; i < 3; i++) {
+      result[i] = [];
+      for (var j = 0; j < 3; j++) {
+        var sum = 0;
+        for (var k = 0; k < 3; k++) {
+          sum += m1[i][k] * m2[k][j];
+        }
+        result[i].push(sum);
+      }
+    }
+    return result;
+  }
+
+
+  /**
+   * Multiplies a matrix with a number.
+   * @param {!object} m A 3x3 matrix.
+   * @param {!number} k A scalar multiplier.
+   * @return {!object} The 3x3 matrix m * k.
+   */
+  function mul3x3Scalar(m, k) {
+    var result = [];
+    for (var i = 0; i < 3; i++) {
+      result[i] = [];
+      for (var j = 0; j < 3; j++) {
+        result[i].push(k * m[i][j]);
+      }
+    }
+    return result;
+  }
+
+
+  // ======= 3x3 matrix utils =======
+
+  /**
+   * Makes the SVG matrix string (of 20 values) for a given matrix.
+   * @param {!object} m A 3x3 matrix.
+   * @return {!string} The SVG matrix string for m.
+   */
+  function svgMatrixStringFrom3x3(m) {
+    var outputRows = [];
+    for (var i = 0; i < 3; i++) {
+      outputRows.push(m[i].join(' ') + ' 0 0');
+    }
+    // Add the alpha row
+    outputRows.push('0 0 0 1 0');
+    return outputRows.join(' ');
+  }
+
+
+  /**
+   * Makes a human readable string for a given matrix.
+   * @param {!object} m A 3x3 matrix.
+   * @return {!string} A human-readable string for m.
+   */
+  function humanReadbleStringFrom3x3(m) {
+      var result = '';
+      for (var i = 0; i < 3; i++) {
+          result += (i ? ', ' : '') + '[';
+          for (var j = 0; j < 3; j++) {
+              result += (j ? ', ' : '') + m[i][j].toFixed(2);
+          }
+          result += ']';
+      }
+      return result;
+  }
+
+
+  // ======= CVD parameters =======
+  /**
+   * Parameters for simulating color vision deficiency.
+   * Source:
+   *     http://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/CVD_Simulation.html
+   * Original Research Paper:
+   *     http://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/Machado_Oliveira_Fernandes_CVD_Vis2009_final.pdf
+   *
+   * @enum {string}
+   */
+  var cvdSimulationParams = {
+    PROTANOMALY: [
+      [0.4720, -1.2946, 0.9857],
+      [-0.6128, 1.6326, 0.0187],
+      [0.1407, -0.3380, -0.0044],
+      [-0.1420, 0.2488, 0.0044],
+      [0.1872, -0.3908, 0.9942],
+      [-0.0451, 0.1420, 0.0013],
+      [0.0222, -0.0253, -0.0004],
+      [-0.0290, -0.0201, 0.0006],
+      [0.0068, 0.0454, 0.9990]
+    ],
+    DEUTERANOMALY: [
+      [0.5442, -1.1454, 0.9818],
+      [-0.7091, 1.5287, 0.0238],
+      [0.1650, -0.3833, -0.0055],
+      [-0.1664, 0.4368, 0.0056],
+      [0.2178, -0.5327, 0.9927],
+      [-0.0514, 0.0958, 0.0017],
+      [0.0180, -0.0288, -0.0006],
+      [-0.0232, -0.0649, 0.0007],
+      [0.0052, 0.0360, 0.9998]
+    ],
+    TRITANOMALY: [
+      [0.4275, -0.0181, 0.9307],
+      [-0.2454, 0.0013, 0.0827],
+      [-0.1821, 0.0168, -0.0134],
+      [-0.1280, 0.0047, 0.0202],
+      [0.0233, -0.0398, 0.9728],
+      [0.1048, 0.0352, 0.0070],
+      [-0.0156, 0.0061, 0.0071],
+      [0.3841, 0.2947, 0.0151],
+      [-0.3685, -0.3008, 0.9778]
+    ]
+  };
+
+
+  // TODO(mustaq): This should be nuked, see getCvdCorrectionMatrix().
+  var cvdCorrectionParams = {
+    PROTANOMALY: {
+      addendum: [
+        [0.0, 0.0, 0.0],
+        [0.7, 1.0, 0.0],
+        [0.7, 0.0, 1.0]
+      ],
+      delta_factor: [
+        [0.0, 0.0, 0.0],
+        [0.3, 0.0, 0.0],
+        [-0.3, 0.0, 0.0]
+      ]
+    },
+    DEUTERANOMALY: {
+      addendum: [
+        [0.0, 0.0, 0.0],
+        [0.7, 1.0, 0.0],
+        [0.7, 0.0, 1.0]
+      ],
+      delta_factor: [
+        [0.0, 0.0, 0.0],
+        [0.3, 0.0, 0.0],
+        [-0.3, 0.0, 0.0]
+      ]
+    },
+    TRITANOMALY: {
+      addendum: [
+        [1.0, 0.0, 0.7],
+        [0.0, 1.0, 0.7],
+        [0.0, 0.0, 0.0]
+      ],
+      delta_factor: [
+        [0.0, 0.0, 0.3],
+        [0.0, 0.0, -0.3],
+        [0.0, 0.0, 0.0]
+      ]
+    }
+  };
+
+
+  // =======  CVD matrix builders =======
+
+  /**
+   * Returns a 3x3 matrix for simulating the given type of CVD with the given
+   * severity.
+   * @param {string} cvdType Type of CVD, either "PROTANOMALY" or
+   *     "DEUTERANOMALY" or "TRITANOMALY".
+   * @param {number} severity A real number in [0,1] denoting severity.
+   */
+  function getCvdSimulationMatrix(cvdType, severity) {
+    var cvdSimulationParam = cvdSimulationParams[cvdType];
+    var severity2 = severity * severity;
+    var matrix = [];
+    for (var i = 0; i < 3; i++) {
+      var row = [];
+      for (var j = 0; j < 3; j++) {
+        var paramRow = i*3+j;
+        var val = cvdSimulationParam[paramRow][0] * severity2
+                + cvdSimulationParam[paramRow][1] * severity
+                + cvdSimulationParam[paramRow][2];
+        row.push(val);
+      }
+      matrix.push(row);
+    }
+    return matrix;
+  }
+
+
+  /**
+   * Returns a 3x3 matrix for correcting the given type of CVD using the given
+   * color adjustment.
+   * @param {string} cvdType Type of CVD, either "PROTANOMALY" or
+   *     "DEUTERANOMALY" or "TRITANOMALY".
+   * @param {number} delta A real number in [0,1] denoting color adjustment.
+   */
+  function getCvdCorrectionMatrix(cvdType, delta) {
+    cvdCorrectionParam = cvdCorrectionParams[cvdType];
+    // TODO(mustaq): Perhaps nuke full-matrix operations after experiment.
+    return add3x3(cvdCorrectionParam['addendum'],
+                  mul3x3Scalar(cvdCorrectionParam['delta_factor'], delta));
+  }
+
+
+  /**
+   * Returns the 3x3 matrix to be used for the given settings.
+   * @param {string} cvdType Type of CVD, either "PROTANOMALY" or
+   *     "DEUTERANOMALY" or "TRITANOMALY".
+   * @param {number} severity A real number in [0,1] denoting severity.
+   * @param {number} delta A real number in [0,1] denoting color adjustment.
+   * @param {boolean} simulate Whether to simulate the CVD type.
+   * @param {boolean} enable Whether to enable color filtering.
+   */
+  function getEffectiveCvdMatrix(cvdType, severity, delta, simulate, enable) {
+    if (!enable) {
+      //TODO(mustaq): we should remove matrices at the svg level
+      return IDENTITY_MATRIX_3x3;
+    }
+
+    var effectiveMatrix = getCvdSimulationMatrix(cvdType, severity);
+
+    if (!simulate) {
+      var cvdCorrectionMatrix = getCvdCorrectionMatrix(cvdType, delta);
+      var tmpProduct = mul3x3(cvdCorrectionMatrix, effectiveMatrix);
+
+      effectiveMatrix = sub3x3(
+          add3x3(IDENTITY_MATRIX_3x3, cvdCorrectionMatrix),
+          tmpProduct);
+    }
+
+    return effectiveMatrix;
+  }
+
+
+  // ======= Page linker =======
+
+  /** @const {string} */
+  var SVG_DEFAULT_MATRIX =
+    '1 0 0 0 0 ' +
+    '0 1 0 0 0 ' +
+    '0 0 1 0 0 ' +
+    '0 0 0 1 0';
+
+  var svgContent =
+    '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">' +
+    '  <defs>' +
+    '    <filter id="cvd_extension_0">' +
+    '      <feColorMatrix id="cvd_matrix_0" type="matrix" values="' +
+        SVG_DEFAULT_MATRIX + '"/>' +
+    '    </filter>' +
+    '    <filter id="cvd_extension_1">' +
+    '      <feColorMatrix id="cvd_matrix_1" type="matrix" values="' +
+        SVG_DEFAULT_MATRIX + '"/>' +
+    '    </filter>' +
+    '  </defs>' +
+    '</svg>';
+
+  /**
+   * Checks for svg filter matrix presence and append to DOM if not present.
+   */
+  function addSvgIfMissing() {
+    var wrap = document.getElementById('cvd_extension_svg_filter');
+    if (!wrap) {
+      wrap = document.createElement('span');
+      wrap.id = 'cvd_extension_svg_filter';
+      wrap.setAttribute('hidden', '');
+      wrap.innerHTML = svgContent;
+      document.body.appendChild(wrap);
+    }
+  }
+
+  /**
+   * Updates the SVG filter based on the RGB correction/simulation matrix.
+   * @param {!Object} matrix  3x3 RGB transformation matrix.
+   */
+  function setFilter(matrix) {
+    addSvgIfMissing();
+    var next = 1 - curFilter;
+
+    debugPrint('update: matrix#' + next + '=' +
+        humanReadbleStringFrom3x3(matrix));
+
+    var matrixElem = document.getElementById('cvd_matrix_' + next);
+    matrixElem.setAttribute('values', svgMatrixStringFrom3x3(matrix));
+
+    var html = document.documentElement;
+    html.classList.remove('filter' + curFilter);
+    html.classList.add('filter' + next);
+
+    curFilter = next;
+  }
+
+  /**
+   * Updates the SVG matrix using the current settings.
+   */
+  function update() {
+    if (!document.body) {
+      document.addEventListener('DOMContentLoaded', update);
+      return;
+    }
+
+    var effectiveMatrix = getEffectiveCvdMatrix(
+        curType, curSeverity, curDelta * 2 - 1, curSimulate, curEnable);
+
+    setFilter(effectiveMatrix);
+
+    // TODO(kevers): Check if a call to getComputedStyle is sufficient to force
+    // an update.
+    window.scrollBy(0, 1);
+    window.scrollBy(0, -1);
+  }
+
+
+  /**
+   * Process request from background page.
+   * @param {!object} request An object containing color filter parameters.
+   */
+  function onExtensionMessage(request) {
+    debugPrint('onExtensionMessage: ' + JSON.stringify(request));
+    var changed = false;
+
+    if (request['type'] !== undefined) {
+      var type = request.type;
+      if (curType != type) {
+        curType = type;
+        changed = true;
+      }
+    }
+
+    if (request['severity'] !== undefined) {
+      var severity = request.severity;
+      if (curSeverity != severity) {
+        curSeverity = severity;
+        changed = true;
+      }
+    }
+
+    if (request['delta'] !== undefined) {
+      var delta = request.delta;
+      if (curDelta != delta) {
+        curDelta = delta;
+        changed = true;
+      }
+    }
+
+    if (request['simulate'] !== undefined) {
+      var simulate = request.simulate;
+      if (curSimulate != simulate) {
+        curSimulate = simulate;
+        changed = true;
+      }
+    }
+
+    if (request['enable'] !== undefined) {
+      var enable = request.enable;
+      if (curEnable != enable) {
+        curEnable = enable;
+        changed = true;
+      }
+    }
+
+    if (changed)
+      update();
+  }
+
+
+  /**
+   * Prepare to process background messages and let it know to send initial
+   * values.
+   */
+  exports.initializeExtension = function () {
+    chrome.extension.onRequest.addListener(onExtensionMessage);
+    chrome.extension.sendRequest({'init': true}, onExtensionMessage);
+  };
+
   /**
    * Generate SVG filter for color enhancement based on type and severity using
    * default color adjustment.
@@ -472,3 +470,5 @@
     html.classList.remove('filter1');
   };
 })(this);
+
+this.initializeExtension();
diff --git a/ui/accessibility/extensions/colorenhancer/src/popup.js b/ui/accessibility/extensions/colorenhancer/src/popup.js
index 4473342..d875706 100644
--- a/ui/accessibility/extensions/colorenhancer/src/popup.js
+++ b/ui/accessibility/extensions/colorenhancer/src/popup.js
@@ -2,401 +2,418 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-var site;
-
 /**
- * Toggle between filters 0 and 1 in order to force a repaint.
- * TODO(kevers): Consolidate with filter in CVD.
- * @type {!number}
+ * Global exports, used locally to separate initialization from declaration.
  */
-var activeFilterIndex = 0;
+(function(exports) {
+  var site;
 
-/**
- * Save previous state of setup parameters for use in the event of a canceled
- * setup.
- * @type {{type: string, severity: number} | undefined}
- */
-var restoreSettings = undefined;
+  /**
+   * Toggle between filters 0 and 1 in order to force a repaint.
+   * TODO(kevers): Consolidate with filter in CVD.
+   * @type {!number}
+   */
+  var activeFilterIndex = 0;
 
-/**
- * The strings for CVD Types.
- * TODO(mustaq): Define an enum in cvd.js instead.
- * @const {array{string}}
- */
-var CVD_TYPES = [
-  'PROTANOMALY',
-  'DEUTERANOMALY',
-  'TRITANOMALY'
-];
+  /**
+   * Save previous state of setup parameters for use in the event of a canceled
+   * setup.
+   * @type {{type: string, severity: number} | undefined}
+   */
+  var restoreSettings = undefined;
 
-/**
- * Vertical offset for displaying the row highlight.
- * @const {number}
- */
-var HIGHLIGHT_OFFSET = 7;
+  /**
+   * The strings for CVD Types.
+   * TODO(mustaq): Define an enum in cvd.js instead.
+   * @const {array{string}}
+   */
+  var CVD_TYPES = [
+    'PROTANOMALY',
+    'DEUTERANOMALY',
+    'TRITANOMALY'
+  ];
 
-// ======= Swatch generator =======
+  /**
+   * Vertical offset for displaying the row highlight.
+   * @const {number}
+   */
+  var HIGHLIGHT_OFFSET = 7;
 
-/**
- * Set of colors for test swatches.
- * Each row of swatches corresponds to a different type of color blindness.
- * Tests for the 3 different types of dichromatic color vison.
- * Colors selected based on color confusion lines for dichromats using our
- * swatch generator tool. See:
- * http://www.color-blindness.com/2007/01/23/confusion-lines-of-the-cie-1931-color-space/
- */
-var SWATCH_COLORS = [
-  {
-    BACKGROUND: [194,66,96],
-    PROTANOMALY: [123,73,103],
-    DEUTERANOMALY: [131,91,97],
-    TRITANOMALY: [182,57,199]
-  },
-  {
-    BACKGROUND: [156,90,94],
-    PROTANOMALY: [100,96,97],
-    DEUTERANOMALY: [106,110,95],
-    TRITANOMALY: [165,100,0]
-  },
-  {
-    BACKGROUND: [201,110,50],
-    PROTANOMALY: [125,120,52],
-    DEUTERANOMALY: [135,136,51],
-    TRITANOMALY: [189,99,163]
-  },
-  {
-    BACKGROUND: [90,180,60],
-    PROTANOMALY: [161,171,57],
-    DEUTERANOMALY: [156,154,59],
-    TRITANOMALY: [84,151,247]
-  },
-  {
-    BACKGROUND: [30,172,150],
-    PROTANOMALY: [114,163,144],
-    DEUTERANOMALY: [97,146,148],
-    TRITANOMALY: [31,154,246]
-  },
-  {
-    BACKGROUND: [50,99,144],
-    PROTANOMALY: [145,90,135],
-    DEUTERANOMALY: [97,81,142],
-    TRITANOMALY: [52,112,59]
-  },
-  {
-    BACKGROUND: [91,72,147],
-    PROTANOMALY: [62,74,151],
-    DEUTERANOMALY: [63,83,148],
-    TRITANOMALY: [102,88,12]
-  },
-];
+  // ======= Swatch generator =======
 
-/**
- * Creates a radio button for selecting the given type of CVD and a series of
- * color swatches for testing color vision.
- * @param {string} cvdType Type of CVD, either "PROTANOMALY" or "DEUTERANOMALY"
- *     or "TRITANOMALY".
- *  @return {!Element} Row of color swatches with a leading radio button.
- */
-function createTestRow(type) {
-  var toCssColor = function(rgb) {
-    return 'rgb(' + rgb.join(',') + ')';
-  };
-  var row = document.createElement('label');
-  row.classList.add('row');
+  /**
+   * Set of colors for test swatches.
+   * Each row of swatches corresponds to a different type of color blindness.
+   * Tests for the 3 different types of dichromatic color vison.
+   * Colors selected based on color confusion lines for dichromats using our
+   * swatch generator tool. See:
+   * http://www.color-blindness.com/2007/01/23/confusion-lines-of-the-cie-1931-color-space/
+   */
+  var SWATCH_COLORS = [
+    {
+      BACKGROUND: [194,66,96],
+      PROTANOMALY: [123,73,103],
+      DEUTERANOMALY: [131,91,97],
+      TRITANOMALY: [182,57,199]
+    },
+    {
+      BACKGROUND: [156,90,94],
+      PROTANOMALY: [100,96,97],
+      DEUTERANOMALY: [106,110,95],
+      TRITANOMALY: [165,100,0]
+    },
+    {
+      BACKGROUND: [201,110,50],
+      PROTANOMALY: [125,120,52],
+      DEUTERANOMALY: [135,136,51],
+      TRITANOMALY: [189,99,163]
+    },
+    {
+      BACKGROUND: [90,180,60],
+      PROTANOMALY: [161,171,57],
+      DEUTERANOMALY: [156,154,59],
+      TRITANOMALY: [84,151,247]
+    },
+    {
+      BACKGROUND: [30,172,150],
+      PROTANOMALY: [114,163,144],
+      DEUTERANOMALY: [97,146,148],
+      TRITANOMALY: [31,154,246]
+    },
+    {
+      BACKGROUND: [50,99,144],
+      PROTANOMALY: [145,90,135],
+      DEUTERANOMALY: [97,81,142],
+      TRITANOMALY: [52,112,59]
+    },
+    {
+      BACKGROUND: [91,72,147],
+      PROTANOMALY: [62,74,151],
+      DEUTERANOMALY: [63,83,148],
+      TRITANOMALY: [102,88,12]
+    },
+  ];
 
-  var button = document.createElement('input');
-  button.id = 'select-' + type;
-  button.name = 'cvdType';
-  button.setAttribute('type', 'radio');
-  button.value = type;
-  button.checked = false;
-  row.appendChild(button);
-  button.addEventListener('change', function() {
-    onTypeChange(this.value);
-  });
-  button.setAttribute('aria-label', type);
-
-  SWATCH_COLORS.forEach(function(data) {
-    var swatch = document.querySelector('.swatch.template').cloneNode(true);
-    swatch.style.background = toCssColor(data.BACKGROUND);
-    swatch.style.color = toCssColor(data[type]);
-    swatch.classList.remove('template');
-    row.appendChild(swatch);
-  });
-  return row;
-}
-
-
-// ======= UI hooks =======
-
-/**
- * Gets the CVD type selected through the radio buttons.
- * @return {?string}
- */
-function getCvdTypeSelection() {
-  var active = undefined;
-  CVD_TYPES.forEach(function(str) {
-    if ($('select-' + str).checked) {
-      active = str;
-      return;
-    }
-  });
-  return active;
-}
-
-
-/**
- * Sets the radio buttons selection to the given CVD type.
- * @param {string} cvdType Type of CVD, either "PROTANOMALY" or "DEUTERANOMALY"
- *     or "TRITANOMALY".
- * @return {?string}
- */
-function setCvdTypeSelection(cvdType) {
-  var highlight = $('row-highlight');
-  highlight.hidden = true;
-  CVD_TYPES.forEach(function(str) {
-    var checkbox = $('select-' + str);
-    if (cvdType == str) {
-      checkbox.checked = true;
-      var top = checkbox.parentElement.offsetTop - HIGHLIGHT_OFFSET;
-      highlight.style.top = top + 'px';
-      highlight.hidden = false;
-    } else {
-      checkbox.checked = false;
-    }
-  });
-}
-
-/**
- * Styles controls based on stage of setup.
- */
-function updateControls() {
-  if ($('setup-panel').classList.contains('collapsed')) {
-    // Not performing setup.  Ensure main controls are enabled.
-    $('enable').disabled = false;
-    $('delta').disabled = false;
-    $('setup').disabled = false;
-  } else {
-    // Disable main controls during setup phase.
-    $('enable').disabled = true;
-    $('delta').disabled = true;
-    $('setup').disabled = true;
-
-    if (!getCvdTypeSelection()) {
-      // Have not selected a CVD type. Mark Step 1 as active.
-      $('step-1').classList.add('active');
-      $('step-2').classList.remove('active');
-      // Disable "step 2" controls.
-      $('severity').disabled = true;
-      $('reset').disabled = true;
-    } else {
-      $('step-1').classList.remove('active');
-      $('step-2').classList.add('active');
-      // Enable "step 2" controls.
-      $('severity').disabled = false;
-      $('reset').disabled = false;
-      // Force filter update.
-      onSeverityChange(parseFloat($('severity').value));
-    }
-  }
-}
-
-/**
- * Update the popup controls based on settings for this site or the default.
- * @return {boolean} True if settings are valid and update performed.
- */
-function update() {
-  var type = getDefaultType();
-  var validType = false;
-  CVD_TYPES.forEach(function(cvdType) {
-    if (cvdType == type) {
-      validType = true;
-      return;
-    }
-  });
-
-  if (!validType)
-    return false;
-
-  if (site) {
-    $('delta').value = getSiteDelta(site);
-  } else {
-    $('delta').value = getDefaultDelta();
-  }
-
-  $('severity').value = getDefaultSeverity();
-
-  if (!$('setup-panel').classList.contains('collapsed'))
-    setCvdTypeSelection(getDefaultType());
-  $('enable').checked = getDefaultEnable();
-
-  debugPrint('update: ' +
-      ' del=' + $('delta').value +
-      ' sev=' + $('severity').value +
-      ' typ=' + getDefaultType() +
-      ' enb=' + $('enable').checked +
-      ' for ' + site
-  );
-  chrome.extension.getBackgroundPage().updateTabs();
-  return true;
-}
-
-/**
- * Callback for color rotation slider.
- *
- * @param {number} value Parsed value of slider element.
- */
-function onDeltaChange(value) {
-  debugPrint('onDeltaChange: ' + value + ' for ' + site);
-  if (site) {
-    setSiteDelta(site, value);
-  }
-  setDefaultDelta(value);
-  update();
-}
-
-/**
- * Callback for severity slider.
- *
- * @param {number} value Parsed value of slider element.
- */
-function onSeverityChange(value) {
-  debugPrint('onSeverityChange: ' + value + ' for ' + site);
-  setDefaultSeverity(value);
-  update();
-  // Apply filter to popup swatches.
-  var filter = window.getDefaultCvdCorrectionFilter(
-      getCvdTypeSelection(), value);
-  injectColorEnhancementFilter(filter);
-  // Force a refresh.
-  window.getComputedStyle(document.documentElement, null);
-}
-
-/**
- * Callback for changing color deficiency type.
- *
- * @param {string} value Value of dropdown element.
- */
-function onTypeChange(value) {
-  debugPrint('onTypeChange: ' + value + ' for ' + site);
-  setDefaultType(value);
-  update();
-  // TODO(kevers): reset severity to effectively disable filter.
-  activeFilterType = value;
-  $('severity').value = 0;
-  updateControls();
-}
-
-/**
- * Callback for enable/disable setting.
- *
- * @param {boolean} value Value of checkbox element.
-*/
-function onEnableChange(value) {
-  debugPrint('onEnableChange: ' + value + ' for ' + site);
-  setDefaultEnable(value);
-  if (!update()) {
-    // Settings are not valid for a reconfiguration.
-    $('setup').onclick();
-  }
-}
-
-/**
- * Callback for resetting stored per-site values.
- */
-function onReset() {
-  debugPrint('onReset');
-  resetSiteDeltas();
-  update();
-}
-
-/**
- * Attach event handlers to controls and update the filter config values for the
- * currently visible tab.
- */
-function initialize() {
-  var i18nElements = document.querySelectorAll('*[i18n-content]');
-  for (var i = 0; i < i18nElements.length; i++) {
-    var elem = i18nElements[i];
-    var msg = elem.getAttribute('i18n-content');
-    elem.textContent = chrome.i18n.getMessage(msg);
-  }
-
-  $('setup').onclick = function() {
-    $('setup-panel').classList.remove('collapsed');
-    // Store current settings in the event of a canceled setup.
-    restoreSettings = {
-      type: getDefaultType(),
-      severity: getDefaultSeverity()
+  /**
+   * Creates a radio button for selecting the given type of CVD and a series of
+   * color swatches for testing color vision.
+   * @param {string} cvdType Type of CVD, either "PROTANOMALY" or
+   *     "DEUTERANOMALY" or "TRITANOMALY".
+   *  @return {!Element} Row of color swatches with a leading radio button.
+   */
+  function createTestRow(type) {
+    var toCssColor = function(rgb) {
+      return 'rgb(' + rgb.join(',') + ')';
     };
-    // Initalize controls based on current settings.
-    setCvdTypeSelection(restoreSettings.type);
-    $('severity').value = restoreSettings.severity;
-    updateControls();
-  };
+    var row = document.createElement('label');
+    row.classList.add('row');
 
-  $('delta').addEventListener('input', function() {
-    onDeltaChange(parseFloat(this.value));
-  });
-  $('severity').addEventListener('input', function() {
-    onSeverityChange(parseFloat(this.value));
-  });
-  $('enable').addEventListener('change', function() {
-    onEnableChange(this.checked);
-  });
+    var button = document.createElement('input');
+    button.id = 'select-' + type;
+    button.name = 'cvdType';
+    button.setAttribute('type', 'radio');
+    button.value = type;
+    button.checked = false;
+    row.appendChild(button);
+    button.addEventListener('change', function() {
+      onTypeChange(this.value);
+    });
+    button.setAttribute('aria-label', type);
 
-  $('reset').onclick = function() {
-    setDefaultSeverity(0);
-    setDefaultType('');
-    setDefaultEnable(false);
-    $('severity').value = 0;
-    $('enable').checked = false;
-    setCvdTypeSelection('');
-    updateControls();
-    clearColorEnhancementFilter();
-  };
-  $('reset').hidden = !IS_DEV_MODE;
+    SWATCH_COLORS.forEach(function(data) {
+      var swatch = document.querySelector('.swatch.template').cloneNode(true);
+      swatch.style.background = toCssColor(data.BACKGROUND);
+      swatch.style.color = toCssColor(data[type]);
+      swatch.classList.remove('template');
+      row.appendChild(swatch);
+    });
+    return row;
+  }
 
-  var closeSetup = function() {
-    $('setup-panel').classList.add('collapsed');
-    updateControls();
-  };
 
-  $('ok').onclick = function() {
-    closeSetup();
-  };
+  // ======= UI hooks =======
 
-  $('cancel').onclick = function() {
-    closeSetup();
-    if (restoreSettings) {
-      debugPrint(
-        'restore previous settings: ' +
-        'type = ' + restoreSettings.type +
-         ', severity = ' + restoreSettings.severity);
-      setDefaultType(restoreSettings.type);
-      setDefaultSeverity(restoreSettings.severity);
-    }
-  };
-
-  var swatches = $('swatches');
-  CVD_TYPES.forEach(function(cvdType) {
-    swatches.appendChild(createTestRow(cvdType));
-  });
-
-  chrome.windows.getLastFocused({'populate': true}, function(window) {
-    for (var i = 0; i < window.tabs.length; i++) {
-      var tab = window.tabs[i];
-      if (tab.active) {
-        site = siteFromUrl(tab.url);
-        debugPrint('init: active tab update for ' + site);
-        update();
+  /**
+   * Gets the CVD type selected through the radio buttons.
+   * @return {?string}
+   */
+  function getCvdTypeSelection() {
+    var active = undefined;
+    CVD_TYPES.forEach(function(str) {
+      if ($('select-' + str).checked) {
+        active = str;
         return;
       }
-    }
-    site = 'unknown site';
-    update();
-  });
-}
+    });
+    return active;
+  }
 
-// TODO(wnwen): Use Promise instead, more reliable.
-window.addEventListener('load', initialize, false);
+
+  /**
+   * Sets the radio buttons selection to the given CVD type.
+   * @param {string} cvdType Type of CVD, either "PROTANOMALY" or
+   *     "DEUTERANOMALY" or "TRITANOMALY".
+   * @return {?string}
+   */
+  function setCvdTypeSelection(cvdType) {
+    var highlight = $('row-highlight');
+    highlight.hidden = true;
+    CVD_TYPES.forEach(function(str) {
+      var checkbox = $('select-' + str);
+      if (cvdType == str) {
+        checkbox.checked = true;
+        var top = checkbox.parentElement.offsetTop - HIGHLIGHT_OFFSET;
+        highlight.style.top = top + 'px';
+        highlight.hidden = false;
+      } else {
+        checkbox.checked = false;
+      }
+    });
+  }
+
+  /**
+   * Styles controls based on stage of setup.
+   */
+  function updateControls() {
+    if ($('setup-panel').classList.contains('collapsed')) {
+      // Not performing setup.  Ensure main controls are enabled.
+      $('enable').disabled = false;
+      $('delta').disabled = false;
+      $('setup').disabled = false;
+    } else {
+      // Disable main controls during setup phase.
+      $('enable').disabled = true;
+      $('delta').disabled = true;
+      $('setup').disabled = true;
+
+      if (!getCvdTypeSelection()) {
+        // Have not selected a CVD type. Mark Step 1 as active.
+        $('step-1').classList.add('active');
+        $('step-2').classList.remove('active');
+        // Disable "step 2" controls.
+        $('severity').disabled = true;
+        $('reset').disabled = true;
+      } else {
+        $('step-1').classList.remove('active');
+        $('step-2').classList.add('active');
+        // Enable "step 2" controls.
+        $('severity').disabled = false;
+        $('reset').disabled = false;
+        // Force filter update.
+        onSeverityChange(parseFloat($('severity').value));
+      }
+    }
+  }
+
+  /**
+   * Update the popup controls based on settings for this site or the default.
+   * @return {boolean} True if settings are valid and update performed.
+   */
+  function update() {
+    var type = getDefaultType();
+    var validType = false;
+    CVD_TYPES.forEach(function(cvdType) {
+      if (cvdType == type) {
+        validType = true;
+        return;
+      }
+    });
+
+    if (!validType)
+      return false;
+
+    if (site) {
+      $('delta').value = getSiteDelta(site);
+    } else {
+      $('delta').value = getDefaultDelta();
+    }
+
+    $('severity').value = getDefaultSeverity();
+
+    if (!$('setup-panel').classList.contains('collapsed'))
+      setCvdTypeSelection(getDefaultType());
+    $('enable').checked = getDefaultEnable();
+
+    debugPrint('update: ' +
+        ' del=' + $('delta').value +
+        ' sev=' + $('severity').value +
+        ' typ=' + getDefaultType() +
+        ' enb=' + $('enable').checked +
+        ' for ' + site
+    );
+    chrome.extension.getBackgroundPage().updateTabs();
+    return true;
+  }
+
+  /**
+   * Callback for color rotation slider.
+   *
+   * @param {number} value Parsed value of slider element.
+   */
+  function onDeltaChange(value) {
+    debugPrint('onDeltaChange: ' + value + ' for ' + site);
+    if (site) {
+      setSiteDelta(site, value);
+    }
+    setDefaultDelta(value);
+    update();
+  }
+
+  /**
+   * Callback for severity slider.
+   *
+   * @param {number} value Parsed value of slider element.
+   */
+  function onSeverityChange(value) {
+    debugPrint('onSeverityChange: ' + value + ' for ' + site);
+    setDefaultSeverity(value);
+    update();
+    // Apply filter to popup swatches.
+    var filter = window.getDefaultCvdCorrectionFilter(
+        getCvdTypeSelection(), value);
+    injectColorEnhancementFilter(filter);
+    // Force a refresh.
+    window.getComputedStyle(document.documentElement, null);
+  }
+
+  /**
+   * Callback for changing color deficiency type.
+   *
+   * @param {string} value Value of dropdown element.
+   */
+  function onTypeChange(value) {
+    debugPrint('onTypeChange: ' + value + ' for ' + site);
+    setDefaultType(value);
+    update();
+    // TODO(kevers): reset severity to effectively disable filter.
+    activeFilterType = value;
+    $('severity').value = 0;
+    updateControls();
+  }
+
+  /**
+   * Callback for enable/disable setting.
+   *
+   * @param {boolean} value Value of checkbox element.
+  */
+  function onEnableChange(value) {
+    debugPrint('onEnableChange: ' + value + ' for ' + site);
+    setDefaultEnable(value);
+    if (!update()) {
+      // Settings are not valid for a reconfiguration.
+      $('setup').onclick();
+    }
+  }
+
+  /**
+   * Callback for resetting stored per-site values.
+   */
+  function onReset() {
+    debugPrint('onReset');
+    resetSiteDeltas();
+    update();
+  }
+
+  /**
+   * Attach event handlers to controls and update the filter config values for
+   * the currently visible tab.
+   */
+  function initialize() {
+    var i18nElements = document.querySelectorAll('*[i18n-content]');
+    for (var i = 0; i < i18nElements.length; i++) {
+      var elem = i18nElements[i];
+      var msg = elem.getAttribute('i18n-content');
+      elem.textContent = chrome.i18n.getMessage(msg);
+    }
+
+    $('setup').onclick = function() {
+      $('setup-panel').classList.remove('collapsed');
+      // Store current settings in the event of a canceled setup.
+      restoreSettings = {
+        type: getDefaultType(),
+        severity: getDefaultSeverity()
+      };
+      // Initalize controls based on current settings.
+      setCvdTypeSelection(restoreSettings.type);
+      $('severity').value = restoreSettings.severity;
+      updateControls();
+    };
+
+    $('delta').addEventListener('input', function() {
+      onDeltaChange(parseFloat(this.value));
+    });
+    $('severity').addEventListener('input', function() {
+      onSeverityChange(parseFloat(this.value));
+    });
+    $('enable').addEventListener('change', function() {
+      onEnableChange(this.checked);
+    });
+
+    $('reset').onclick = function() {
+      setDefaultSeverity(0);
+      setDefaultType('');
+      setDefaultEnable(false);
+      $('severity').value = 0;
+      $('enable').checked = false;
+      setCvdTypeSelection('');
+      updateControls();
+      clearColorEnhancementFilter();
+    };
+    $('reset').hidden = !IS_DEV_MODE;
+
+    var closeSetup = function() {
+      $('setup-panel').classList.add('collapsed');
+      updateControls();
+    };
+
+    $('ok').onclick = function() {
+      closeSetup();
+    };
+
+    $('cancel').onclick = function() {
+      closeSetup();
+      if (restoreSettings) {
+        debugPrint(
+          'restore previous settings: ' +
+          'type = ' + restoreSettings.type +
+           ', severity = ' + restoreSettings.severity);
+        setDefaultType(restoreSettings.type);
+        setDefaultSeverity(restoreSettings.severity);
+      }
+    };
+
+    var swatches = $('swatches');
+    CVD_TYPES.forEach(function(cvdType) {
+      swatches.appendChild(createTestRow(cvdType));
+    });
+
+    chrome.windows.getLastFocused({'populate': true}, function(window) {
+      for (var i = 0; i < window.tabs.length; i++) {
+        var tab = window.tabs[i];
+        if (tab.active) {
+          site = siteFromUrl(tab.url);
+          debugPrint('init: active tab update for ' + site);
+          update();
+          return;
+        }
+      }
+      site = 'unknown site';
+      update();
+    });
+  }
+
+  /**
+   * Runs initialize once popup loading is complete.
+   */
+  exports.initializeOnLoad = function() {
+    var ready = new Promise(function readyPromise(resolve) {
+      if (document.readyState === 'complete') {
+        resolve();
+      }
+      document.addEventListener('DOMContentLoaded', resolve);
+    });
+    ready.then(initialize);
+  };
+})(this);
+
+this.initializeOnLoad();
diff --git a/ui/android/java/src/org/chromium/ui/VSyncMonitor.java b/ui/android/java/src/org/chromium/ui/VSyncMonitor.java
index 83d02d9..c074501 100644
--- a/ui/android/java/src/org/chromium/ui/VSyncMonitor.java
+++ b/ui/android/java/src/org/chromium/ui/VSyncMonitor.java
@@ -72,6 +72,7 @@
             @Override
             public void doFrame(long frameTimeNanos) {
                 TraceEvent.begin("VSync");
+                mHandler.removeCallbacks(mSyntheticVSyncRunnable);
                 if (useEstimatedRefreshPeriod && mConsecutiveVSync) {
                     // Display.getRefreshRate() is unreliable on some platforms.
                     // Adjust refresh period- initial value is based on Display.getRefreshRate()
@@ -90,6 +91,7 @@
             @Override
             public void run() {
                 TraceEvent.begin("VSyncSynthetic");
+                mChoreographer.removeFrameCallback(mVSyncFrameCallback);
                 final long currentTime = getCurrentNanoTime();
                 onVSyncCallback(estimateLastVSyncTime(currentTime), currentTime);
                 TraceEvent.end("VSyncSynthetic");
@@ -145,19 +147,26 @@
     private void postCallback() {
         if (mHaveRequestInFlight) return;
         mHaveRequestInFlight = true;
-        if (postSyntheticVSync()) return;
         mConsecutiveVSync = mInsideVSync;
+        // There's no way to tell if we're currently in the scope of a
+        // choregrapher frame callback, which might in turn allow us to honor
+        // the vsync callback in the current frame. Thus, we eagerly post the
+        // frame callback even when we post a synthetic frame callback. If the
+        // frame callback is honored before the synthetic callback, we simply
+        // remove the synthetic callback.
+        postSyntheticVSyncIfNecessary();
         mChoreographer.postFrameCallback(mVSyncFrameCallback);
     }
 
-    private boolean postSyntheticVSync() {
+    private void postSyntheticVSyncIfNecessary() {
+        // TODO(jdduke): Consider removing synthetic vsyncs altogether if
+        // they're found to be no longer necessary.
         final long currentTime = getCurrentNanoTime();
         // Only trigger a synthetic vsync if we've been idle for long enough and the upcoming real
         // vsync is more than half a frame away.
-        if (currentTime - mLastVSyncCpuTimeNano < 2 * mRefreshPeriodNano) return false;
-        if (currentTime - estimateLastVSyncTime(currentTime) > mRefreshPeriodNano / 2) return false;
+        if (currentTime - mLastVSyncCpuTimeNano < 2 * mRefreshPeriodNano) return;
+        if (currentTime - estimateLastVSyncTime(currentTime) > mRefreshPeriodNano / 2) return;
         mHandler.post(mSyntheticVSyncRunnable);
-        return true;
     }
 
     private long estimateLastVSyncTime(long currentTime) {
diff --git a/ui/app_list/app_list_constants.cc b/ui/app_list/app_list_constants.cc
index 56d10b1..ad73455f 100644
--- a/ui/app_list/app_list_constants.cc
+++ b/ui/app_list/app_list_constants.cc
@@ -48,8 +48,7 @@
 // Color of the folder bubble shadow.
 const SkColor kFolderShadowColor = SkColorSetRGB(0xBF, 0xBF, 0xBF);
 const float kFolderBubbleRadius = 23;
-const float kFolderShadowRadius = 23.5;
-const float kFolderShadowOffsetY = 1;
+const float kFolderBubbleOffsetY = 1;
 
 const SkColor kCardBackgroundColor = SK_ColorWHITE;
 
@@ -164,8 +163,8 @@
 
 const gfx::ShadowValues& IconStartShadows() {
   CR_DEFINE_STATIC_LOCAL(const gfx::ShadowValues, icon_shadows,
-                         (1, gfx::ShadowValue(gfx::Vector2d(0, 2), 2,
-                                              SkColorSetARGB(0x24, 0, 0, 0))));
+                         (1, gfx::ShadowValue(gfx::Vector2d(0, 1), 2,
+                                              SkColorSetARGB(0x33, 0, 0, 0))));
   return icon_shadows;
 }
 
diff --git a/ui/app_list/app_list_constants.h b/ui/app_list/app_list_constants.h
index afcb4a53..2efcee2 100644
--- a/ui/app_list/app_list_constants.h
+++ b/ui/app_list/app_list_constants.h
@@ -43,8 +43,7 @@
 APP_LIST_EXPORT extern const SkColor kFolderBubbleColor;
 APP_LIST_EXPORT extern const SkColor kFolderShadowColor;
 APP_LIST_EXPORT extern const float kFolderBubbleRadius;
-APP_LIST_EXPORT extern const float kFolderShadowRadius;
-APP_LIST_EXPORT extern const float kFolderShadowOffsetY;
+APP_LIST_EXPORT extern const float kFolderBubbleOffsetY;
 
 APP_LIST_EXPORT extern const SkColor kCardBackgroundColor;
 
diff --git a/ui/app_list/app_list_folder_item.cc b/ui/app_list/app_list_folder_item.cc
index e1b327e..da2cc09d 100644
--- a/ui/app_list/app_list_folder_item.cc
+++ b/ui/app_list/app_list_folder_item.cc
@@ -85,7 +85,7 @@
 }
 
 void AppListFolderItem::OnFolderImageUpdated() {
-  SetIcon(folder_image_.icon(), false);
+  SetIcon(folder_image_.icon());
 }
 
 }  // namespace app_list
diff --git a/ui/app_list/app_list_item.cc b/ui/app_list/app_list_item.cc
index 0cac35a0..d0daa27 100644
--- a/ui/app_list/app_list_item.cc
+++ b/ui/app_list/app_list_item.cc
@@ -11,7 +11,6 @@
 
 AppListItem::AppListItem(const std::string& id)
     : id_(id),
-      has_shadow_(false),
       highlighted_(false),
       is_installing_(false),
       percent_downloaded_(-1) {
@@ -21,9 +20,8 @@
   FOR_EACH_OBSERVER(AppListItemObserver, observers_, ItemBeingDestroyed());
 }
 
-void AppListItem::SetIcon(const gfx::ImageSkia& icon, bool has_shadow) {
+void AppListItem::SetIcon(const gfx::ImageSkia& icon) {
   icon_ = icon;
-  has_shadow_ = has_shadow;
   FOR_EACH_OBSERVER(AppListItemObserver, observers_, ItemIconChanged());
 }
 
diff --git a/ui/app_list/app_list_item.h b/ui/app_list/app_list_item.h
index ea476bb88d..d77fa9ef 100644
--- a/ui/app_list/app_list_item.h
+++ b/ui/app_list/app_list_item.h
@@ -33,9 +33,8 @@
   explicit AppListItem(const std::string& id);
   virtual ~AppListItem();
 
-  void SetIcon(const gfx::ImageSkia& icon, bool has_shadow);
+  void SetIcon(const gfx::ImageSkia& icon);
   const gfx::ImageSkia& icon() const { return icon_; }
-  bool has_shadow() const { return has_shadow_; }
 
   const std::string& GetDisplayName() const {
     return short_name_.empty() ? name_ : short_name_;
@@ -121,7 +120,6 @@
   std::string folder_id_;  // Id of containing folder; empty if top level item.
   syncer::StringOrdinal position_;
   gfx::ImageSkia icon_;
-  bool has_shadow_;
 
   // The full name of an item. Used for display if |short_name_| is empty.
   std::string name_;
diff --git a/ui/app_list/cocoa/apps_grid_controller_unittest.mm b/ui/app_list/cocoa/apps_grid_controller_unittest.mm
index 7294b3c..85ae6a53 100644
--- a/ui/app_list/cocoa/apps_grid_controller_unittest.mm
+++ b/ui/app_list/cocoa/apps_grid_controller_unittest.mm
@@ -438,7 +438,7 @@
   EXPECT_NSEQ(@"UpdatedItem", [button title]);
 
   // Test icon updates through the model observer by ensuring the icon changes.
-  item_model->SetIcon(gfx::ImageSkia(), false);
+  item_model->SetIcon(gfx::ImageSkia());
   NSSize icon_size = [[button image] size];
   EXPECT_EQ(0, icon_size.width);
   EXPECT_EQ(0, icon_size.height);
@@ -447,7 +447,7 @@
   const int kTestImageSize = 10;
   const int kTargetImageSize = 48;
   bitmap.setInfo(SkImageInfo::MakeN32Premul(kTestImageSize, kTestImageSize));
-  item_model->SetIcon(gfx::ImageSkia::CreateFrom1xBitmap(bitmap), false);
+  item_model->SetIcon(gfx::ImageSkia::CreateFrom1xBitmap(bitmap));
   icon_size = [[button image] size];
   // Icon should always be resized to 48x48.
   EXPECT_EQ(kTargetImageSize, icon_size.width);
diff --git a/ui/app_list/cocoa/apps_grid_view_item.mm b/ui/app_list/cocoa/apps_grid_view_item.mm
index 2d5ce04..992bc9a 100644
--- a/ui/app_list/cocoa/apps_grid_view_item.mm
+++ b/ui/app_list/cocoa/apps_grid_view_item.mm
@@ -274,7 +274,7 @@
   NSImage* buttonImage = gfx::NSImageFromImageSkiaWithColorSpace(
       icon, base::mac::GetSRGBColorSpace());
   [[self button] setImage:buttonImage];
-  [[[self button] cell] setHasShadow:[self model]->has_shadow()];
+  [[[self button] cell] setHasShadow:true];
 }
 
 - (void)setModel:(app_list::AppListItem*)itemModel {
diff --git a/ui/app_list/demo/app_list_demo_views.cc b/ui/app_list/demo/app_list_demo_views.cc
index 89cb92612..dc71701 100644
--- a/ui/app_list/demo/app_list_demo_views.cc
+++ b/ui/app_list/demo/app_list_demo_views.cc
@@ -76,7 +76,7 @@
   for (size_t i = 0; i < item_list->item_count(); ++i) {
     app_list::AppListItem* item = item_list->item_at(i);
     // Alternate images with shadows and images without.
-    item->SetIcon(*test_image.ToImageSkia(), i & 1);
+    item->SetIcon(*test_image.ToImageSkia());
   }
   return view_;
 }
diff --git a/ui/app_list/folder_image.cc b/ui/app_list/folder_image.cc
index a542f553..0c9b958 100644
--- a/ui/app_list/folder_image.cc
+++ b/ui/app_list/folder_image.cc
@@ -77,17 +77,12 @@
 }
 
 void FolderImageSource::Draw(gfx::Canvas* canvas) {
-  // Draw circle for folder shadow.
-  gfx::PointF shadow_center(size().width() / 2, size().height() / 2);
   SkPaint paint;
+  // Draw circle for folder bubble.
+  gfx::PointF bubble_center(size().width() / 2, size().height() / 2);
+  bubble_center.Offset(0, -kFolderBubbleOffsetY);
   paint.setStyle(SkPaint::kFill_Style);
   paint.setAntiAlias(true);
-  paint.setColor(kFolderShadowColor);
-  canvas->sk_canvas()->drawCircle(shadow_center.x(), shadow_center.y(),
-                                  kFolderShadowRadius, paint);
-  // Draw circle for folder bubble.
-  gfx::PointF bubble_center(shadow_center);
-  bubble_center.Offset(0, -kFolderShadowOffsetY);
   paint.setColor(kFolderBubbleColor);
   canvas->sk_canvas()->drawCircle(bubble_center.x(), bubble_center.y(),
                                   kFolderBubbleRadius, paint);
diff --git a/ui/app_list/folder_image_unittest.cc b/ui/app_list/folder_image_unittest.cc
index f9c97b0..7929ebf 100644
--- a/ui/app_list/folder_image_unittest.cc
+++ b/ui/app_list/folder_image_unittest.cc
@@ -74,8 +74,7 @@
  protected:
   void AddAppWithColoredIcon(const std::string& id, SkColor icon_color) {
     scoped_ptr<AppListItem> item(new AppListItem(id));
-    item->SetIcon(CreateSquareBitmapWithColor(kListIconSize, icon_color),
-                  false);
+    item->SetIcon(CreateSquareBitmapWithColor(kListIconSize, icon_color));
     app_list_model_.AddItem(item.Pass());
   }
 
@@ -138,8 +137,8 @@
   gfx::ImageSkia icon1 = folder_image_.icon();
 
   // Change an item's icon. Ensure that the observer fired and the icon changed.
-  app_list_model_.FindItem("app2")->SetIcon(
-      CreateSquareBitmapWithColor(kListIconSize, SK_ColorMAGENTA), false);
+  app_list_model_.FindItem("app2")
+      ->SetIcon(CreateSquareBitmapWithColor(kListIconSize, SK_ColorMAGENTA));
   EXPECT_TRUE(observer_.updated());
   observer_.Reset();
   EXPECT_FALSE(ImagesAreEqual(icon1, folder_image_.icon()));
diff --git a/ui/app_list/test/app_list_test_model.cc b/ui/app_list/test/app_list_test_model.cc
index 8ab31d47..e263b0f 100644
--- a/ui/app_list/test/app_list_test_model.cc
+++ b/ui/app_list/test/app_list_test_model.cc
@@ -30,8 +30,7 @@
     AppListTestModel* model)
     : AppListItem(id),
       model_(model) {
-  SetIcon(CreateImageSkia(kGridIconDimension, kGridIconDimension),
-          false /* has_shadow */);
+  SetIcon(CreateImageSkia(kGridIconDimension, kGridIconDimension));
 }
 
 AppListTestModel::AppListTestItem::~AppListTestItem() {
diff --git a/ui/app_list/views/app_list_item_view.cc b/ui/app_list/views/app_list_item_view.cc
index 66faa98..e6b55bfa 100644
--- a/ui/app_list/views/app_list_item_view.cc
+++ b/ui/app_list/views/app_list_item_view.cc
@@ -110,7 +110,7 @@
   AddChildView(title_);
   AddChildView(progress_bar_);
 
-  SetIcon(item->icon(), item->has_shadow());
+  SetIcon(item->icon());
   SetItemName(base::UTF8ToUTF16(item->GetDisplayName()),
               base::UTF8ToUTF16(item->name()));
   SetItemIsInstalling(item->is_installing());
@@ -128,7 +128,7 @@
     item_weak_->RemoveObserver(this);
 }
 
-void AppListItemView::SetIcon(const gfx::ImageSkia& icon, bool has_shadow) {
+void AppListItemView::SetIcon(const gfx::ImageSkia& icon) {
   // Clear icon and bail out if item icon is empty.
   if (icon.isNull()) {
     icon_->SetImage(NULL);
@@ -139,12 +139,7 @@
       icon,
       skia::ImageOperations::RESIZE_BEST,
       gfx::Size(kGridIconDimension, kGridIconDimension)));
-  if (has_shadow || app_list::switches::IsExperimentalAppListEnabled()) {
-    shadow_animator_.SetOriginalImage(resized);
-    return;
-  }
-
-  icon_->SetImage(resized);
+  shadow_animator_.SetOriginalImage(resized);
 }
 
 void AppListItemView::SetUIState(UIState state) {
@@ -560,7 +555,7 @@
 }
 
 void AppListItemView::ItemIconChanged() {
-  SetIcon(item_weak_->icon(), item_weak_->has_shadow());
+  SetIcon(item_weak_->icon());
 }
 
 void AppListItemView::ItemNameChanged() {
diff --git a/ui/app_list/views/app_list_item_view.h b/ui/app_list/views/app_list_item_view.h
index 3333879..c434371e 100644
--- a/ui/app_list/views/app_list_item_view.h
+++ b/ui/app_list/views/app_list_item_view.h
@@ -44,7 +44,7 @@
   ~AppListItemView() override;
 
   // Set the icon of this image, adding a drop shadow if |has_shadow|.
-  void SetIcon(const gfx::ImageSkia& icon, bool has_shadow);
+  void SetIcon(const gfx::ImageSkia& icon);
 
   void SetItemName(const base::string16& display_name,
                    const base::string16& full_name);
diff --git a/ui/base/accelerators/accelerator_history.h b/ui/base/accelerators/accelerator_history.h
index 4b0f51a..435e752 100644
--- a/ui/base/accelerators/accelerator_history.h
+++ b/ui/base/accelerators/accelerator_history.h
@@ -25,9 +25,8 @@
     return current_accelerator_;
   }
 
-  // Returns the most recent previously recorded key accelerator that is
-  // different than the current. Non-synthesized mouse events will be stored
-  // in the histroy as an empty accelerator.
+  // Returns the most recent previously recorded accelerator that is different
+  // than the current.
   const Accelerator& previous_accelerator() const {
     return previous_accelerator_;
   }
diff --git a/ui/base/cocoa/remote_layer_api.mm b/ui/base/cocoa/remote_layer_api.mm
index 9c00683..41167fdb 100644
--- a/ui/base/cocoa/remote_layer_api.mm
+++ b/ui/base/cocoa/remote_layer_api.mm
@@ -19,7 +19,9 @@
 
   bool disabled_at_command_line =
       base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableRemoteCoreAnimation);
+          switches::kDisableRemoteCoreAnimation) ||
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableNSGLSurfaces);
   if (disabled_at_command_line)
     return false;
 
diff --git a/ui/base/ime/input_method_auralinux.cc b/ui/base/ime/input_method_auralinux.cc
index eebfc324..7f70b5e 100644
--- a/ui/base/ime/input_method_auralinux.cc
+++ b/ui/base/ime/input_method_auralinux.cc
@@ -154,6 +154,7 @@
 void InputMethodAuraLinux::OnTextInputTypeChanged(
     const TextInputClient* client) {
   UpdateContextFocusState();
+  InputMethodBase::OnTextInputTypeChanged(client);
   // TODO(yoichio): Support inputmode HTML attribute.
 }
 
diff --git a/ui/base/ui_base_switches.cc b/ui/base/ui_base_switches.cc
index e6c2fd2..e26b8828 100644
--- a/ui/base/ui_base_switches.cc
+++ b/ui/base/ui_base_switches.cc
@@ -10,6 +10,10 @@
 // Enable use of cross-process CALayers to display content directly from the
 // GPU process on Mac.
 const char kDisableRemoteCoreAnimation[] = "disable-remote-core-animation";
+
+// Force all windows to render via a layer-backed view bound to an
+// NSOpenGLContext.
+const char kEnableNSGLSurfaces[] = "enable-ns-gl-surfaces";
 #endif
 
 // Disables use of DWM composition for top level windows.
diff --git a/ui/base/ui_base_switches.h b/ui/base/ui_base_switches.h
index b49dde5..eddf34f 100644
--- a/ui/base/ui_base_switches.h
+++ b/ui/base/ui_base_switches.h
@@ -14,6 +14,7 @@
 
 #if defined(OS_MACOSX) && !defined(OS_IOS)
 UI_BASE_EXPORT extern const char kDisableRemoteCoreAnimation[];
+UI_BASE_EXPORT extern const char kEnableNSGLSurfaces[];
 #endif
 
 UI_BASE_EXPORT extern const char kDisableDwmComposition[];
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc
index a931f27..7c09a4d4 100644
--- a/ui/base/x/x11_util.cc
+++ b/ui/base/x/x11_util.cc
@@ -156,6 +156,19 @@
   return !err_tracker.FoundNewError() && result;
 }
 
+struct XImageDeleter {
+  void operator()(XImage* image) const { XDestroyImage(image); }
+};
+
+// Custom release function that will be passed to Skia so that it deletes the
+// image when the SkBitmap goes out of scope.
+// |address| is the pointer to the data inside the XImage.
+// |context| is the pointer to the XImage.
+void ReleaseXImage(void* address, void* context) {
+  if (context)
+    XDestroyImage(static_cast<XImage*>(context));
+}
+
 // A process wide singleton that manages the usage of X cursors.
 class XCursorCache {
  public:
@@ -1181,12 +1194,9 @@
                       gfx::Rect source_bounds,
                       gfx::Point dest_offset,
                       gfx::Canvas* canvas) {
-  ui::XScopedImage scoped_image(
-      XGetImage(gfx::GetXDisplay(), drawable,
-                source_bounds.x(), source_bounds.y(),
-                source_bounds.width(), source_bounds.height(),
-                AllPlanes, ZPixmap));
-  XImage* image = scoped_image.get();
+  scoped_ptr<XImage, XImageDeleter> image(XGetImage(
+      gfx::GetXDisplay(), drawable, source_bounds.x(), source_bounds.y(),
+      source_bounds.width(), source_bounds.height(), AllPlanes, ZPixmap));
   if (!image) {
     LOG(ERROR) << "XGetImage failed";
     return false;
@@ -1210,9 +1220,9 @@
       image->data[i + 3] = 0xff;
 
     SkBitmap bitmap;
-    bitmap.installPixels(SkImageInfo::MakeN32Premul(image->width,
-                                                    image->height),
-                         image->data, image->bytes_per_line);
+    bitmap.installPixels(
+        SkImageInfo::MakeN32Premul(image->width, image->height), image->data,
+        image->bytes_per_line, nullptr, &ReleaseXImage, image.release());
     gfx::ImageSkia image_skia;
     gfx::ImageSkiaRep image_rep(bitmap, canvas->image_scale());
     image_skia.AddRepresentation(image_rep);
@@ -1349,18 +1359,6 @@
 XRefcountedMemory::~XRefcountedMemory() {
 }
 
-XScopedImage::~XScopedImage() {
-  reset(NULL);
-}
-
-void XScopedImage::reset(XImage* image) {
-  if (image_ == image)
-    return;
-  if (image_)
-    XDestroyImage(image_);
-  image_ = image;
-}
-
 XScopedCursor::XScopedCursor(::Cursor cursor, XDisplay* display)
     : cursor_(cursor),
       display_(display) {
diff --git a/ui/base/x/x11_util.h b/ui/base/x/x11_util.h
index 36d7f40..039e2b6 100644
--- a/ui/base/x/x11_util.h
+++ b/ui/base/x/x11_util.h
@@ -316,25 +316,6 @@
   DISALLOW_COPY_AND_ASSIGN(XRefcountedMemory);
 };
 
-// Keeps track of an image returned by an X function (e.g. XGetImage) and
-// makes sure it's XDestroyImage'd.
-class UI_BASE_EXPORT XScopedImage {
- public:
-  explicit XScopedImage(XImage* image) : image_(image) {}
-  ~XScopedImage();
-
-  XImage* get() const { return image_; }
-
-  XImage* operator->() const { return image_; }
-
-  void reset(XImage* image);
-
- private:
-  XImage* image_;
-
-  DISALLOW_COPY_AND_ASSIGN(XScopedImage);
-};
-
 // Keeps track of a cursor returned by an X function and makes sure it's
 // XFreeCursor'd.
 class UI_BASE_EXPORT XScopedCursor {
diff --git a/ui/compositor/BUILD.gn b/ui/compositor/BUILD.gn
index a0944fe..283d1ab 100644
--- a/ui/compositor/BUILD.gn
+++ b/ui/compositor/BUILD.gn
@@ -7,6 +7,8 @@
 
 component("compositor") {
   sources = [
+    "canvas_painter.cc",
+    "canvas_painter.h",
     "clip_transform_recorder.cc",
     "clip_transform_recorder.h",
     "closure_animation_observer.cc",
diff --git a/ui/compositor/canvas_painter.cc b/ui/compositor/canvas_painter.cc
new file mode 100644
index 0000000..ff187d9
--- /dev/null
+++ b/ui/compositor/canvas_painter.cc
@@ -0,0 +1,29 @@
+// 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 "ui/compositor/canvas_painter.h"
+
+#include "cc/playback/display_item_list.h"
+#include "cc/playback/display_item_list_settings.h"
+#include "ui/gfx/canvas.h"
+
+namespace ui {
+
+CanvasPainter::CanvasPainter(gfx::Canvas* canvas, float raster_scale_factor)
+    : canvas_(canvas),
+      raster_scale_factor_(raster_scale_factor),
+      rect_(gfx::ScaleToEnclosedRect(
+          gfx::Rect(canvas_->sk_canvas()->getBaseLayerSize().width(),
+                    canvas_->sk_canvas()->getBaseLayerSize().height()),
+          1.f / raster_scale_factor)),
+      list_(cc::DisplayItemList::Create(rect_, cc::DisplayItemListSettings())),
+      context_(list_.get(), raster_scale_factor_, rect_, rect_) {
+}
+
+CanvasPainter::~CanvasPainter() {
+  list_->Finalize();
+  list_->Raster(canvas_->sk_canvas(), nullptr, rect_, raster_scale_factor_);
+}
+
+}  // namespace ui
diff --git a/ui/compositor/canvas_painter.h b/ui/compositor/canvas_painter.h
new file mode 100644
index 0000000..6d8d3902
--- /dev/null
+++ b/ui/compositor/canvas_painter.h
@@ -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.
+
+#ifndef UI_COMPOSITOR_CANVAS_PAINTER_H_
+#define UI_COMPOSITOR_CANVAS_PAINTER_H_
+
+#include "base/memory/ref_counted.h"
+#include "ui/compositor/compositor_export.h"
+#include "ui/compositor/paint_context.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace cc {
+class DisplayItemList;
+}
+
+namespace gfx {
+class Canvas;
+}
+
+namespace ui {
+
+// This class provides a simple helper for painting directly to a bitmap
+// backed canvas (for painting use-cases other than compositing). After
+// constructing an instance of a CanvasPainter, the context() can be used
+// to do painting using the normal composited paint paths. When
+// the painter is destroyed, any painting done with the context() will be
+// rastered into the canvas.
+class COMPOSITOR_EXPORT CanvasPainter {
+ public:
+  CanvasPainter(gfx::Canvas* canvas, float raster_scale_factor);
+  ~CanvasPainter();
+
+  const PaintContext& context() const { return context_; }
+
+ private:
+  gfx::Canvas* const canvas_;
+  const float raster_scale_factor_;
+  const gfx::Rect rect_;
+  scoped_refptr<cc::DisplayItemList> list_;
+  PaintContext context_;
+
+  DISALLOW_COPY_AND_ASSIGN(CanvasPainter);
+};
+
+}  // namespace ui
+
+#endif  // UI_COMPOSITOR_CANVAS_PAINTER_H_
diff --git a/ui/compositor/compositor.gyp b/ui/compositor/compositor.gyp
index 92f5ef4e..99392af 100644
--- a/ui/compositor/compositor.gyp
+++ b/ui/compositor/compositor.gyp
@@ -25,6 +25,8 @@
         'COMPOSITOR_IMPLEMENTATION',
       ],
       'sources': [
+        'canvas_painter.cc',
+        'canvas_painter.h',
         'clip_transform_recorder.cc',
         'clip_transform_recorder.h',
         'closure_animation_observer.cc',
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index e82c49db..beb91955 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -298,6 +298,10 @@
   void DidCompleteSwapBuffers() override;
   void DidCompletePageScaleAnimation() override {}
   void SendBeginFramesToChildren(const cc::BeginFrameArgs& args) override;
+  void RecordFrameTimingEvents(
+      scoped_ptr<cc::FrameTimingTracker::CompositeTimingSet> composite_events,
+      scoped_ptr<cc::FrameTimingTracker::MainFrameTimingSet> main_frame_events)
+      override {}
 
   // cc::LayerTreeHostSingleThreadClient implementation.
   void DidPostSwapBuffers() override;
diff --git a/ui/compositor/paint_context.cc b/ui/compositor/paint_context.cc
index 0d7d20f..7c44f449 100644
--- a/ui/compositor/paint_context.cc
+++ b/ui/compositor/paint_context.cc
@@ -38,10 +38,6 @@
 #endif
 }
 
-PaintContext::PaintContext(gfx::Canvas* canvas)
-    : PaintContext(canvas, gfx::Rect()) {
-}
-
 PaintContext::PaintContext(const PaintContext& other,
                            const gfx::Vector2d& offset)
     : canvas_(other.canvas_),
diff --git a/ui/compositor/paint_context.h b/ui/compositor/paint_context.h
index e091c5e..79c9142 100644
--- a/ui/compositor/paint_context.h
+++ b/ui/compositor/paint_context.h
@@ -38,10 +38,6 @@
                const gfx::Rect& bounds,
                const gfx::Rect& invalidation);
 
-  // Construct a PaintContext that will re-paint everything (no consideration
-  // for invalidation).
-  explicit PaintContext(gfx::Canvas* canvas);
-
   // Clone a PaintContext with an additional |offset|.
   PaintContext(const PaintContext& other, const gfx::Vector2d& offset);
 
diff --git a/ui/events/ozone/evdev/device_event_dispatcher_evdev.cc b/ui/events/ozone/evdev/device_event_dispatcher_evdev.cc
index 0500248..8fe624d 100644
--- a/ui/events/ozone/evdev/device_event_dispatcher_evdev.cc
+++ b/ui/events/ozone/evdev/device_event_dispatcher_evdev.cc
@@ -9,8 +9,13 @@
 KeyEventParams::KeyEventParams(int device_id,
                                unsigned int code,
                                bool down,
+                               bool enable_repeat,
                                base::TimeDelta timestamp)
-    : device_id(device_id), code(code), down(down), timestamp(timestamp) {
+    : device_id(device_id),
+      code(code),
+      down(down),
+      enable_repeat(enable_repeat),
+      timestamp(timestamp) {
 }
 
 KeyEventParams::KeyEventParams(const KeyEventParams& other) = default;
diff --git a/ui/events/ozone/evdev/device_event_dispatcher_evdev.h b/ui/events/ozone/evdev/device_event_dispatcher_evdev.h
index 019b330..c49cff0 100644
--- a/ui/events/ozone/evdev/device_event_dispatcher_evdev.h
+++ b/ui/events/ozone/evdev/device_event_dispatcher_evdev.h
@@ -23,6 +23,7 @@
   KeyEventParams(int device_id,
                  unsigned int code,
                  bool down,
+                 bool enable_repeat,
                  base::TimeDelta timestamp);
   KeyEventParams(const KeyEventParams& other);
   ~KeyEventParams();
@@ -30,6 +31,7 @@
   int device_id;
   unsigned int code;
   bool down;
+  bool enable_repeat;
   base::TimeDelta timestamp;
 };
 
diff --git a/ui/events/ozone/evdev/event_converter_evdev_impl.cc b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
index d36509d..23c6f143 100644
--- a/ui/events/ozone/evdev/event_converter_evdev_impl.cc
+++ b/ui/events/ozone/evdev/event_converter_evdev_impl.cc
@@ -188,8 +188,8 @@
   // State transition: !(down) -> (down)
   key_state_.set(key, down);
 
-  dispatcher_->DispatchKeyEvent(
-      KeyEventParams(input_device_.id, key, down, timestamp));
+  dispatcher_->DispatchKeyEvent(KeyEventParams(
+      input_device_.id, key, down, true /* enable_repeat */, timestamp));
 }
 
 void EventConverterEvdevImpl::ReleaseKeys() {
diff --git a/ui/events/ozone/evdev/event_factory_evdev.cc b/ui/events/ozone/evdev/event_factory_evdev.cc
index 6eb45d9..fff6aaa1 100644
--- a/ui/events/ozone/evdev/event_factory_evdev.cc
+++ b/ui/events/ozone/evdev/event_factory_evdev.cc
@@ -152,8 +152,8 @@
 void EventFactoryEvdev::DispatchKeyEvent(const KeyEventParams& params) {
   TRACE_EVENT1("evdev", "EventFactoryEvdev::DispatchKeyEvent", "device",
                params.device_id);
-  keyboard_.OnKeyChange(params.code, params.down, params.timestamp,
-                        params.device_id);
+  keyboard_.OnKeyChange(params.code, params.down, params.enable_repeat,
+                        params.timestamp, params.device_id);
 }
 
 void EventFactoryEvdev::DispatchMouseMoveEvent(
@@ -199,7 +199,14 @@
   }
 
   int flag = modifiers_.GetEventFlagFromModifier(modifier);
+  bool was_down = modifiers_.GetModifierFlags() & flag;
   modifiers_.UpdateModifier(modifier, params.down);
+  bool down = modifiers_.GetModifierFlags() & flag;
+
+  // Suppress nested clicks. EventModifiersEvdev counts presses, we only
+  // dispatch an event on 0-1 (first press) and 1-0 (last release) transitions.
+  if (down == was_down)
+    return;
 
   MouseEvent event(params.down ? ui::ET_MOUSE_PRESSED : ui::ET_MOUSE_RELEASED,
                    params.location, params.location, params.timestamp,
diff --git a/ui/events/ozone/evdev/input_controller_evdev.cc b/ui/events/ozone/evdev/input_controller_evdev.cc
index c5b44ad8..7e459d1 100644
--- a/ui/events/ozone/evdev/input_controller_evdev.cc
+++ b/ui/events/ozone/evdev/input_controller_evdev.cc
@@ -63,7 +63,7 @@
 }
 
 void InputControllerEvdev::SetNumLockEnabled(bool enabled) {
-  NOTIMPLEMENTED();
+  // No num lock on Chrome OS.
 }
 
 bool InputControllerEvdev::IsAutoRepeatEnabled() {
diff --git a/ui/events/ozone/evdev/input_injector_evdev.cc b/ui/events/ozone/evdev/input_injector_evdev.cc
index 2b574bd..86bc35b 100644
--- a/ui/events/ozone/evdev/input_injector_evdev.cc
+++ b/ui/events/ozone/evdev/input_injector_evdev.cc
@@ -66,16 +66,18 @@
       kDeviceIdForInjection, cursor_->GetLocation(), EventTimeForNow()));
 }
 
-void InputInjectorEvdev::InjectKeyPress(DomCode physical_key, bool down) {
-  if (physical_key == DomCode::NONE) {
+void InputInjectorEvdev::InjectKeyPress(DomCode physical_key,
+                                        bool down,
+                                        bool enable_repeat) {
+  if (physical_key == DomCode::NONE)
     return;
-  }
 
   int native_keycode = KeycodeConverter::DomCodeToNativeKeycode(physical_key);
   int evdev_code = NativeCodeToEvdevCode(native_keycode);
 
-  dispatcher_->DispatchKeyEvent(KeyEventParams(
-      kDeviceIdForInjection, evdev_code, down, EventTimeForNow()));
+  dispatcher_->DispatchKeyEvent(KeyEventParams(kDeviceIdForInjection,
+                                               evdev_code, down, enable_repeat,
+                                               EventTimeForNow()));
 }
 
 }  // namespace ui
diff --git a/ui/events/ozone/evdev/input_injector_evdev.h b/ui/events/ozone/evdev/input_injector_evdev.h
index 82e3f68..59b5e36 100644
--- a/ui/events/ozone/evdev/input_injector_evdev.h
+++ b/ui/events/ozone/evdev/input_injector_evdev.h
@@ -27,7 +27,9 @@
   void InjectMouseButton(EventFlags button, bool down) override;
   void InjectMouseWheel(int delta_x, int delta_y) override;
   void MoveCursorTo(const gfx::PointF& location) override;
-  void InjectKeyPress(DomCode physical_key, bool down) override;
+  void InjectKeyPress(DomCode physical_key,
+                      bool down,
+                      bool enable_repeat) override;
 
  private:
   // Shared cursor state.
diff --git a/ui/events/ozone/evdev/keyboard_evdev.cc b/ui/events/ozone/evdev/keyboard_evdev.cc
index 1def4c6..36f2bf6 100644
--- a/ui/events/ozone/evdev/keyboard_evdev.cc
+++ b/ui/events/ozone/evdev/keyboard_evdev.cc
@@ -74,22 +74,20 @@
 
 void KeyboardEvdev::OnKeyChange(unsigned int key,
                                 bool down,
+                                bool enable_repeat,
                                 base::TimeDelta timestamp,
                                 int device_id) {
   if (key > KEY_MAX)
     return;
 
-  if (down == key_state_.test(key))
-    return;
+  bool was_down = key_state_.test(key);
+  bool repeat = down && was_down;
+  if (!down && !was_down)
+    return;  // Key already released.
 
-  // State transition: !(down) -> (down)
-  if (down)
-    key_state_.set(key);
-  else
-    key_state_.reset(key);
-
-  UpdateKeyRepeat(key, down, device_id);
-  DispatchKey(key, down, false /* repeat */, timestamp, device_id);
+  key_state_.set(key, down);
+  UpdateKeyRepeat(key, down, enable_repeat, device_id);
+  DispatchKey(key, down, repeat, timestamp, device_id);
 }
 
 void KeyboardEvdev::SetCapsLockEnabled(bool enabled) {
@@ -143,8 +141,9 @@
 
 void KeyboardEvdev::UpdateKeyRepeat(unsigned int key,
                                     bool down,
+                                    bool enable_repeat,
                                     int device_id) {
-  if (!repeat_enabled_)
+  if (!repeat_enabled_ || !enable_repeat)
     StopKeyRepeat();
   else if (key != repeat_key_ && down)
     StartKeyRepeat(key, device_id);
diff --git a/ui/events/ozone/evdev/keyboard_evdev.h b/ui/events/ozone/evdev/keyboard_evdev.h
index 8a5108e..7071831 100644
--- a/ui/events/ozone/evdev/keyboard_evdev.h
+++ b/ui/events/ozone/evdev/keyboard_evdev.h
@@ -36,6 +36,7 @@
   // Handlers for raw key presses & releases.
   void OnKeyChange(unsigned int code,
                    bool down,
+                   bool enable_repeat,
                    base::TimeDelta timestamp,
                    int device_id);
 
@@ -53,7 +54,10 @@
  private:
   void UpdateModifier(int modifier_flag, bool down);
   void UpdateCapsLockLed();
-  void UpdateKeyRepeat(unsigned int key, bool down, int device_id);
+  void UpdateKeyRepeat(unsigned int key,
+                       bool down,
+                       bool enable_repeat,
+                       int device_id);
   void StartKeyRepeat(unsigned int key, int device_id);
   void StopKeyRepeat();
   void ScheduleKeyRepeat(const base::TimeDelta& delay);
diff --git a/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc b/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc
index 6ea8799..db41c1c8 100644
--- a/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc
+++ b/ui/events/ozone/evdev/libgestures_glue/gesture_interpreter_libevdev_cros.cc
@@ -398,7 +398,8 @@
                                  metrics->data[0],
                                  metrics->data[1],
                                  metrics->type);
-  NOTIMPLEMENTED();
+
+  // TODO(spang): Hook up metrics.
 }
 
 void GestureInterpreterLibevdevCros::DispatchChangedMouseButtons(
@@ -451,7 +452,8 @@
 
       // Dispatch key press or release to keyboard.
       dispatcher_->DispatchKeyEvent(
-          KeyEventParams(id_, key, value, StimeToTimedelta(timestamp)));
+          KeyEventParams(id_, key, value, true /* enable_repeat */,
+                         StimeToTimedelta(timestamp)));
     }
   }
 
diff --git a/ui/file_manager/audio_player/audio_player.html b/ui/file_manager/audio_player/audio_player.html
index cc784faf..0fecd84 100644
--- a/ui/file_manager/audio_player/audio_player.html
+++ b/ui/file_manager/audio_player/audio_player.html
@@ -13,6 +13,13 @@
   <title>&#xFEFF;</title>
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
   <link rel="stylesheet" type="text/css" href="css/audio_player.css">
+  <link rel="import" href="elements/audio_player.html">
+</head>
+<body>
+  <div class="audio-player">
+    <!-- Place the audio player. -->
+    <audio-player></audio-player>
+  </div>
 
   <!-- Don't load mediaplayer_scripts.js when flattening is disabled -->
   <if expr="False"><!-- </if>
@@ -49,169 +56,6 @@
 
     <script src="js/audio_player.js"></script>
     <script src="js/audio_player_model.js"></script>
-
-    <script src="elements/track_list.js"></script>
-    <script src="elements/control_panel.js"></script>
-    <script src="elements/volume_controller.js"></script>
-    <script src="elements/audio_player.js"></script>
-   </if>
- </head>
-<body>
-  <!-- Definition of <track-list> tag. -->
-  <polymer-element name="track-list" attributes="tracks">
-    <template>
-      <link rel="stylesheet" href="elements/track_list.css">
-      <template id="tracks" repeat="{{track, index in tracks}}">
-        <div class="track" active?="{{track.active}}" index="{{index}}" on-click="{{trackClicked}}">
-          <div class="data">
-            <div class="data-title">{{track.title}}</div>
-            <div class="data-artist">{{track.artist}}</div>
-          </div>
-        </div>
-      </template>
-    </template>
-  </polymer-element>
-
-  <!-- Definition of <control-panel> tag. -->
-  <polymer-element name="control-panel">
-    <template>
-      <link rel="stylesheet" href="elements/control_panel.css">
-
-      <div class="controls">
-        <div class="upper-controls time-controls">
-          <div class="time media-control">
-            <div class="current">{{timeString_}}</div>
-          </div>
-          <div class="progress media-control custom-slider">
-            <input name="timeInput" type="range" touch-action="manipulation"
-                   min="0" max="{{duration}}" value="{{time}}">
-            <div class="bar">
-              <div class="filled" style="width: {{time/duration*100}}%;"></div>
-              <div class="cap left"></div>
-              <div class="cap right"></div>
-            </div>
-          </div>
-          <div class="time media-control">
-            <div class="duration">{{durationString_}}</div>
-          </div>
-        </div>
-        <div class="lower-controls audio-controls">
-          <!-- Shuffle toggle button in the bottom line. -->
-          <button class="shuffle-mode media-button toggle" state="default">
-            <label>
-              <input id="shuffleCheckbox"
-                     type="checkbox"
-                     checked="{{model.shuffle}}">
-              <span class="icon"></span>
-            </label>
-          </button>
-
-          <!-- Repeat toggle button in the bottom line. -->
-          <button class="repeat media-button toggle" state="default">
-            <label>
-              <input id="repeatCheckbox"
-                     type="checkbox"
-                     checked="{{model.repeat}}">
-              <span class="icon"></span>
-            </label>
-          </button>
-
-          <!-- Prev button in the bottom line. -->
-          <button class="previous media-button"
-                 state="default"
-                 on-click="{{previousClick}}">
-            <div class="normal default"></div>
-            <div class="disabled"></div>
-          </button>
-
-          <!-- Play button in the bottom line. -->
-          <button class="play media-control media-button"
-                  state='{{playing ? "playing" : "ended"}}'
-                  on-click="{{playClick}}">
-            <div class="normal playing"></div>
-            <div class="normal ended"></div>
-            <div class="disabled"></div>
-          </button>
-
-          <!-- Next button in the bottom line. -->
-          <button class="next media-button"
-                  state="default"
-                  on-click="{{nextClick}}">
-            <div class="normal default"></div>
-            <div class="disabled"></div>
-          </button>
-
-          <div id="volumeContainer"
-               class="default-hidden"
-               anchor-point="bottom center">
-            <volume-controller id="volumeSlider"
-                               width="32" height="85" value="50">
-            </volume-controller>
-
-            <polymer-anchor-point id="anchorHelper"></polymer-anchor-point>
-          </div>
-
-          <!-- Volume button in the bottom line. -->
-          <button id="volumeButton"
-                  class="volume media-button toggle"
-                  state="default"
-                  on-click="{{volumeButtonClick}}"
-                  anchor-point="bottom center">
-            <label>
-              <input type="checkbox" checked="{{volumeSliderShown}}">
-              <span class="icon"></span>
-            </label>
-          </button>
-
-          <!-- Playlist button in the bottom line. -->
-          <button id="playlistButton"
-                  class="playlist media-button toggle"
-                  state="default">
-            <label>
-              <input type="checkbox" checked="{{model.expanded}}">
-              <span class="icon"></span>
-            </label>
-          </button>
-        </div>
-      </div>
-    </template>
-  </polymer-element>
-
-  <!-- Definition of <volume-controller> tag. -->
-  <polymer-element name="volume-controller" attributes="width height value">
-    <template>
-      <link rel="stylesheet" href="elements/volume_controller.css">
-
-      <div id="background"></div>
-      <input name="rawValueInput" id="rawValueInput" touch-action="manipulation"
-             type="range" min="0" max="100" value="{{rawValue}}">
-      <div id="bar">
-        <div class="filled" style="height: {{rawValue}}%;"></div>
-        <div class="cap left"></div>
-        <div class="cap right"></div>
-      </div>
-    </template>
-  </polymer-element>
-
-  <!-- Definition of <audio-player> tag. -->
-  <polymer-element name="audio-player"
-                   attributes="playing currenttrackurl playcount">
-    <template>
-      <link rel="stylesheet" href="elements/audio_player.css">
-
-      <track-list id="trackList" expanded?="{{model.expanded}}"
-                  on-replay="{{onReplayCurrentTrack}}"></track-list>
-      <control-panel id="audioController"
-                     on-next-clicked="{{onControllerNextClicked}}"
-                     on-previous-clicked="{{onControllerPreviousClicked}}">
-      </control-panel>
-      <audio id="audio"></audio>
-    </template>
-  </polymer-element>
-
-  <div class="audio-player">
-    <!-- Place the audio player. -->
-    <audio-player></audio-player>
-  </div>
+  </if>
 </body>
 </html>
diff --git a/ui/file_manager/audio_player/elements/audio_player.html b/ui/file_manager/audio_player/elements/audio_player.html
new file mode 100644
index 0000000..eddeb8d7
--- /dev/null
+++ b/ui/file_manager/audio_player/elements/audio_player.html
@@ -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.
+  -->
+
+<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
+<link rel="import" href="track_list.html">
+<link rel="import" href="control_panel.html">
+
+<polymer-element name="audio-player"
+                 attributes="playing currenttrackurl playcount">
+  <template>
+    <link rel="stylesheet" href="audio_player.css">
+
+    <track-list id="trackList" expanded?="{{model.expanded}}"
+                on-replay="{{onReplayCurrentTrack}}"></track-list>
+    <control-panel id="audioController"
+                   on-next-clicked="{{onControllerNextClicked}}"
+                   on-previous-clicked="{{onControllerPreviousClicked}}">
+    </control-panel>
+    <audio id="audio"></audio>
+  </template>
+  <script src="audio_player.js"></script>
+</polymer-element>
diff --git a/ui/file_manager/audio_player/elements/control_panel.html b/ui/file_manager/audio_player/elements/control_panel.html
new file mode 100644
index 0000000..e8fd56ad
--- /dev/null
+++ b/ui/file_manager/audio_player/elements/control_panel.html
@@ -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.
+  -->
+
+<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
+<link rel="import" href="volume_controller.html">
+
+<polymer-element name="control-panel">
+  <template>
+    <link rel="stylesheet" href="control_panel.css">
+
+    <div class="controls">
+      <div class="upper-controls time-controls">
+        <div class="time media-control">
+          <div class="current">{{timeString_}}</div>
+        </div>
+        <div class="progress media-control custom-slider">
+          <input name="timeInput" type="range" touch-action="manipulation"
+                 min="0" max="{{duration}}" value="{{time}}">
+          <div class="bar">
+            <div class="filled" style="width: {{time/duration*100}}%;"></div>
+            <div class="cap left"></div>
+            <div class="cap right"></div>
+          </div>
+        </div>
+        <div class="time media-control">
+          <div class="duration">{{durationString_}}</div>
+        </div>
+      </div>
+      <div class="lower-controls audio-controls">
+        <!-- Shuffle toggle button in the bottom line. -->
+        <button class="shuffle-mode media-button toggle" state="default">
+          <label>
+            <input id="shuffleCheckbox"
+                   type="checkbox"
+                   checked="{{model.shuffle}}">
+            <span class="icon"></span>
+          </label>
+        </button>
+
+        <!-- Repeat toggle button in the bottom line. -->
+        <button class="repeat media-button toggle" state="default">
+          <label>
+            <input id="repeatCheckbox"
+                   type="checkbox"
+                   checked="{{model.repeat}}">
+            <span class="icon"></span>
+          </label>
+        </button>
+
+        <!-- Prev button in the bottom line. -->
+        <button class="previous media-button"
+               state="default"
+               on-click="{{previousClick}}">
+          <div class="normal default"></div>
+          <div class="disabled"></div>
+        </button>
+
+        <!-- Play button in the bottom line. -->
+        <button class="play media-control media-button"
+                state='{{playing ? "playing" : "ended"}}'
+                on-click="{{playClick}}">
+          <div class="normal playing"></div>
+          <div class="normal ended"></div>
+          <div class="disabled"></div>
+        </button>
+
+        <!-- Next button in the bottom line. -->
+        <button class="next media-button"
+                state="default"
+                on-click="{{nextClick}}">
+          <div class="normal default"></div>
+          <div class="disabled"></div>
+        </button>
+
+        <div id="volumeContainer"
+             class="default-hidden"
+             anchor-point="bottom center">
+          <volume-controller id="volumeSlider"
+                             width="32" height="85" value="50">
+          </volume-controller>
+
+          <polymer-anchor-point id="anchorHelper"></polymer-anchor-point>
+        </div>
+
+        <!-- Volume button in the bottom line. -->
+        <button id="volumeButton"
+                class="volume media-button toggle"
+                state="default"
+                on-click="{{volumeButtonClick}}"
+                anchor-point="bottom center">
+          <label>
+            <input type="checkbox" checked="{{volumeSliderShown}}">
+            <span class="icon"></span>
+          </label>
+        </button>
+
+        <!-- Playlist button in the bottom line. -->
+        <button id="playlistButton"
+                class="playlist media-button toggle"
+                state="default">
+          <label>
+            <input type="checkbox" checked="{{model.expanded}}">
+            <span class="icon"></span>
+          </label>
+        </button>
+      </div>
+    </div>
+  </template>
+  <script src="control_panel.js"></script>
+</polymer-element>
diff --git a/ui/file_manager/audio_player/elements/track_list.html b/ui/file_manager/audio_player/elements/track_list.html
new file mode 100644
index 0000000..eeeff3a
--- /dev/null
+++ b/ui/file_manager/audio_player/elements/track_list.html
@@ -0,0 +1,23 @@
+<!--
+  -- 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.
+  -->
+
+<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
+
+<polymer-element name="track-list" attributes="tracks">
+  <template>
+    <link rel="stylesheet" href="track_list.css">
+
+    <template id="tracks" repeat="{{track, index in tracks}}">
+      <div class="track" active?="{{track.active}}" index="{{index}}" on-click="{{trackClicked}}">
+        <div class="data">
+          <div class="data-title">{{track.title}}</div>
+          <div class="data-artist">{{track.artist}}</div>
+        </div>
+      </div>
+    </template>
+  </template>
+  <script src="track_list.js"></script>
+</polymer-element>
diff --git a/ui/file_manager/audio_player/elements/volume_controller.html b/ui/file_manager/audio_player/elements/volume_controller.html
new file mode 100644
index 0000000..db64ec6
--- /dev/null
+++ b/ui/file_manager/audio_player/elements/volume_controller.html
@@ -0,0 +1,23 @@
+<!--
+  -- 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.
+  -->
+
+<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
+
+<polymer-element name="volume-controller" attributes="width height value">
+  <template>
+    <link rel="stylesheet" href="volume_controller.css">
+
+    <div id="background"></div>
+    <input name="rawValueInput" id="rawValueInput" touch-action="manipulation"
+           type="range" min="0" max="100" value="{{rawValue}}">
+    <div id="bar">
+      <div class="filled" style="height: {{rawValue}}%;"></div>
+      <div class="cap left"></div>
+      <div class="cap right"></div>
+    </div>
+  </template>
+  <script src="volume_controller.js"></script>
+</polymer-element>
diff --git a/ui/file_manager/audio_player/js/audio_player_scripts.js b/ui/file_manager/audio_player/js/audio_player_scripts.js
index f35bc4e9..ec50fc7 100644
--- a/ui/file_manager/audio_player/js/audio_player_scripts.js
+++ b/ui/file_manager/audio_player/js/audio_player_scripts.js
@@ -13,8 +13,6 @@
 if (!('allowsEval' in document.securityPolicy))
   document.securityPolicy['allowsEval'] = false;
 
-<include src="../../../../third_party/polymer/components/polymer/polymer.js">
-
 (function() {
 
 // 'strict mode' is invoked for this scope.
@@ -42,11 +40,6 @@
 <include src="audio_player.js"/>
 <include src="audio_player_model.js"/>
 
-<include src="../elements/track_list.js"/>
-<include src="../elements/control_panel.js"/>
-<include src="../elements/volume_controller.js"/>
-<include src="../elements/audio_player.js"/>
-
 window.reload = reload;
 window.unload = unload;
 window.AudioPlayer = AudioPlayer;
diff --git a/ui/file_manager/audio_player/js/background.js b/ui/file_manager/audio_player/js/background.js
index edc25e5d..233bea3 100644
--- a/ui/file_manager/audio_player/js/background.js
+++ b/ui/file_manager/audio_player/js/background.js
@@ -10,7 +10,7 @@
  * @type {string}
  * @const
  */
-var AUDIO_PLAYER_ICON = 'audio_player/icons/audio-player-64.png';
+var AUDIO_PLAYER_ICON = 'icons/audio-player-64.png';
 
 /**
  * Configuration of the audio player panel.
@@ -158,7 +158,7 @@
                          fulfill.bind(null, null));
     });
   }).then(function() {
-    audioPlayer.setIcon('icons/audio-player-64.png');
+    audioPlayer.setIcon(AUDIO_PLAYER_ICON);
     audioPlayer.rawAppWindow.focus();
   }).catch(function(error) {
     console.error('Launch failed' + error.stack || error);
diff --git a/ui/file_manager/audio_player/manifest.json b/ui/file_manager/audio_player/manifest.json
index 2ef7522..b97f24f 100644
--- a/ui/file_manager/audio_player/manifest.json
+++ b/ui/file_manager/audio_player/manifest.json
@@ -32,9 +32,6 @@
   ],
   "file_handlers": {
     "audio": {
-      "types": [
-        "audio/*"
-      ],
       "extensions": [
         "amr",
         "flac",
diff --git a/ui/file_manager/file_manager/background/js/launcher_search.js b/ui/file_manager/file_manager/background/js/launcher_search.js
index 7806f9b..381831a2 100644
--- a/ui/file_manager/file_manager/background/js/launcher_search.js
+++ b/ui/file_manager/file_manager/background/js/launcher_search.js
@@ -118,14 +118,19 @@
         chrome.launcherSearchProvider.setSearchResults(
             queryId,
             results.map(function(result) {
-              // Use high-dpi icons since preferred icon size is 24px in the
-              // current implementation.
-              //
               // TODO(yawano): Use filetype_folder_shared.png for a shared
               //     folder.
+              // TODO(yawano): Add archive launcher filetype icon.
+              var fileType = FileType.getIcon(result.entry);
+              if (fileType === 'UNKNOWN' || fileType === 'archive')
+                fileType = 'generic';
+
+              var useHighDpiIcon = window.devicePixelRatio > 1.0;
               var iconUrl = chrome.runtime.getURL(
-                  'foreground/images/filetype/2x/filetype_' +
-                  FileType.getIcon(result.entry) + '.png');
+                  'foreground/images/launcher_filetypes/' +
+                  (useHighDpiIcon ? '2x/' : '') + 'launcher_filetype_' +
+                  fileType + '.png');
+
               return {
                 itemId: result.entry.toURL(),
                 title: result.entry.name,
diff --git a/ui/file_manager/file_manager/common/js/file_type.js b/ui/file_manager/file_manager/common/js/file_type.js
index 030ae250..95fc35d6 100644
--- a/ui/file_manager/file_manager/common/js/file_type.js
+++ b/ui/file_manager/file_manager/common/js/file_type.js
@@ -15,31 +15,38 @@
   // Images
   {
     type: 'image', name: 'IMAGE_FILE_TYPE', subtype: 'JPEG',
-    pattern: /\.jpe?g$/i
+    pattern: /\.jpe?g$/i,
+    mimePattern: /image\/jpeg/i,
   },
   {
     type: 'image', name: 'IMAGE_FILE_TYPE', subtype: 'BMP',
-    pattern: /\.bmp$/i
+    pattern: /\.bmp$/i,
+    mimePattern: /image\/bmp/i,
   },
   {
     type: 'image', name: 'IMAGE_FILE_TYPE', subtype: 'GIF',
-    pattern: /\.gif$/i
+    pattern: /\.gif$/i,
+    mimePattern: /image\/gif/i,
   },
   {
     type: 'image', name: 'IMAGE_FILE_TYPE', subtype: 'ICO',
-    pattern: /\.ico$/i
+    pattern: /\.ico$/i,
+    mimePattern: /image\/x\-icon/i,
   },
   {
     type: 'image', name: 'IMAGE_FILE_TYPE', subtype: 'PNG',
-    pattern: /\.png$/i
+    pattern: /\.png$/i,
+    mimePattern: /image\/png/i
   },
   {
     type: 'image', name: 'IMAGE_FILE_TYPE', subtype: 'WebP',
-    pattern: /\.webp$/i
+    pattern: /\.webp$/i,
+    mimePattern: /image\/webp/i
   },
   {
     type: 'image', name: 'IMAGE_FILE_TYPE', subtype: 'TIFF',
-    pattern: /\.tiff?$/i
+    pattern: /\.tiff?$/i,
+    mimePattern: /image\/tiff/i
   },
 
   // Raw
@@ -79,85 +86,104 @@
   // Video
   {
     type: 'video', name: 'VIDEO_FILE_TYPE', subtype: '3GP',
-    pattern: /\.3gp$/i
+    pattern: /\.3gp$/i,
+    mimePattern: /video\/3gpp/i
   },
   {
     type: 'video', name: 'VIDEO_FILE_TYPE', subtype: 'AVI',
-    pattern: /\.avi$/i
+    pattern: /\.avi$/i,
+    mimePattern: /video\/x\-msvideo/i
   },
   {
     type: 'video', name: 'VIDEO_FILE_TYPE', subtype: 'QuickTime',
-    pattern: /\.mov$/i
+    pattern: /\.mov$/i,
+    mimePattern: /video\/quicktime/i
   },
   {
     type: 'video', name: 'VIDEO_FILE_TYPE', subtype: 'MKV',
-    pattern: /\.mkv$/i
+    pattern: /\.mkv$/i,
+    mimePattern: /video\/x\-matroska/i
   },
   {
     type: 'video', name: 'VIDEO_FILE_TYPE', subtype: 'MPEG',
-    pattern: /\.m(p4|4v|pg|peg|pg4|peg4)$/i
+    pattern: /\.m(p4|4v|pg|peg|pg4|peg4)$/i,
+    mimePattern: /video\/mp(4|eg)/i
   },
   {
     type: 'video', name: 'VIDEO_FILE_TYPE', subtype: 'OGG',
-    pattern: /\.og(m|v|x)$/i
+    pattern: /\.og(m|v|x)$/i,
+    mimePattern: /(application|video)\/ogg/i
   },
   {
     type: 'video', name: 'VIDEO_FILE_TYPE', subtype: 'WebM',
-    pattern: /\.webm$/i
+    pattern: /\.webm$/i,
+    mimePattern: /video\/webm/i
   },
 
   // Audio
   {
     type: 'audio', name: 'AUDIO_FILE_TYPE', subtype: 'AMR',
-    pattern: /\.amr$/i
+    pattern: /\.amr$/i,
+    mimePattern: /audio\/amr/i
   },
   {
     type: 'audio', name: 'AUDIO_FILE_TYPE', subtype: 'FLAC',
-    pattern: /\.flac$/i
+    pattern: /\.flac$/i,
+    mimePattern: /audio\/flac/i
   },
   {
     type: 'audio', name: 'AUDIO_FILE_TYPE', subtype: 'MP3',
-    pattern: /\.mp3$/i
+    pattern: /\.mp3$/i,
+    mimePattern: /audio\/mpeg/i
   },
   {
     type: 'audio', name: 'AUDIO_FILE_TYPE', subtype: 'MPEG',
-    pattern: /\.m4a$/i
+    pattern: /\.m4a$/i,
+    mimePattern: /audio\/mp4a-latm/i
   },
   {
     type: 'audio', name: 'AUDIO_FILE_TYPE', subtype: 'OGG',
-    pattern: /\.og(a|g)$/i
+    pattern: /\.og(a|g)$/i,
+    mimePattern: /audio\/ogg/i
   },
   {
     type: 'audio', name: 'AUDIO_FILE_TYPE', subtype: 'WAV',
-    pattern: /\.wav$/i
+    pattern: /\.wav$/i,
+    mimePattern: /audio\/x\-wav/i
   },
 
   // Text
   {
     type: 'text', name: 'PLAIN_TEXT_FILE_TYPE', subtype: 'TXT',
-    pattern: /\.txt$/i
+    pattern: /\.txt$/i,
+    mimePattern: /text\/plain/i
   },
 
   // Archive
   {
     type: 'archive', name: 'ZIP_ARCHIVE_FILE_TYPE', subtype: 'ZIP',
-    pattern: /\.zip$/i
+    pattern: /\.zip$/i,
+    mimePattern: /application\/zip/i
   },
   {
     type: 'archive', name: 'RAR_ARCHIVE_FILE_TYPE', subtype: 'RAR',
-    pattern: /\.rar$/i
+    pattern: /\.rar$/i,
+    mimePattern: /application\/x\-rar\-compressed/i
   },
   {
     type: 'archive', name: 'TAR_ARCHIVE_FILE_TYPE', subtype: 'TAR',
-    pattern: /\.tar$/i
+    pattern: /\.tar$/i,
+    mimePattern: /application\/x\-tar/i
   },
   {
     type: 'archive', name: 'TAR_BZIP2_ARCHIVE_FILE_TYPE', subtype: 'TBZ2',
-    pattern: /\.(tar\.bz2|tbz|tbz2)$/i
+    pattern: /\.(tar\.bz2|tbz|tbz2)$/i,
+    mimePattern: /application\/x\-bzip2/i
   },
   {
     type: 'archive', name: 'TAR_GZIP_ARCHIVE_FILE_TYPE', subtype: 'TGZ',
-    pattern: /\.(tar\.|t)gz$/i
+    pattern: /\.(tar\.|t)gz$/i,
+    mimePattern: /application\/x\-gzip/i
   },
 
   // Hosted docs.
@@ -199,23 +225,31 @@
   // Others
   {
     type: 'document', icon: 'pdf', name: 'PDF_DOCUMENT_FILE_TYPE',
-    subtype: 'PDF', pattern: /\.pdf$/i
+    subtype: 'PDF', pattern: /\.pdf$/i,
+    mimePattern: /application\/pdf/i
   },
   {
     type: 'document', name: 'HTML_DOCUMENT_FILE_TYPE',
-    subtype: 'HTML', pattern: /\.(html?|mht(ml)?|shtml|xht(ml)?)$/i
+    subtype: 'HTML', pattern: /\.(html?|mht(ml)?|shtml|xht(ml)?)$/i,
+    mimePattern: /text\/html/i
   },
   {
     type: 'document', icon: 'word', name: 'WORD_DOCUMENT_FILE_TYPE',
-    subtype: 'Word', pattern: /\.(doc|docx)$/i
+    subtype: 'Word', pattern: /\.(doc|docx)$/i,
+    mimePattern: new RegExp('/application\/(msword|vnd\.openxmlformats\-' +
+          'officedocument\./wordprocessingml\.document)/i')
   },
   {
     type: 'document', icon: 'ppt', name: 'POWERPOINT_PRESENTATION_FILE_TYPE',
-    subtype: 'PPT', pattern: /\.(ppt|pptx)$/i
+    subtype: 'PPT', pattern: /\.(ppt|pptx)$/i,
+    mimePattern: new RegExp('/application\/(vnd\.ms-powerpoint|\.' +
+          'openxmlformats\-/officedocument\.wordprocessingml\.presentation)/i')
   },
   {
     type: 'document', icon: 'excel', name: 'EXCEL_FILE_TYPE',
-    subtype: 'Excel', pattern: /\.(xls|xlsx)$/i
+    subtype: 'Excel', pattern: /\.(xls|xlsx)$/i,
+    mimePattern: new RegExp('/application\/(vnd\.ms-excel|\.openxmlformats\-/' +
+        'officedocument\.wordprocessingml\.sheet)/i')
   }
 ];
 
@@ -273,18 +307,29 @@
 };
 
 /**
- * Gets the file type object for a given file.
- * @param {Entry} entry Reference to the file.
+ * Gets the file type object for a given entry. If mime type is provided, then
+ * uses it with higher priority than the extension.
+ *
+ * @param {Entry} entry Reference to the entry.
+ * @param {string=} opt_mimeType Optional mime type for the entry.
  * @return {!Object} The matching file type object or an empty object.
  */
-FileType.getType = function(entry) {
+FileType.getType = function(entry, opt_mimeType) {
   if (entry.isDirectory)
     return FileType.DIRECTORY;
 
-  var types = FileType.types;
-  for (var i = 0; i < types.length; i++) {
-    if (types[i].pattern.test(entry.name))
-      return types[i];
+  if (opt_mimeType) {
+    for (var i = 0; i < FileType.types.length; i++) {
+      if (FileType.types[i].mimePattern &&
+          FileType.types[i].mimePattern.test(opt_mimeType)) {
+        return FileType.types[i];
+      }
+    }
+  }
+
+  for (var i = 0; i < FileType.types.length; i++) {
+    if (FileType.types[i].pattern.test(entry.name))
+      return FileType.types[i];
   }
 
   // Unknown file type.
@@ -303,72 +348,80 @@
  * Gets the media type for a given file.
  *
  * @param {Entry} entry Reference to the file.
+ * @param {string=} opt_mimeType Optional mime type for the file.
  * @return {string} The value of 'type' property from one of the elements in
  *     FileType.types or undefined.
  */
-FileType.getMediaType = function(entry) {
-  return FileType.getType(entry).type;
+FileType.getMediaType = function(entry, opt_mimeType) {
+  return FileType.getType(entry, opt_mimeType).type;
 };
 
 /**
  * @param {Entry} entry Reference to the file.
+ * @param {string=} opt_mimeType Optional mime type for the file.
  * @return {boolean} True if audio file.
  */
-FileType.isAudio = function(entry) {
-  return FileType.getMediaType(entry) === 'audio';
+FileType.isAudio = function(entry, opt_mimeType) {
+  return FileType.getMediaType(entry, opt_mimeType) === 'audio';
 };
 
 /**
  * Returns whether the |entry| is image file that can be opened in browser.
  * Note that it returns false for RAW images.
  * @param {Entry} entry Reference to the file.
+ * @param {string=} opt_mimeType Optional mime type for the file.
  * @return {boolean} True if image file.
  */
-FileType.isImage = function(entry) {
-  return FileType.getMediaType(entry) === 'image';
+FileType.isImage = function(entry, opt_mimeType) {
+  return FileType.getMediaType(entry, opt_mimeType) === 'image';
 };
 
 /**
  * @param {Entry} entry Reference to the file.
+ * @param {string=} opt_mimeType Optional mime type for the file.
  * @return {boolean} True if video file.
  */
-FileType.isVideo = function(entry) {
-  return FileType.getMediaType(entry) === 'video';
+FileType.isVideo = function(entry, opt_mimeType) {
+  return FileType.getMediaType(entry, opt_mimeType) === 'video';
 };
 
 /**
  * @param {Entry} entry Reference to the file.
+ * @param {string=} opt_mimeType Optional mime type for the file.
  * @return {boolean} True if raw file.
  */
-FileType.isRaw = function(entry) {
-  return FileType.getMediaType(entry) === 'raw';
+FileType.isRaw = function(entry, opt_mimeType) {
+  return FileType.getMediaType(entry, opt_mimeType) === 'raw';
 };
 
 /**
  * Files with more pixels won't have preview.
- * @param {Entry} entry Reference to the file.
  * @param {!Array<string>} types
+ * @param {Entry} entry Reference to the file.
+ * @param {string=} opt_mimeType Optional mime type for the file.
  * @return {boolean} True if type is in specified set
  */
-FileType.isType = function(entry, types) {
-  var type = FileType.getMediaType(entry);
+FileType.isType = function(types, entry, opt_mimeType) {
+  var type = FileType.getMediaType(entry, opt_mimeType);
   return !!type && types.indexOf(type) !== -1;
 };
 
 /**
  * @param {Entry} entry Reference to the file.
+ * @param {string=} opt_mimeType Optional mime type for the file.
  * @return {boolean} Returns true if the file is hosted.
  */
-FileType.isHosted = function(entry) {
-  return FileType.getType(entry).type === 'hosted';
+FileType.isHosted = function(entry, opt_mimeType) {
+  return FileType.getType(entry, opt_mimeType).type === 'hosted';
 };
 
 /**
  * @param {Entry} entry Reference to the file.
+ * @param {string=} opt_mimeType Optional mime type for the file.
  * @return {string} Returns string that represents the file icon.
  *     It refers to a file 'images/filetype_' + icon + '.png'.
  */
-FileType.getIcon = function(entry) {
-  var fileType = FileType.getType(entry);
+FileType.getIcon = function(entry, opt_mimeType) {
+  var fileType = FileType.getType(entry, opt_mimeType);
   return fileType.icon || fileType.type || 'unknown';
 };
diff --git a/ui/file_manager/file_manager/common/js/importer_common.js b/ui/file_manager/file_manager/common/js/importer_common.js
index 448645d..6a5eb19 100644
--- a/ui/file_manager/file_manager/common/js/importer_common.js
+++ b/ui/file_manager/file_manager/common/js/importer_common.js
@@ -75,9 +75,10 @@
  * @return {boolean}
  */
 importer.isEligibleType = function(entry) {
+  // TODO(mtomasz): Add support to mime types.
   return !!entry &&
       entry.isFile &&
-      FileType.isType(entry, ['image', 'raw', 'video']);
+      FileType.isType(['image', 'raw', 'video'], entry);
 };
 
 /**
diff --git a/ui/file_manager/file_manager/common/js/polymer_config.js b/ui/file_manager/file_manager/common/js/polymer_config.js
new file mode 100644
index 0000000..3b20eae
--- /dev/null
+++ b/ui/file_manager/file_manager/common/js/polymer_config.js
@@ -0,0 +1,5 @@
+// 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.
+
+Polymer = {dom: 'shadow'};
diff --git a/ui/file_manager/file_manager/foreground/css/common.css b/ui/file_manager/file_manager/foreground/css/common.css
index 5db5a97d..6a1b0bd 100644
--- a/ui/file_manager/file_manager/foreground/css/common.css
+++ b/ui/file_manager/file_manager/foreground/css/common.css
@@ -125,7 +125,7 @@
   color: rgb(51, 51, 51);
   outline: none;
   overflow: hidden;
-  padding: 4px 0;
+  padding: 8px 0;
   transition: opacity 200ms ease-in;
   z-index: 600;  /* Must be below the overlay pane (1000). */
 }
@@ -147,7 +147,7 @@
   background-repeat: no-repeat;
   line-height: 32px;
   outline: none;
-  padding: 0 12px;
+  padding: 0 8px;
 }
 
 html[dir='rtl'] cr-menu.chrome-menu > :not(hr) {
@@ -189,13 +189,12 @@
 }
 
 cr-menu.chrome-menu > cr-menu-item[disabled] {
-  color: rgb(219, 219, 219);
+  color: rgba(51, 51, 51, 0.20);
 }
 
 cr-menu.chrome-menu > cr-menu-item:not([disabled])[selected],
 cr-menu.chrome-menu > cr-menu-item:not([disabled]):active {
-  background-color: rgb(33, 150, 243);
-  color: white;
+  background-color: rgba(0, 0, 0, 0.08);
 }
 
 cr-menu.chrome-menu > hr {
@@ -218,19 +217,12 @@
   display: none;
 }
 
-cr-menu[showShortcuts] >
-cr-menu-item[shortcutText][selected]:not([disabled])::after {
-  color: white;
-}
-
 /**
  * Ok/Cancel style buttons
  * Height: 31px (content:21px + border:5px * 2)
+ * TODO(fukino): Remove these styles once our dialogs get material design.
  **/
-button,
-input[type='button'],
-input[type='submit'],
-select {
+.cr-dialog-buttons > button {
   background-color: rgb(250, 250, 250);
   background-image: none;
   background-position: center;
@@ -258,10 +250,7 @@
   -webkit-margin-start: 12px;
 }
 
-button:hover,
-input[type='button']:hover,
-input[type='submit']:hover,
-select:hover {
+.cr-dialog-buttons > button:hover {
   border-image: -webkit-image-set(
     url(chrome://resources/images/apps/button_hover.png) 1x,
     url(chrome://resources/images/2x/apps/button_hover.png)
@@ -269,9 +258,7 @@
   color: #222;
 }
 
-button:active,
-input[type='button']:active,
-input[type='submit']:active {
+.cr-dialog-buttons > button:active {
   border-image: -webkit-image-set(
     url(chrome://resources/images/apps/button_pressed.png) 1x,
     url(chrome://resources/images/2x/apps/button_pressed.png)
@@ -279,12 +266,8 @@
   color: #333;
 }
 
-button[disabled],
-input[type='button'][disabled],
-input[type='submit'][disabled],
-button[disabled]:hover,
-input[type='button'][disabled]:hover,
-input[type='submit'][disabled]:hover {
+.cr-dialog-buttons > button[disabled],
+.cr-dialog-buttons > button[disabled]:hover {
   background-color: rgb(250, 250, 250);
   background-image: none;
   border-image: -webkit-image-set(
@@ -294,13 +277,6 @@
   color: rgb(150, 150, 150);
 }
 
-select:not([size]):hover,
-select[size='0']:hover,
-select[size='1']:hover {
-  /* Original value is '5 fill', which hides the dropdown triangle. */
-  border-image-slice: 5;
-}
-
 /* Style for <button>s to have similar style with Polymer's <paper-button>. */
 .imitate-paper-button {
   -webkit-user-select: none;
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index dc999f3..8533865 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -268,7 +268,9 @@
 
 .dialog-header button {
   cursor: pointer;
+  position: relative;
   text-transform: uppercase;
+  z-index: 1;
 }
 
 .dialog-header button,
@@ -316,7 +318,7 @@
   display: none !important;
 }
 
-.dialog-header core-icon,
+.dialog-header iron-icon,
 .dialog-header .icon {
   height: 16px;
   width: 16px;
@@ -342,7 +344,7 @@
   width: 32px;
 }
 
-.dialog-header button.icon-button > core-icon {
+.dialog-header button.icon-button > iron-icon {
   margin: 8px;
 }
 
@@ -427,7 +429,7 @@
   width: 24px;
 }
 
-#cloud-import-details-button core-icon {
+#cloud-import-details-button iron-icon {
   margin: 8px 4px;
 }
 
@@ -480,7 +482,7 @@
   margin-top: .2em;
 }
 
-#cloud-import-details .status core-icon {
+#cloud-import-details .status iron-icon {
   display: block;
   height: 16px;
   opacity: .6;
@@ -547,7 +549,7 @@
   width: 240px;  /* initial value, same as .dialog-navigation-list's width. */
 }
 
-#cancel-selection-button > core-icon {
+#cancel-selection-button > iron-icon {
   -webkit-margin-end: 6px;
 }
 
@@ -582,23 +584,30 @@
   -webkit-appearance: none;
 }
 
-#search-box paper-input-decorator {
+#search-box paper-input-container {
   margin-top: -4px;
 }
 
-#search-box paper-input-decorator /deep/ ::-webkit-input-placeholder {
+#search-box paper-input-container /deep/ ::-webkit-input-placeholder {
   color: rgba(255, 255, 255, 0.5);
 }
 
-#search-box paper-input-decorator /deep/ .unfocused-underline {
+#search-box paper-input-container /deep/ .unfocused-line {
   background-color: rgba(255, 255, 255, 0.3);
 }
 
-#search-box paper-input-decorator /deep/ .focused-underline {
+#search-box paper-input-container /deep/ .focused-line {
   background-color: white;
   height: 1px;
 }
 
+#search-box paper-input-container /deep/ .input-content ::content input {
+  color: inherit;
+  font: inherit;
+  margin: 0.5em 0 0.25em;
+  padding: 0;
+}
+
 #search-box.has-cursor,
 #search-box.has-text {
   -webkit-margin-end: 12px;
@@ -740,20 +749,28 @@
   margin: 3px 0 !important;
 }
 
-.dialog-footer paper-input-decorator {
+.dialog-footer select {
+  min-height: 21px;
+}
+
+.dialog-footer paper-input-container {
   color: rgb(51, 51, 51);
   padding: 4px 0;
   width: 100%;
 }
 
-.dialog-footer paper-input-decorator /deep/ .unfocused-underline {
+.dialog-footer paper-input-container /deep/ .unfocused-line {
   background-color: rgb(207, 207, 207);
 }
 
-.dialog-footer paper-input-decorator /deep/ .focused-underline {
+.dialog-footer paper-input-container /deep/ .focused-line {
   background-color: rgb(33, 150, 243);
 }
 
+.dialog-footer paper-input-container /deep/ .input-content ::content input {
+  font: inherit;
+}
+
 .dialog-footer select {
   -webkit-appearance: none;
   background: -webkit-image-set(
@@ -1790,7 +1807,7 @@
   flex: none;
   margin-top: 10px;
   overflow: hidden;
-  padding: 0;
+  padding: 8px 0;
   position: fixed;
   width: 260px !important; /* This overrides the value specified by script. */
   z-index: 550;
@@ -1799,17 +1816,17 @@
 list.autocomplete-suggestions > li {
   align-items: center;
   display: flex;
-  height: 40px;
+  height: 32px;
 }
 
 list.autocomplete-suggestions > li > div.detail-icon {
-  margin: 0 3px;
+  height: 32px;
+  width: 32px;
   flex: none;
 }
 
 list.autocomplete-suggestions > li > div.detail-text {
   flex: auto;
-  margin: 0 4px;
   overflow-x: hidden;
   text-overflow: ellipsis;
 }
@@ -1827,7 +1844,7 @@
 
 list.autocomplete-suggestions > [selected],
 list.autocomplete-suggestions > [lead] {
-  background-color: rgb(222, 243, 254);
+  background-color: rgba(0, 0, 0, 0.08);
 }
 
 #gear-menu {
diff --git a/ui/file_manager/file_manager/foreground/css/file_types.css b/ui/file_manager/file_manager/foreground/css/file_types.css
index 1ddfca7..3b14646 100644
--- a/ui/file_manager/file_manager/foreground/css/file_types.css
+++ b/ui/file_manager/file_manager/foreground/css/file_types.css
@@ -330,11 +330,6 @@
   -webkit-filter: contrast(0) brightness(0.7143);
 }
 
-cr-menu-item.providers-menu-item[selected] .menu-icon {
-  /* Apply the rgb(255, 255, 255) mask. */
-  -webkit-filter: contrast(0) brightness(2);
-}
-
 cr-menu-item.providers-menu-item[command='#install-new-extension'] .menu-icon {
   background-image: -webkit-image-set(
       url(../images/files/ui/store.png) 1x,
diff --git a/ui/file_manager/file_manager/foreground/css/menu.css b/ui/file_manager/file_manager/foreground/css/menu.css
index b4776c6f..74501da 100644
--- a/ui/file_manager/file_manager/foreground/css/menu.css
+++ b/ui/file_manager/file_manager/foreground/css/menu.css
@@ -32,7 +32,7 @@
 
 cr-menu > [shortcutText]::after {
   -webkit-padding-start: 30px;
-  color: rgba(51, 51, 51, 0.5);
+  color: rgb(100, 100, 100);
   content: attr(shortcutText);
   float: right;
 }
@@ -44,7 +44,7 @@
 /* Icon on the left of the item label for cr.ui.ProvidersMenuItem.
    TODO(mtomasz): Upstream to cr.ui.MenuItem. */
 cr-menu-item.providers-menu-item .menu-icon {
-  -webkit-margin-end: 12px;
+  -webkit-margin-end: 8px;
   background: no-repeat 0 center;
   display: inline-block;
   float: left;
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_audio.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_audio.png
new file mode 100644
index 0000000..1f904f0
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_audio.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_chart.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_chart.png
new file mode 100644
index 0000000..9184c43b
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_chart.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_excel.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_excel.png
new file mode 100644
index 0000000..5c88525
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_excel.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_folder.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_folder.png
new file mode 100644
index 0000000..e270776
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_folder.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_form.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_form.png
new file mode 100644
index 0000000..5c1bbad1
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_form.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdoc.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdoc.png
new file mode 100644
index 0000000..13773d4
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdoc.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdraw.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdraw.png
new file mode 100644
index 0000000..57a783b
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdraw.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_generic.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_generic.png
new file mode 100644
index 0000000..e13ca09
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_generic.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gsheet.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gsheet.png
new file mode 100644
index 0000000..c2e929a
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gsheet.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gslides.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gslides.png
new file mode 100644
index 0000000..4fc3d297
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gslides.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gtable.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gtable.png
new file mode 100644
index 0000000..c5522789
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gtable.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_image.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_image.png
new file mode 100644
index 0000000..864d718
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_image.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_map.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_map.png
new file mode 100644
index 0000000..b7eee942
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_map.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_pdf.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_pdf.png
new file mode 100644
index 0000000..e94ea5c
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_pdf.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_ppt.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_ppt.png
new file mode 100644
index 0000000..b1ed30b
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_ppt.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_script.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_script.png
new file mode 100644
index 0000000..d191cda3
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_script.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_shared.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_shared.png
new file mode 100644
index 0000000..8db0c5a1
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_shared.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_sites.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_sites.png
new file mode 100644
index 0000000..06a7b31
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_sites.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_video.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_video.png
new file mode 100644
index 0000000..4618011
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_video.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_word.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_word.png
new file mode 100644
index 0000000..3cd89479
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_word.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_audio.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_audio.png
new file mode 100644
index 0000000..cdec77b
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_audio.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_chart.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_chart.png
new file mode 100644
index 0000000..2dc4d064
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_chart.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_excel.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_excel.png
new file mode 100644
index 0000000..e734419b
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_excel.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_folder.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_folder.png
new file mode 100644
index 0000000..49c41935
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_folder.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_form.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_form.png
new file mode 100644
index 0000000..e849e9da1
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_form.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdoc.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdoc.png
new file mode 100644
index 0000000..ef49d881
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdoc.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdraw.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdraw.png
new file mode 100644
index 0000000..ace9613
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdraw.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_generic.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_generic.png
new file mode 100644
index 0000000..a46c66c8
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_generic.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gsheet.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gsheet.png
new file mode 100644
index 0000000..803cc24
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gsheet.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gslides.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gslides.png
new file mode 100644
index 0000000..b2253ad8
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gslides.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gtable.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gtable.png
new file mode 100644
index 0000000..4458d466
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_gtable.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_image.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_image.png
new file mode 100644
index 0000000..f7ba01b
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_image.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_map.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_map.png
new file mode 100644
index 0000000..eada3fe
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_map.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_pdf.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_pdf.png
new file mode 100644
index 0000000..e0262be
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_pdf.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_ppt.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_ppt.png
new file mode 100644
index 0000000..849a592
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_ppt.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_script.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_script.png
new file mode 100644
index 0000000..425fb90
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_script.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_shared.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_shared.png
new file mode 100644
index 0000000..d41286c
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_shared.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_sites.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_sites.png
new file mode 100644
index 0000000..5141e9d
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_sites.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_video.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_video.png
new file mode 100644
index 0000000..1a15d01
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_video.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_word.png b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_word.png
new file mode 100644
index 0000000..e3106f01
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/images/launcher_filetypes/launcher_filetype_word.png
Binary files differ
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents.js b/ui/file_manager/file_manager/foreground/js/directory_contents.js
index 83d99cf..4b87f4f6 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_contents.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_contents.js
@@ -550,7 +550,9 @@
   else
     this.numFiles_++;
 
-  if (FileType.isImage(entry) || FileType.isRaw(entry))
+  var mimeType = this.metadataModel_.getCache([entry],
+      ['contentMimeType'])[0].contentMimeType;
+  if (FileType.isImage(entry, mimeType) || FileType.isRaw(entry, mimeType))
     this.numImageFiles_++;
 };
 
@@ -565,7 +567,9 @@
   else
     this.numFiles_--;
 
-  if (FileType.isImage(entry) || FileType.isRaw(entry))
+  var mimeType = this.metadataModel_.getCache([entry],
+      ['contentMimeType'])[0].contentMimeType;
+  if (FileType.isImage(entry, mimeType) || FileType.isRaw(entry, mimeType))
     this.numImageFiles_--;
 };
 
@@ -641,8 +645,11 @@
   if (a.isDirectory !== b.isDirectory)
     return a.isDirectory === this.isDescendingOrder_ ? 1 : -1;
 
-  var aType = FileListModel.getFileTypeString(FileType.getType(a));
-  var bType = FileListModel.getFileTypeString(FileType.getType(b));
+  var properties = this.metadataModel_.getCache([a, b], ['contentMimeType']);
+  var aType = FileListModel.getFileTypeString(
+      FileType.getType(a, properties[0].contentMimeType));
+  var bType = FileListModel.getFileTypeString(
+      FileType.getType(b, properties[1].contentMimeType));
 
   var result = util.collator.compare(aType, bType);
   return result !== 0 ? result : util.compareName(a, b);
diff --git a/ui/file_manager/file_manager/foreground/js/import_controller.js b/ui/file_manager/file_manager/foreground/js/import_controller.js
index 6ac1556..05a1180 100644
--- a/ui/file_manager/file_manager/foreground/js/import_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/import_controller.js
@@ -562,9 +562,9 @@
 
   /** @private {Element} */
   this.toolbarIcon_ =
-      document.querySelector('#cloud-import-button core-icon');
+      document.querySelector('#cloud-import-button iron-icon');
   this.statusIcon_ =
-      document.querySelector('#cloud-import-details .status core-icon');
+      document.querySelector('#cloud-import-details .status iron-icon');
 
   /** @private {Element} */
   this.detailsBanner_ = document.querySelector('#cloud-import-details .banner');
diff --git a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js
index 80ff510..b5ee6f45 100644
--- a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.js
@@ -75,7 +75,14 @@
     }
   };
 
-  fileListModel = new FileListModel(thumbnailModel);
+  var metadataModel = {
+    get: function() {},
+    getCache: function(entries, names) {
+      return [{}];
+    }
+  };
+
+  fileListModel = new FileListModel(metadataModel);
 
   directoryModel = {
     __proto__: cr.EventTarget.prototype,
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js
index 41b40f6f..a7e3b2a 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js
@@ -17,7 +17,7 @@
  * @const {!Array<string>}
  */
 FileSystemMetadataProvider.PROPERTY_NAMES = [
-  'modificationTime', 'size', 'present', 'availableOffline', 'contentMimeType'
+  'modificationTime', 'size', 'present', 'availableOffline'
 ];
 
 FileSystemMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype;
@@ -29,26 +29,14 @@
   if (!requests.length)
     return Promise.resolve([]);
   return Promise.all(requests.map(function(request) {
-    return Promise.all([
-        new Promise(function(fulfill, reject) {
-          request.entry.getMetadata(fulfill, reject);
-        }),
-        new Promise(function(fulfill) {
-          if (request.names.indexOf('contentMimeType') > -1) {
-            chrome.fileManagerPrivate.getMimeType(
-                request.entry.toURL(), fulfill);
-          } else {
-            fulfill(null);
-          }
-        })
-    ]).then(function(results) {
+    return new Promise(function(fulfill, reject) {
+      request.entry.getMetadata(fulfill, reject);
+    }).then(function(result) {
       var item = new MetadataItem();
-      item.modificationTime = results[0].modificationTime;
-      item.size = request.entry.isDirectory ? -1 : results[0].size;
+      item.modificationTime = result.modificationTime;
+      item.size = request.entry.isDirectory ? -1 : result.size;
       item.present = true;
       item.availableOffline = true;
-      if (results[1] !== null)
-        item.contentMimeType = results[1];
       return item;
     }, function() {
       return new MetadataItem();
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.js
index bd90df8..4ed6af4 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.js
@@ -18,27 +18,6 @@
   }
 };
 
-function setUp() {
-  chrome.fileManagerPrivate = {
-    getMimeType: function(url, callback) {
-      chrome.fileManagerPrivate.isGetMimeTypeCalled_ = true;
-
-      switch (url) {
-        case 'filesystem://A':
-          callback('application/A');
-          break;
-        case 'filesystem://B':
-          callback('application/B');
-          break;
-        default:
-          callback('');
-          break;
-      }
-    },
-    isGetMimeTypeCalled_: false
-  };
-}
-
 function testFileSystemMetadataProviderBasic(callback) {
   var provider = new FileSystemMetadataProvider();
   var names = [
@@ -53,14 +32,12 @@
         new Date(2015, 1, 1).toString(),
         results[0].modificationTime.toString());
     assertEquals(1024, results[0].size);
-    assertEquals('application/A', results[0].contentMimeType);
     assertTrue(results[0].present);
     assertTrue(results[0].availableOffline);
     assertEquals(
         new Date(2015, 2, 2).toString(),
         results[1].modificationTime.toString());
     assertEquals(2048, results[1].size);
-    assertEquals('application/B', results[1].contentMimeType);
     assertTrue(results[1].present);
     assertTrue(results[1].availableOffline);
   }), callback);
@@ -76,8 +53,5 @@
             new Date(2015, 1, 1).toString(),
             results[0].modificationTime.toString());
         assertEquals(1024, results[0].size);
-        // When contentMimeType is not requested, this shouldn't try to get
-        // MIME type.
-        assertFalse(chrome.fileManagerPrivate.isGetMimeTypeCalled_);
       }), callback);
 }
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model.js b/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model.js
index bc6a6cc9..f8e0b3a 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model.js
@@ -33,6 +33,7 @@
       [
         'modificationTime',
         'customIconUrl',
+        'contentMimeType',
         'thumbnailUrl',
         'croppedThumbnailUrl',
         'present'
@@ -62,7 +63,8 @@
             media: {}
           };
           var canUseContentThumbnail =
-              metadataList[i].present && FileType.isImage(entries[i]);
+              metadataList[i].present &&
+              FileType.isImage(entries[i], metadataList[i].contentMimeType);
           if (canUseContentThumbnail)
             contentRequestEntries.push(entries[i]);
         }
diff --git a/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js b/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js
index 2c8aa6d..8a0897e8 100644
--- a/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js
+++ b/ui/file_manager/file_manager/foreground/js/thumbnail_loader.js
@@ -48,6 +48,7 @@
   this.thumbnailUrl_ = null;
   if (opt_metadata.external && opt_metadata.external.customIconUrl)
     this.fallbackUrl_ = opt_metadata.external.customIconUrl;
+  var mimeType = opt_metadata && opt_metadata.contentMimeType;
 
   for (var i = 0; i < loadTargets.length; i++) {
     switch (loadTargets[i]) {
@@ -61,14 +62,16 @@
         break;
       case ThumbnailLoader.LoadTarget.EXTERNAL_METADATA:
         if (opt_metadata.external && opt_metadata.external.thumbnailUrl &&
-            (!opt_metadata.external.present || !FileType.isImage(entry))) {
+            (!opt_metadata.external.present ||
+             !FileType.isImage(entry, mimeType))) {
           this.thumbnailUrl_ = opt_metadata.external.thumbnailUrl;
           this.croppedThumbnailUrl_ = opt_metadata.external.croppedThumbnailUrl;
           this.loadTarget_ = ThumbnailLoader.LoadTarget.EXTERNAL_METADATA;
         }
         break;
       case ThumbnailLoader.LoadTarget.FILE_ENTRY:
-        if (FileType.isImage(entry) || FileType.isRaw(entry)) {
+        if (FileType.isImage(entry, mimeType) ||
+            FileType.isRaw(entry, mimeType)) {
           this.thumbnailUrl_ = entry.toURL();
           this.transform_ =
               opt_metadata.media && opt_metadata.media.imageTransform;
diff --git a/ui/file_manager/file_manager/foreground/js/ui/combobutton.js b/ui/file_manager/file_manager/foreground/js/ui/combobutton.js
index c4a211d..192a31b 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/combobutton.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/combobutton.js
@@ -73,7 +73,7 @@
       this.actionNode_.classList.add('action');
       this.appendChild(this.actionNode_);
 
-      var triggerIcon = this.ownerDocument.createElement('core-icon');
+      var triggerIcon = this.ownerDocument.createElement('iron-icon');
       triggerIcon.setAttribute('icon', 'arrow-drop-down');
       this.trigger_ = this.ownerDocument.createElement('div');
       this.trigger_.classList.add('trigger');
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 8de55942..e5e336c 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
@@ -437,7 +437,9 @@
   item.setupIcon_(item.querySelector('.icon'), item.volumeInfo_);
 
   // Attach the "eject" icon if the volume is ejectable.
-  if (modelItem.volumeInfo_.source === VolumeManagerCommon.Source.DEVICE ||
+  if ((modelItem.volumeInfo_.source === VolumeManagerCommon.Source.DEVICE &&
+       modelItem.volumeInfo_.volumeType !==
+           VolumeManagerCommon.VolumeType.MTP) ||
       modelItem.volumeInfo_.source === VolumeManagerCommon.Source.FILE) {
     item.setupEjectButton_(item.rowElement);
   }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
index 6092b98..66d37542 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
@@ -142,13 +142,16 @@
   if (entry) {
     var box = listItem.querySelector('.img-container');
     if (box) {
+      var mimeType = this.metadataModel_.getCache(
+          [entry], ['contentMimeType'])[0].contentMimeType;
       FileGrid.setThumbnailImage_(
           assertInstanceof(box, HTMLDivElement),
           entry,
           event.dataUrl,
           event.width,
           event.height,
-          /* should animate */ true);
+          /* should animate */ true,
+          mimeType);
     }
     listItem.classList.toggle('thumbnail-loaded', true);
   }
@@ -539,7 +542,10 @@
 
   var bottom = li.ownerDocument.createElement('div');
   bottom.className = 'thumbnail-bottom';
-  var detailIcon = filelist.renderFileTypeIcon(li.ownerDocument, entry);
+  var mimeType = this.metadataModel_.getCache(
+      [entry], ['contentMimeType'])[0].contentMimeType;
+  var detailIcon = filelist.renderFileTypeIcon(
+      li.ownerDocument, entry, mimeType);
   if (isDirectory) {
     var checkmark = li.ownerDocument.createElement('div');
     checkmark.className = 'detail-checkmark';
@@ -580,21 +586,27 @@
   if (this.listThumbnailLoader_ &&
       this.listThumbnailLoader_.getThumbnailFromCache(entry)) {
     var thumbnailData = this.listThumbnailLoader_.getThumbnailFromCache(entry);
+    var mimeType = this.metadataModel_.getCache(
+        [entry], ['contentMimeType'])[0].contentMimeType;
     FileGrid.setThumbnailImage_(
         box,
         entry,
         thumbnailData.dataUrl,
         thumbnailData.width,
         thumbnailData.height,
-        /* should not animate */ false);
+        /* should not animate */ false,
+        mimeType);
     li.classList.toggle('thumbnail-loaded', true);
   } else {
     var mediaType = FileType.getMediaType(entry);
     box.setAttribute('generic-thumbnail', mediaType);
     li.classList.toggle('thumbnail-loaded', false);
   }
+  var mimeType = this.metadataModel_.getCache(
+      [entry], ['contentMimeType'])[0].contentMimeType;
   li.classList.toggle('can-hide-filename',
-                      FileType.isImage(entry) || FileType.isRaw(entry));
+                      FileType.isImage(entry, mimeType) ||
+                      FileType.isRaw(entry, mimeType));
 };
 
 /**
@@ -642,10 +654,11 @@
  * @param {number} height Height of thumbnail.
  * @param {boolean} shouldAnimate Whether the thumbanil is shown with animation
  *     or not.
+ * @param {string=} opt_mimeType Optional mime type for the image.
  * @private
  */
 FileGrid.setThumbnailImage_ = function(
-    box, entry, dataUrl, width, height, shouldAnimate) {
+    box, entry, dataUrl, width, height, shouldAnimate, opt_mimeType) {
   var oldThumbnails = box.querySelectorAll('.thumbnail');
 
   var thumbnail = box.ownerDocument.createElement('div');
@@ -653,7 +666,7 @@
 
   // If the image is JPEG or the thumbnail is larger than the grid size, resize
   // it to cover the thumbnail box.
-  var type = FileType.getType(entry);
+  var type = FileType.getType(entry, opt_mimeType);
   if ((type.type === 'image' && type.subtype === 'JPEG') ||
       width > FileGrid.GridSize || height > FileGrid.GridSize)
     thumbnail.style.backgroundSize = 'cover';
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table.js b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
index 4a64aad8..6d14b92ad 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
@@ -685,9 +685,11 @@
   var label = /** @type {!HTMLDivElement} */
       (this.ownerDocument.createElement('div'));
 
-  var icon = filelist.renderFileTypeIcon(this.ownerDocument, entry);
-  if (FileType.isImage(entry) || FileType.isVideo(entry) ||
-      FileType.isRaw(entry)) {
+  var mimeType = this.metadataModel_.getCache([entry],
+      ['contentMimeType'])[0].contentMimeType;
+  var icon = filelist.renderFileTypeIcon(this.ownerDocument, entry, mimeType);
+  if (FileType.isImage(entry, mimeType) || FileType.isVideo(entry, mimeType) ||
+      FileType.isRaw(entry, mimeType)) {
     icon.appendChild(this.renderThumbnail_(entry));
   }
   icon.appendChild(this.renderCheckmark_());
@@ -827,7 +829,11 @@
   var div = /** @type {!HTMLDivElement} */
       (this.ownerDocument.createElement('div'));
   div.className = 'type';
-  div.textContent = FileListModel.getFileTypeString(FileType.getType(entry));
+
+  var mimeType = this.metadataModel_.getCache([entry],
+      ['contentMimeType'])[0].contentMimeType;
+  div.textContent = FileListModel.getFileTypeString(
+      FileType.getType(entry, mimeType));
   return div;
 };
 
@@ -1085,12 +1091,13 @@
  * Render the type column of the detail table.
  * @param {!Document} doc Owner document.
  * @param {!Entry} entry The Entry object to render.
+ * @param {string=} opt_mimeType Optional mime type for the file.
  * @return {!HTMLDivElement} Created element.
  */
-filelist.renderFileTypeIcon = function(doc, entry) {
+filelist.renderFileTypeIcon = function(doc, entry, opt_mimeType) {
   var icon = /** @type {!HTMLDivElement} */ (doc.createElement('div'));
   icon.className = 'detail-icon';
-  icon.setAttribute('file-type-icon', FileType.getIcon(entry));
+  icon.setAttribute('file-type-icon', FileType.getIcon(entry, opt_mimeType));
   return icon;
 };
 
diff --git a/ui/file_manager/file_manager/foreground/js/ui/list_container.js b/ui/file_manager/file_manager/foreground/js/ui/list_container.js
index 72f1460..ff89af7 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/list_container.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/list_container.js
@@ -141,6 +141,7 @@
  */
 ListContainer.METADATA_PREFETCH_PROPERTY_NAMES = [
   'availableOffline',
+  'contentMimeType',
   'customIconUrl',
   'hosted',
   'modificationTime',
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index 96f6f056..8a44dec 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -25,172 +25,18 @@
     <link rel="stylesheet" href="foreground/css/file_status.css">
     <link rel="stylesheet" href="foreground/css/file_types.css">
     <link rel="stylesheet" href="foreground/css/common.css">
-
-    <link rel="import" href="chrome://resources/polymer/core-icon/core-icon.html">
-    <link rel="import" href="chrome://resources/polymer/core-icons/core-icons.html">
-    <link rel="import" href="chrome://resources/polymer/core-icons/image-icons.html">
-    <link rel="import" href="chrome://resources/polymer/core-icons/social-icons.html">
-    <link rel="import" href="chrome://resources/polymer/core-input/core-input.html">
-    <link rel="import" href="chrome://resources/polymer/paper-button/paper-button.html">
-    <link rel="import" href="chrome://resources/polymer/paper-input/paper-input-decorator.html">
-    <link rel="import" href="chrome://resources/polymer/paper-progress/paper-progress.html">
-    <link rel="import" href="chrome://resources/polymer/paper-ripple/paper-ripple.html">
-
     <link rel="stylesheet" href="chrome-extension://fbjakikfhfdajcamjleinfciajelkpek/cws_widget/cws_widget_container.css">
 
-    <!-- Don't load main_scripts.js when flattening is disabled. -->
-    <if expr="False"><!-- </if>
-      <script src="foreground/js/main_scripts.js"></script>
-    <if expr="False"> --></if>
-
-    <if expr="False">
-      <!-- This section is used when the file manager is loaded with
-           'filemgr-ext-path' command-line flag. -->
-      <!-- Keep the list in sync with js/main_scripts.js. -->
-
-      <!-- metrics.js initiates load performance tracking
-           so we want to parse it as early as possible -->
-      <script src="common/js/metrics_base.js"></script>
-      <script src="common/js/metrics_events.js"></script>
-      <script src="common/js/metrics.js"></script>
-      <script src="foreground/js/metrics_start.js"></script>
-
-      <!-- Loads the client of the image loader extension -->
-      <script src="common/js/lru_cache.js"></script>
-      <script src="chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/image_loader_client.js"></script>
-
-      <!-- Scripts for Chrome Webstore widget -->
-      <script src="chrome-extension://fbjakikfhfdajcamjleinfciajelkpek/cws_widget/app_installer.js"></script>
-      <script src="chrome-extension://fbjakikfhfdajcamjleinfciajelkpek/cws_widget/cws_webview_client.js"></script>
-      <script src="chrome-extension://fbjakikfhfdajcamjleinfciajelkpek/cws_widget/cws_widget_container.js"></script>
-      <script src="chrome-extension://fbjakikfhfdajcamjleinfciajelkpek/cws_widget/cws_widget_container_error_dialog.js"></script>
-
-      <script src="chrome://resources/js/load_time_data.js"></script>
-      <script src="chrome://resources/js/cr.js"></script>
-      <script src="chrome://resources/js/util.js"></script>
-      <script src="chrome://resources/js/i18n_template_no_process.js"></script>
-
-      <script src="chrome://resources/js/event_tracker.js"></script>
-      <script src="chrome://resources/js/cr/ui.js"></script>
-      <script src="chrome://resources/js/cr/event_target.js"></script>
-      <script src="chrome://resources/js/cr/ui/touch_handler.js"></script>
-      <script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
-      <script src="chrome://resources/js/cr/ui/dialogs.js"></script>
-      <script src="chrome://resources/js/cr/ui/list_item.js"></script>
-      <script src="chrome://resources/js/cr/ui/list_selection_model.js"></script>
-      <script src="chrome://resources/js/cr/ui/list_single_selection_model.js"></script>
-      <script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script>
-      <script src="chrome://resources/js/cr/ui/list.js"></script>
-      <script src="chrome://resources/js/cr/ui/tree.js"></script>
-      <script src="chrome://resources/js/cr/ui/autocomplete_list.js"></script>
-
-      <script src="chrome://resources/js/cr/ui/splitter.js"></script>
-      <script src="chrome://resources/js/cr/ui/table/table_splitter.js"></script>
-
-      <script src="chrome://resources/js/cr/ui/table/table_column.js"></script>
-      <script src="chrome://resources/js/cr/ui/table/table_column_model.js"></script>
-      <script src="chrome://resources/js/cr/ui/table/table_header.js"></script>
-      <script src="chrome://resources/js/cr/ui/table/table_list.js"></script>
-      <script src="chrome://resources/js/cr/ui/table.js"></script>
-
-      <script src="chrome://resources/js/cr/ui/grid.js"></script>
-
-      <script src="chrome://resources/js/cr/ui/command.js"></script>
-      <script src="chrome://resources/js/cr/ui/position_util.js"></script>
-      <script src="chrome://resources/js/cr/ui/menu_item.js"></script>
-      <script src="chrome://resources/js/cr/ui/menu.js"></script>
-      <script src="chrome://resources/js/cr/ui/menu_button.js"></script>
-      <script src="chrome://resources/js/cr/ui/context_menu_handler.js"></script>
-
-      <script src="chrome://resources/js/analytics.js"></script>
-
-      <!-- This script must be loaded before all other Files.app's scripts. -->
-      <script src="foreground/js/error_counter.js"></script>
-
-      <script src="common/js/async_util.js"></script>
-      <script src="common/js/file_type.js"></script>
-      <script src="common/js/volume_manager_common.js"></script>
-      <script src="common/js/importer_common.js"></script>
-      <script src="common/js/util.js"></script>
-      <script src="common/js/progress_center_common.js"></script>
-
-      <script src="foreground/js/ui/combobutton.js"></script>
-      <script src="foreground/js/ui/commandbutton.js"></script>
-      <script src="foreground/js/ui/file_manager_dialog_base.js"></script>
-      <script src="foreground/js/metadata/metadata_cache_set.js"></script>
-      <script src="foreground/js/metadata/new_metadata_provider.js"></script>
-      <script src="foreground/js/metadata/thumbnail_model.js"></script>
-
-      <script src="foreground/js/app_state_controller.js"></script>
-      <script src="foreground/js/column_visibility_controller.js"></script>
-      <script src="foreground/js/dialog_action_controller.js"></script>
-      <script src="foreground/js/dialog_type.js"></script>
-      <script src="foreground/js/directory_contents.js"></script>
-      <script src="foreground/js/directory_model.js"></script>
-      <script src="foreground/js/empty_folder_controller.js"></script>
-      <script src="foreground/js/file_manager.js"></script>
-      <script src="foreground/js/file_manager_commands.js"></script>
-      <script src="foreground/js/file_selection.js"></script>
-      <script src="foreground/js/file_tasks.js"></script>
-      <script src="foreground/js/file_transfer_controller.js"></script>
-      <script src="foreground/js/file_watcher.js"></script>
-      <script src="foreground/js/folder_shortcuts_data_model.js"></script>
-      <script src="foreground/js/sort_menu_controller.js"></script>
-      <script src="foreground/js/gear_menu_controller.js"></script>
-      <script src="foreground/js/import_controller.js"></script>
-      <script src="foreground/js/launch_param.js"></script>
-      <script src="foreground/js/metadata/content_metadata_provider.js"></script>
-      <script src="foreground/js/metadata/external_metadata_provider.js"></script>
-      <script src="foreground/js/metadata/file_system_metadata_provider.js"></script>
-      <script src="foreground/js/metadata/metadata_cache_item.js"></script>
-      <script src="foreground/js/metadata/metadata_item.js"></script>
-      <script src="foreground/js/metadata/metadata_model.js"></script>
-      <script src="foreground/js/metadata/multi_metadata_provider.js"></script>
-      <script src="foreground/js/metadata_update_controller.js"></script>
-      <script src="foreground/js/naming_controller.js"></script>
-      <script src="foreground/js/navigation_list_model.js"></script>
-      <script src="foreground/js/progress_center_item_group.js"></script>
-      <script src="foreground/js/scan_controller.js"></script>
-      <script src="foreground/js/search_controller.js"></script>
-      <script src="foreground/js/share_client.js"></script>
-      <script src="foreground/js/spinner_controller.js"></script>
-      <script src="foreground/js/task_controller.js"></script>
-      <script src="foreground/js/toolbar_controller.js"></script>
-      <script src="foreground/js/thumbnail_loader.js"></script>
-      <script src="foreground/js/list_thumbnail_loader.js"></script>
-      <script src="foreground/js/providers_model.js"></script>
-      <script src="foreground/js/ui/banners.js"></script>
-      <script src="foreground/js/ui/conflict_dialog.js"></script>
-      <script src="foreground/js/ui/default_action_dialog.js"></script>
-      <script src="foreground/js/ui/dialog_footer.js"></script>
-      <script src="foreground/js/ui/directory_tree.js"></script>
-      <script src="foreground/js/ui/drag_selector.js"></script>
-      <script src="foreground/js/ui/empty_folder.js"></script>
-      <script src="foreground/js/ui/error_dialog.js"></script>
-      <script src="foreground/js/ui/file_grid.js"></script>
-      <script src="foreground/js/ui/file_manager_ui.js"></script>
-      <script src="foreground/js/ui/file_list_selection_model.js"></script>
-      <script src="foreground/js/ui/file_table.js"></script>
-      <script src="foreground/js/ui/file_table_list.js"></script>
-      <script src="foreground/js/ui/gear_menu.js"></script>
-      <script src="foreground/js/ui/list_container.js"></script>
-      <script src="foreground/js/ui/location_line.js"></script>
-      <script src="foreground/js/ui/multi_profile_share_dialog.js"></script>
-      <script src="foreground/js/ui/progress_center_panel.js"></script>
-      <script src="foreground/js/ui/providers_menu.js"></script>
-      <script src="foreground/js/ui/scrollbar.js"></script>
-      <script src="foreground/js/ui/search_box.js"></script>
-      <script src="foreground/js/ui/share_dialog.js"></script>
-      <script src="foreground/js/ui/suggest_apps_dialog.js"></script>
-      <script src="foreground/js/main_window_component.js"></script>
-      <script src="foreground/js/volume_manager_wrapper.js"></script>
-
-      <!-- For accurate load performance tracking main.js should be
-           the last script to include. -->
-      <script src="foreground/js/main.js"></script>
-    </if>
-
+    <script src="common/js/polymer_config.js"></script>
+    <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+    <link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html">
+    <link rel="import" href="chrome://resources/polymer/v1_0/iron-input/iron-input.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-input/paper-input-container.html">
+    <link rel="import" href="chrome://resources/polymer/v1_0/paper-progress/paper-progress.html">
+    <link rel="import" href="chrome://resources/polymer/v1_0/paper-ripple/paper-ripple.html">
   </head>
+
   <body tabindex="-1">
     <commands>
       <!-- We have to use U+XXXX notation here according to event.keyIdentifier
@@ -393,18 +239,18 @@
         <paper-ripple fit class="recenteringTouch"></paper-ripple>
       </button>
       <div id="search-box">
-        <paper-input-decorator i18n-values="label:SEARCH_TEXT_LABEL">
-          <input is="core-input" type="search" tabindex="13"
-                 i18n-values="aria-label:SEARCH_TEXT_LABEL">
+        <paper-input-container no-label-float>
+          <input is="iron-input" type="search" tabindex="13"
+                 i18n-values="aria-label:SEARCH_TEXT_LABEL;placeholder:SEARCH_TEXT_LABEL">
           <span class="clear"></span>
-        </paper-input-decorator>
+        </paper-input-container>
       </div>
       <button id="cloud-import-button"
               class="icon-button manual-display"
               tabindex="14"
               i18n-values="aria-label:CLOUD_IMPORT_COMMAND"
               hidden>
-        <core-icon icon="cloud-queue"></core-icon>
+        <iron-icon icon="cloud-queue"></iron-icon>
         <paper-ripple fit class="recenteringTouch"></paper-ripple>
       </button>
       <button id="cloud-import-details-button"
@@ -412,7 +258,7 @@
               tabindex="-1"
               i18n-values="aria-label:CLOUD_IMPORT_SHOW_DETAILS"
               hidden>
-        <core-icon icon="arrow-drop-down"></core-icon>
+        <iron-icon icon="arrow-drop-down"></iron-icon>
         <paper-ripple fit class="recenteringTouch"></paper-ripple>
       </button>
       <button id="view-button" class="icon-button" tabindex="15"
@@ -441,7 +287,7 @@
         </div>
         <div class="main">
           <div class="status">
-            <core-icon icon="cloud-queue"></core-icon>
+            <iron-icon icon="cloud-queue"></iron-icon>
             <div class="content"></div>
           </div>
           <paper-button class="import" tabindex="-1">
@@ -528,10 +374,11 @@
                 tabindex="3" disabled>
         </button>
         <div id="filename-input-box" visibleif="saveas-file">
-          <paper-input-decorator i18n-values="label:FILENAME_LABEL">
-            <input id="filename-input-textbox" is="core-input" tabindex="4"
-                   class="entry-name" type="text" spellcheck="false">
-          </paper-input-decorator>
+          <paper-input-container no-label-float>
+            <input id="filename-input-textbox" is="iron-input" tabindex="4"
+                   class="entry-name" type="text" spellcheck="false"
+                   i18n-values="placeholder:FILENAME_LABEL">
+          </paper-input-container>
         </div>
         <div class="preparing-label" i18n-content="PREPARING_LABEL"></div>
         <div class="progress-bar"><div class="progress-track"></div></div>
@@ -545,5 +392,157 @@
     </div>
     <div id="drag-container"></div>
     <iframe id="command-dispatcher" hidden aria-hidden="true"></iframe>
+
+    <!-- Don't load main_scripts.js when flattening is disabled. -->
+    <if expr="False"><!-- </if>
+      <script src="foreground/js/main_scripts.js"></script>
+    <if expr="False"> --></if>
+
+    <if expr="False">
+      <!-- This section is used when the file manager is loaded with
+           'filemgr-ext-path' command-line flag. -->
+      <!-- Keep the list in sync with js/main_scripts.js. -->
+
+      <!-- metrics.js initiates load performance tracking
+           so we want to parse it as early as possible -->
+      <script src="common/js/metrics_base.js"></script>
+      <script src="common/js/metrics_events.js"></script>
+      <script src="common/js/metrics.js"></script>
+      <script src="foreground/js/metrics_start.js"></script>
+
+      <!-- Loads the client of the image loader extension -->
+      <script src="common/js/lru_cache.js"></script>
+      <script src="chrome-extension://pmfjbimdmchhbnneeidfognadeopoehp/image_loader_client.js"></script>
+
+      <!-- Scripts for Chrome Webstore widget -->
+      <script src="chrome-extension://fbjakikfhfdajcamjleinfciajelkpek/cws_widget/app_installer.js"></script>
+      <script src="chrome-extension://fbjakikfhfdajcamjleinfciajelkpek/cws_widget/cws_webview_client.js"></script>
+      <script src="chrome-extension://fbjakikfhfdajcamjleinfciajelkpek/cws_widget/cws_widget_container.js"></script>
+      <script src="chrome-extension://fbjakikfhfdajcamjleinfciajelkpek/cws_widget/cws_widget_container_error_dialog.js"></script>
+
+      <script src="chrome://resources/js/load_time_data.js"></script>
+      <script src="chrome://resources/js/cr.js"></script>
+      <script src="chrome://resources/js/util.js"></script>
+      <script src="chrome://resources/js/i18n_template_no_process.js"></script>
+
+      <script src="chrome://resources/js/event_tracker.js"></script>
+      <script src="chrome://resources/js/cr/ui.js"></script>
+      <script src="chrome://resources/js/cr/event_target.js"></script>
+      <script src="chrome://resources/js/cr/ui/touch_handler.js"></script>
+      <script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
+      <script src="chrome://resources/js/cr/ui/dialogs.js"></script>
+      <script src="chrome://resources/js/cr/ui/list_item.js"></script>
+      <script src="chrome://resources/js/cr/ui/list_selection_model.js"></script>
+      <script src="chrome://resources/js/cr/ui/list_single_selection_model.js"></script>
+      <script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script>
+      <script src="chrome://resources/js/cr/ui/list.js"></script>
+      <script src="chrome://resources/js/cr/ui/tree.js"></script>
+      <script src="chrome://resources/js/cr/ui/autocomplete_list.js"></script>
+
+      <script src="chrome://resources/js/cr/ui/splitter.js"></script>
+      <script src="chrome://resources/js/cr/ui/table/table_splitter.js"></script>
+
+      <script src="chrome://resources/js/cr/ui/table/table_column.js"></script>
+      <script src="chrome://resources/js/cr/ui/table/table_column_model.js"></script>
+      <script src="chrome://resources/js/cr/ui/table/table_header.js"></script>
+      <script src="chrome://resources/js/cr/ui/table/table_list.js"></script>
+      <script src="chrome://resources/js/cr/ui/table.js"></script>
+
+      <script src="chrome://resources/js/cr/ui/grid.js"></script>
+
+      <script src="chrome://resources/js/cr/ui/command.js"></script>
+      <script src="chrome://resources/js/cr/ui/position_util.js"></script>
+      <script src="chrome://resources/js/cr/ui/menu_item.js"></script>
+      <script src="chrome://resources/js/cr/ui/menu.js"></script>
+      <script src="chrome://resources/js/cr/ui/menu_button.js"></script>
+      <script src="chrome://resources/js/cr/ui/context_menu_handler.js"></script>
+
+      <script src="chrome://resources/js/analytics.js"></script>
+
+      <!-- This script must be loaded before all other Files.app's scripts. -->
+      <script src="foreground/js/error_counter.js"></script>
+
+      <script src="common/js/async_util.js"></script>
+      <script src="common/js/file_type.js"></script>
+      <script src="common/js/volume_manager_common.js"></script>
+      <script src="common/js/importer_common.js"></script>
+      <script src="common/js/util.js"></script>
+      <script src="common/js/progress_center_common.js"></script>
+
+      <script src="foreground/js/ui/combobutton.js"></script>
+      <script src="foreground/js/ui/commandbutton.js"></script>
+      <script src="foreground/js/ui/file_manager_dialog_base.js"></script>
+      <script src="foreground/js/metadata/metadata_cache_set.js"></script>
+      <script src="foreground/js/metadata/new_metadata_provider.js"></script>
+      <script src="foreground/js/metadata/thumbnail_model.js"></script>
+
+      <script src="foreground/js/app_state_controller.js"></script>
+      <script src="foreground/js/column_visibility_controller.js"></script>
+      <script src="foreground/js/dialog_action_controller.js"></script>
+      <script src="foreground/js/dialog_type.js"></script>
+      <script src="foreground/js/directory_contents.js"></script>
+      <script src="foreground/js/directory_model.js"></script>
+      <script src="foreground/js/empty_folder_controller.js"></script>
+      <script src="foreground/js/file_manager.js"></script>
+      <script src="foreground/js/file_manager_commands.js"></script>
+      <script src="foreground/js/file_selection.js"></script>
+      <script src="foreground/js/file_tasks.js"></script>
+      <script src="foreground/js/file_transfer_controller.js"></script>
+      <script src="foreground/js/file_watcher.js"></script>
+      <script src="foreground/js/folder_shortcuts_data_model.js"></script>
+      <script src="foreground/js/sort_menu_controller.js"></script>
+      <script src="foreground/js/gear_menu_controller.js"></script>
+      <script src="foreground/js/import_controller.js"></script>
+      <script src="foreground/js/launch_param.js"></script>
+      <script src="foreground/js/metadata/content_metadata_provider.js"></script>
+      <script src="foreground/js/metadata/external_metadata_provider.js"></script>
+      <script src="foreground/js/metadata/file_system_metadata_provider.js"></script>
+      <script src="foreground/js/metadata/metadata_cache_item.js"></script>
+      <script src="foreground/js/metadata/metadata_item.js"></script>
+      <script src="foreground/js/metadata/metadata_model.js"></script>
+      <script src="foreground/js/metadata/multi_metadata_provider.js"></script>
+      <script src="foreground/js/metadata_update_controller.js"></script>
+      <script src="foreground/js/naming_controller.js"></script>
+      <script src="foreground/js/navigation_list_model.js"></script>
+      <script src="foreground/js/progress_center_item_group.js"></script>
+      <script src="foreground/js/scan_controller.js"></script>
+      <script src="foreground/js/search_controller.js"></script>
+      <script src="foreground/js/share_client.js"></script>
+      <script src="foreground/js/spinner_controller.js"></script>
+      <script src="foreground/js/task_controller.js"></script>
+      <script src="foreground/js/toolbar_controller.js"></script>
+      <script src="foreground/js/thumbnail_loader.js"></script>
+      <script src="foreground/js/list_thumbnail_loader.js"></script>
+      <script src="foreground/js/providers_model.js"></script>
+      <script src="foreground/js/ui/banners.js"></script>
+      <script src="foreground/js/ui/conflict_dialog.js"></script>
+      <script src="foreground/js/ui/default_action_dialog.js"></script>
+      <script src="foreground/js/ui/dialog_footer.js"></script>
+      <script src="foreground/js/ui/directory_tree.js"></script>
+      <script src="foreground/js/ui/drag_selector.js"></script>
+      <script src="foreground/js/ui/empty_folder.js"></script>
+      <script src="foreground/js/ui/error_dialog.js"></script>
+      <script src="foreground/js/ui/file_grid.js"></script>
+      <script src="foreground/js/ui/file_manager_ui.js"></script>
+      <script src="foreground/js/ui/file_list_selection_model.js"></script>
+      <script src="foreground/js/ui/file_table.js"></script>
+      <script src="foreground/js/ui/file_table_list.js"></script>
+      <script src="foreground/js/ui/gear_menu.js"></script>
+      <script src="foreground/js/ui/list_container.js"></script>
+      <script src="foreground/js/ui/location_line.js"></script>
+      <script src="foreground/js/ui/multi_profile_share_dialog.js"></script>
+      <script src="foreground/js/ui/progress_center_panel.js"></script>
+      <script src="foreground/js/ui/providers_menu.js"></script>
+      <script src="foreground/js/ui/scrollbar.js"></script>
+      <script src="foreground/js/ui/search_box.js"></script>
+      <script src="foreground/js/ui/share_dialog.js"></script>
+      <script src="foreground/js/ui/suggest_apps_dialog.js"></script>
+      <script src="foreground/js/main_window_component.js"></script>
+      <script src="foreground/js/volume_manager_wrapper.js"></script>
+
+      <!-- For accurate load performance tracking main.js should be
+           the last script to include. -->
+      <script src="foreground/js/main.js"></script>
+    </if>
   </body>
 </html>
diff --git a/ui/file_manager/file_manager_resources.grd b/ui/file_manager/file_manager_resources.grd
index 85dc6a5b..63670a2 100644
--- a/ui/file_manager/file_manager_resources.grd
+++ b/ui/file_manager/file_manager_resources.grd
@@ -29,6 +29,7 @@
       <include name="IDR_FILE_MANAGER_METRICS_JS" file="file_manager/common/js/metrics.js" flattenhtml="false" type="BINDATA" />
       <include name="IDR_FILE_MANAGER_METRICS_EVENTS_JS" file="file_manager/common/js/metrics_events.js" flattenhtml="false" type="BINDATA" />
       <include name="IDR_FILE_MANAGER_LRU_CACHE_JS" file="file_manager/common/js/lru_cache.js" flattenhtml="false" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_POLYMER_CONFIG_JS" file="file_manager/common/js/polymer_config.js" flattenhtml="false" type="BINDATA" />
 
       <!-- Scripts working in background page. -->
       <include name="IDR_FILE_MANAGER_DEVICE_APP_WINDOW_WRAPPER_JS" file="file_manager/background/js/app_window_wrapper.js" flattenhtml="false" type="BINDATA" />
@@ -83,26 +84,44 @@
       <include name="IDR_FILE_MANAGER_GALLERY_ICON_256" file="gallery/images/icon256.png" type="BINDATA" />
 
       <!-- Resources used for file type icon in launcher search result. -->
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_ARCHIVE" file="file_manager/foreground/images/filetype/2x/filetype_archive.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_AUDIO" file="file_manager/foreground/images/filetype/2x/filetype_audio.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_CHART" file="file_manager/foreground/images/filetype/2x/filetype_chart.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_EXCEL" file="file_manager/foreground/images/filetype/2x/filetype_excel.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_FOLDER" file="file_manager/foreground/images/filetype/2x/filetype_folder.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_FORM" file="file_manager/foreground/images/filetype/2x/filetype_form.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_GDOC" file="file_manager/foreground/images/filetype/2x/filetype_gdoc.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_GDRAW" file="file_manager/foreground/images/filetype/2x/filetype_gdraw.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_GENERIC" file="file_manager/foreground/images/filetype/2x/filetype_generic.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_GSHEET" file="file_manager/foreground/images/filetype/2x/filetype_gsheet.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_GSLIDES" file="file_manager/foreground/images/filetype/2x/filetype_gslides.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_GTABLE" file="file_manager/foreground/images/filetype/2x/filetype_gtable.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_IMAGE" file="file_manager/foreground/images/filetype/2x/filetype_image.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_MAP" file="file_manager/foreground/images/filetype/2x/filetype_map.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_PDF" file="file_manager/foreground/images/filetype/2x/filetype_pdf.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_PPT" file="file_manager/foreground/images/filetype/2x/filetype_ppt.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_SCRIPT" file="file_manager/foreground/images/filetype/2x/filetype_script.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_SITES" file="file_manager/foreground/images/filetype/2x/filetype_sites.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_VIDEO" file="file_manager/foreground/images/filetype/2x/filetype_video.png" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_IMG_FILETYPE_2X_WORD" file="file_manager/foreground/images/filetype/2x/filetype_word.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_AUDIO" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_audio.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_CHART" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_chart.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_EXCEL" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_excel.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_FOLDER" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_folder.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_FORM" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_form.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_GDOC" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdoc.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_GDRAW" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_gdraw.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_GENERIC" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_generic.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_GSHEET" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_gsheet.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_GSLIDES" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_gslides.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_GTABLE" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_gtable.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_IMAGE" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_image.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_MAP" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_map.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_PDF" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_pdf.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_PPT" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_ppt.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_SCRIPT" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_script.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_SITES" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_sites.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_VIDEO" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_video.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_WORD" file="file_manager/foreground/images/launcher_filetypes/launcher_filetype_word.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_AUDIO" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_audio.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_CHART" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_chart.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_EXCEL" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_excel.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_FOLDER" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_folder.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_FORM" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_form.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GDOC" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdoc.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GDRAW" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gdraw.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GENERIC" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_generic.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GSHEET" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gsheet.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GSLIDES" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gslides.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_GTABLE" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_gtable.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_IMAGE" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_image.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_MAP" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_map.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_PDF" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_pdf.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_PPT" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_ppt.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_SCRIPT" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_script.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_SITES" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_sites.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_VIDEO" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_video.png" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_IMG_LAUNCHER_FILETYPE_2X_WORD" file="file_manager/foreground/images/launcher_filetypes/2x/launcher_filetype_word.png" type="BINDATA" />
 
       <!-- Resources used for non-flattened HTML files. -->
       <include name="IDR_FILE_MANAGER_DRIVE_WELCOME_STYLE" file="file_manager/foreground/css/drive_welcome.css" type="BINDATA" />
@@ -129,6 +148,18 @@
       <!-- AudioPlayer.app pages and scripts. -->
       <include name="IDR_AUDIO_PLAYER_MANIFEST" file="audio_player/manifest.json" type="BINDATA" />
       <include name="IDR_AUDIO_PLAYER_BKGND_JS" file="audio_player/js/background.js" flattenhtml="true" type="BINDATA" />
+      <include name="IDR_AUDIO_PLAYER_ELEMENTS_AUDIO_PLAYER_CSS" file="audio_player/elements/audio_player.css" flattenhtml="true" type="BINDATA" />
+      <include name="IDR_AUDIO_PLAYER_ELEMENTS_AUDIO_PLAYER_HTML" file="audio_player/elements/audio_player.html" type="BINDATA" />
+      <include name="IDR_AUDIO_PLAYER_ELEMENTS_AUDIO_PLAYER_JS" file="audio_player/elements/audio_player.js" type="BINDATA" />
+      <include name="IDR_AUDIO_PLAYER_ELEMENTS_CONTROL_PANEL_CSS" file="audio_player/elements/control_panel.css" flattenhtml="true" type="BINDATA" />
+      <include name="IDR_AUDIO_PLAYER_ELEMENTS_CONTROL_PANEL_HTML" file="audio_player/elements/control_panel.html" type="BINDATA" />
+      <include name="IDR_AUDIO_PLAYER_ELEMENTS_CONTROL_PANEL_JS" file="audio_player/elements/control_panel.js" type="BINDATA" />
+      <include name="IDR_AUDIO_PLAYER_ELEMENTS_TRACK_LIST_CSS" file="audio_player/elements/track_list.css" flattenhtml="true" type="BINDATA" />
+      <include name="IDR_AUDIO_PLAYER_ELEMENTS_TRACK_LIST_HTML" file="audio_player/elements/track_list.html" type="BINDATA" />
+      <include name="IDR_AUDIO_PLAYER_ELEMENTS_TRACK_LIST_JS" file="audio_player/elements/track_list.js" type="BINDATA" />
+      <include name="IDR_AUDIO_PLAYER_ELEMENTS_VOLUME_CONTROLLER_CSS" file="audio_player/elements/volume_controller.css" flattenhtml="true" type="BINDATA" />
+      <include name="IDR_AUDIO_PLAYER_ELEMENTS_VOLUME_CONTROLLER_HTML" file="audio_player/elements/volume_controller.html" type="BINDATA" />
+      <include name="IDR_AUDIO_PLAYER_ELEMENTS_VOLUME_CONTROLLER_JS" file="audio_player/elements/volume_controller.js" type="BINDATA" />
       <include name="IDR_AUDIO_PLAYER_METADATA_WORKER_JS" file="audio_player/js/metadata_worker.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_AUDIO_PLAYER" file="audio_player/audio_player.html" allowexternalscript="true" flattenhtml="true" type="BINDATA" />
       <include name="IDR_AUDIO_PLAYER_JS" file="audio_player/js/audio_player_scripts.js" flattenhtml="true" type="BINDATA" />
diff --git a/ui/file_manager/gallery/css/gallery.css b/ui/file_manager/gallery/css/gallery.css
index 6b0c6f93..a8ef0bf 100644
--- a/ui/file_manager/gallery/css/gallery.css
+++ b/ui/file_manager/gallery/css/gallery.css
@@ -43,7 +43,7 @@
 }
 
 /* Common background for both mosaic and slide mode. */
-.gallery .content {
+.gallery > .content {
   background-color: black;
 }
 
@@ -101,6 +101,7 @@
 }
 
 .gallery .image-container > .image {
+  left: 0;
   pointer-events: none;
   position: absolute;
   /* Duration and timing function are set in Javascript. */
@@ -151,52 +152,30 @@
 
 /* Toolbar */
 
-.gallery > .header,
 .gallery > .toolbar {
   -webkit-box-align: stretch;
   -webkit-box-orient: horizontal;
   -webkit-box-pack: start;
+  background-color: rgba(40, 42, 45, 0.9);
   display: flex;
+  height: 48px;
   left: 0;
   opacity: 0;
-  padding: 0 10px;
+  overflow: hidden;
+  padding: 0;
   pointer-events: none;
   position: absolute;
   right: 0;
   transition: opacity 300ms ease;
 }
 
-.gallery > .header {
-  -webkit-app-region: drag;
-  -webkit-box-align: center;
-  -webkit-box-pack: end;
-  background-color: rgba(30, 30, 30, 0.8);
-  border-bottom: 1px solid rgba(50, 50, 50, 0.8);
-  display: -webkit-box;
-  height: 45px;
-  top: 0;
-}
-
-.gallery > .toolbar {
-  background-color: rgba(40, 42, 45, 0.9);
-}
-
-.gallery .header button {
-  -webkit-app-region: no-drag;
-}
-
-.gallery > .toolbar {
-  border-top: 1px solid rgba(50, 50, 50, 0.8);
-  height: 55px;
-  overflow: hidden;
-}
-
 .gallery > .toolbar.top {
-  top: 45px; /* Header height. */
+  top: 0;
 }
 
 .gallery > .toolbar.bottom {
   bottom: 0;
+  height: 55px;
 }
 
 .gallery > .toolbar.bottom > .slide-mode-toolbar {
@@ -225,7 +204,6 @@
   visibility: visible;
 }
 
-.gallery[tools]:not([slideshow]) > .header,
 .gallery[tools]:not([slideshow]) > .toolbar {
   opacity: 1;
   pointer-events: auto;
@@ -325,6 +303,7 @@
 /* Filename */
 
 .gallery .filename-spacer {
+  -webkit-margin-start: 16px;
   flex: 1 0 auto;
   height: 100%;
   min-width: 140px;
@@ -357,7 +336,7 @@
   padding: 0 3px;
   position: absolute;
   text-overflow: ellipsis;
-  top: 15px;
+  top: 13px;
   white-space: nowrap;
   width: 100%;
 }
@@ -588,9 +567,7 @@
   visibility: visible;
 }
 
-.gallery .header button,
 .gallery .toolbar button,
-.gallery .header button[disabled],
 .gallery .toolbar button[disabled] {
   background-color: rgba(0, 0, 0, 0);
   background-position: center;
@@ -607,17 +584,12 @@
   z-index: 10;
 }
 
-.gallery .header button,
 .gallery .toolbar button {
   height: 40px;
   min-width: 40px;  /* Reset. */
   width: 40px;
 }
 
-.gallery .header button {
-  margin: 6px 0;
-}
-
 .gallery .toolbar button:focus {
   z-index: 11;
 }
@@ -646,17 +618,13 @@
 
 }
 
-.gallery .header button:hover,
 .gallery .toolbar button:hover {
   background-color: rgba(31, 31, 31, 1);
   color: white;
 }
 
-.gallery .header button:active,
 .gallery .toolbar button:active,
-.gallery .header button[pressed],
 .gallery .toolbar button[pressed],
-.gallery .header button[pressed]:hover,
 .gallery .toolbar button[pressed]:hover {
   background-color: rgba(240, 240, 240, 1);
   color: black;
@@ -763,95 +731,72 @@
   display: none;
 }
 
-.gallery[mode='slide'] > .toolbar button.mode {
-  background-image: -webkit-image-set(
-      url(../images/100/icon_mosaic.png) 1x,
-      url(../images/200/icon_mosaic.png) 2x);
+.gallery > .toolbar paper-button {
+  background-position: center;
+  background-repeat: no-repeat;
+  height: 32px;
+  margin: 0 8px;
+  min-width: 32px;
+  width: 32px;
 }
 
-.gallery[mode='slide'] > .toolbar button.mode:active {
-  background-image: -webkit-image-set(
-      url(../images/100/icon_mosaic_selected.png) 1x,
-      url(../images/200/icon_mosaic_selected.png) 2x);
+/* Since currently Gallery does not use shadow dom with Polymer, ::shadow
+ * selector does not work correctly. */
+.gallery > .toolbar paper-button::shadow paper-ripple,
+.gallery > .toolbar paper-button > paper-ripple {
+  color: white;
 }
 
-.gallery[mode='mosaic'] > .toolbar button.mode {
+.gallery > .toolbar paper-button.edit {
   background-image: -webkit-image-set(
-      url(../images/100/icon_1up.png) 1x,
-      url(../images/200/icon_1up.png) 2x);
+      url(../images/100/edit.png) 1x,
+      url(../images/200/edit.png) 2x);
 }
 
-.gallery[mode='mosaic'] > .toolbar button.mode:active {
+.gallery > .toolbar paper-button.print {
   background-image: -webkit-image-set(
-      url(../images/100/icon_1up_selected.png) 1x,
-      url(../images/200/icon_1up_selected.png) 2x);
+      url(../images/100/print.png) 1x,
+      url(../images/200/print.png) 2x);
 }
 
-.gallery > .toolbar button.slideshow {
+.gallery > .toolbar paper-button.delete {
   background-image: -webkit-image-set(
-      url(../images/100/icon_slideshow.png) 1x,
-      url(../images/200/icon_slideshow.png) 2x);
+      url(../images/100/delete.png) 1x,
+      url(../images/200/delete.png) 2x);
 }
 
-.gallery > .toolbar button.slideshow:active,
-.gallery > .toolbar button.slideshow[pressed] {
+.gallery > .toolbar paper-button.slide-mode {
   background-image: -webkit-image-set(
-      url(../images/100/icon_slideshow_selected.png) 1x,
-      url(../images/200/icon_slideshow_selected.png) 2x);
+      url(../images/100/slide_view.png) 1x,
+      url(../images/200/slide_view.png) 2x);
 }
 
-.gallery > .toolbar button.delete {
+.gallery > .toolbar paper-button.mosaic-mode {
   background-image: -webkit-image-set(
-      url(../images/100/icon_delete.png) 1x,
-      url(../images/200/icon_delete.png) 2x);
+      url(../images/100/mosaic_view.png) 1x,
+      url(../images/200/mosaic_view.png) 2x);
 }
 
-.gallery > .toolbar button.delete:active {
+.gallery > .toolbar paper-button.slideshow {
   background-image: -webkit-image-set(
-      url(../images/100/icon_delete_selected.png) 1x,
-      url(../images/200/icon_delete_selected.png) 2x);
+      url(../images/100/slideshow.png) 1x,
+      url(../images/200/slideshow.png) 2x);
 }
 
-.gallery > .toolbar button.edit {
+.gallery > .toolbar paper-button.share {
   background-image: -webkit-image-set(
-      url(../images/100/icon_edit.png) 1x,
-      url(../images/200/icon_edit.png) 2x);
+      url(../images/100/share.png) 1x,
+      url(../images/200/share.png) 2x);
 }
 
-.gallery > .toolbar button.edit:active,
-.gallery > .toolbar button.edit[pressed] {
-  background-image: -webkit-image-set(
-      url(../images/100/icon_edit_selected.png) 1x,
-      url(../images/200/icon_edit_selected.png) 2x);
+.gallery[editing] > .toolbar paper-button.edit {
+  opacity: 0.5;
+  pointer-events: none;
 }
 
-.gallery > .toolbar button.print {
-  background-image: -webkit-image-set(
-      url(../images/100/icon_print.png) 1x,
-      url(../images/200/icon_print.png) 2x);
-}
-
-.gallery > .toolbar button.print:active,
-.gallery > .toolbar button.print[pressed] {
-  background-image: -webkit-image-set(
-      url(../images/100/icon_print_selected.png) 1x,
-      url(../images/200/icon_print_selected.png) 2x);
-}
-
-.gallery > .toolbar button.share {
-  background-image: -webkit-image-set(
-      url(../images/100/icon_share.png) 1x,
-      url(../images/200/icon_share.png) 2x);
-}
-
-.gallery > .toolbar button.share:active,
-.gallery > .toolbar button.share[pressed] {
-  background-image: -webkit-image-set(
-      url(../images/100/icon_share_selected.png) 1x,
-      url(../images/200/icon_share_selected.png) 2x);
-}
-
-.gallery > .toolbar button.share[disabled] {
+.gallery[mode='slide'] > .toolbar paper-button.slide-mode,
+.gallery[mode='mosaic'] > .toolbar paper-button.mosaic-mode,
+.gallery > .toolbar paper-button[disabled] {
   display: none;
 }
 
@@ -1202,7 +1147,7 @@
   overflow-y: hidden;
   position: absolute;
   right: 0;
-  top: 100px; /* Header + Toolbar height. */
+  top: 55px; /* Toolbar height. */
 
   /* transition-duration is set in Javascript. */
   transition-property: transform;
@@ -1362,35 +1307,6 @@
   margin-left: -2px;
 }
 
-.gallery > .header > button {
-  -webkit-margin-start: 10px;
-  cursor: default;
-  height: 32px;
-  min-width: 32px;
-  width: 32px;
-}
-
-.gallery > .header > .minimize-button {
-  background: -webkit-image-set(
-      url(chrome://resources/images/apps/topbar_button_minimize.png) 1x,
-      url(chrome://resources/images/2x/apps/topbar_button_minimize.png) 2x)
-      center;
-}
-
-.gallery > .header > .maximize-button {
-  background: -webkit-image-set(
-      url(chrome://resources/images/apps/topbar_button_maximize.png) 1x,
-      url(chrome://resources/images/2x/apps/topbar_button_maximize.png) 2x)
-      center;
-}
-
-.gallery > .header > .close-button {
-  background: -webkit-image-set(
-      url(chrome://resources/images/apps/topbar_button_close.png) 1x,
-      url(chrome://resources/images/2x/apps/topbar_button_close.png) 2x)
-      center;
-}
-
 .debug-me .load-target-content-metadata::before,
 .debug-me .load-target-external-metadata::before,
 .debug-me .load-target-file-entry::before {
diff --git a/ui/file_manager/gallery/gallery.html b/ui/file_manager/gallery/gallery.html
index dc37823..ba8a663 100644
--- a/ui/file_manager/gallery/gallery.html
+++ b/ui/file_manager/gallery/gallery.html
@@ -12,6 +12,8 @@
   <link rel="stylesheet" href="../file_manager/foreground/css/share_dialog.css">
   <link rel="stylesheet" href="css/gallery.css">
 
+  <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+
   <!-- Don't load gallery_scripts.js when flattening is disabled -->
   <if expr="False"><!-- </if>
     <script src="js/gallery_scripts.js"></script>
@@ -45,7 +47,7 @@
     <script src="chrome://resources/js/cr/ui/list.js"></script>
     <script src="chrome://resources/js/cr/ui/grid.js"></script>
 
-    <!-- Base classes. ->
+    <!-- Base classes. -->
     <script src="../file_manager/foreground/js/metadata/metadata_cache_set.js"></script>
     <script src="../file_manager/foreground/js/metadata/new_metadata_provider.js"></script>
 
@@ -94,16 +96,16 @@
 <body>
   <div class="gallery">
     <div id="content" class="content"></div>
-    <div id="header" class="header tool dimmable"></div>
     <div id="top-toolbar" class="toolbar top tool dimmable">
       <div class="filename-spacer"></div>
       <div class="button-spacer">
-        <button class="button mode"></button>
-        <button class="button slideshow"></button>
-        <button class="button edit"></button>
-        <button class="button print"></button>
-        <button class="delete"></button>
-        <button class="share"></button>
+        <paper-button class="button edit" i18n-values="title:GALLERY_EDIT" disabled></paper-button>
+        <paper-button class="button print" i18n-values="title:GALLERY_PRINT" disabled></paper-button>
+        <paper-button class="button delete" i18n-values="title:GALLERY_DELETE"></paper-button>
+        <paper-button class="button slide-mode" i18n-values="title:GALLERY_SLIDE"></paper-button>
+        <paper-button class="button mosaic-mode" i18n-values="title:GALLERY_MOSAIC"></paper-button>
+        <paper-button class="button slideshow" i18n-values="title:GALLERY_SLIDESHOW"></paper-button>
+        <paper-button class="button share" i18n-values="title:GALLERY_SHARE"></paper-button>
       </div>
     </div>
     <div id="bottom-toolbar" class="toolbar bottom tool dimmable">
diff --git a/ui/file_manager/gallery/images/100/delete.png b/ui/file_manager/gallery/images/100/delete.png
new file mode 100644
index 0000000..0d251bfe
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/delete.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/edit.png b/ui/file_manager/gallery/images/100/edit.png
new file mode 100644
index 0000000..175cde6
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/edit.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_1up.png b/ui/file_manager/gallery/images/100/icon_1up.png
deleted file mode 100644
index 546e87a..0000000
--- a/ui/file_manager/gallery/images/100/icon_1up.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_1up_selected.png b/ui/file_manager/gallery/images/100/icon_1up_selected.png
deleted file mode 100644
index a3043a8..0000000
--- a/ui/file_manager/gallery/images/100/icon_1up_selected.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_delete.png b/ui/file_manager/gallery/images/100/icon_delete.png
deleted file mode 100644
index efb132aa..0000000
--- a/ui/file_manager/gallery/images/100/icon_delete.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_delete_selected.png b/ui/file_manager/gallery/images/100/icon_delete_selected.png
deleted file mode 100644
index f2f88d8..0000000
--- a/ui/file_manager/gallery/images/100/icon_delete_selected.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_edit.png b/ui/file_manager/gallery/images/100/icon_edit.png
deleted file mode 100644
index fc72ecf..0000000
--- a/ui/file_manager/gallery/images/100/icon_edit.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_edit_selected.png b/ui/file_manager/gallery/images/100/icon_edit_selected.png
deleted file mode 100644
index 61540b5..0000000
--- a/ui/file_manager/gallery/images/100/icon_edit_selected.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_mosaic.png b/ui/file_manager/gallery/images/100/icon_mosaic.png
deleted file mode 100644
index 6e49d3c..0000000
--- a/ui/file_manager/gallery/images/100/icon_mosaic.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_mosaic_selected.png b/ui/file_manager/gallery/images/100/icon_mosaic_selected.png
deleted file mode 100644
index 86edb6e1e..0000000
--- a/ui/file_manager/gallery/images/100/icon_mosaic_selected.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_print.png b/ui/file_manager/gallery/images/100/icon_print.png
deleted file mode 100644
index b2355367..0000000
--- a/ui/file_manager/gallery/images/100/icon_print.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_print_selected.png b/ui/file_manager/gallery/images/100/icon_print_selected.png
deleted file mode 100644
index 657b9c8..0000000
--- a/ui/file_manager/gallery/images/100/icon_print_selected.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_share.png b/ui/file_manager/gallery/images/100/icon_share.png
deleted file mode 100644
index 36bb2218..0000000
--- a/ui/file_manager/gallery/images/100/icon_share.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_share_selected.png b/ui/file_manager/gallery/images/100/icon_share_selected.png
deleted file mode 100644
index 438e8a25..0000000
--- a/ui/file_manager/gallery/images/100/icon_share_selected.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_slideshow.png b/ui/file_manager/gallery/images/100/icon_slideshow.png
deleted file mode 100644
index 72763d4..0000000
--- a/ui/file_manager/gallery/images/100/icon_slideshow.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/icon_slideshow_selected.png b/ui/file_manager/gallery/images/100/icon_slideshow_selected.png
deleted file mode 100644
index 4f80a48d..0000000
--- a/ui/file_manager/gallery/images/100/icon_slideshow_selected.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/mosaic_view.png b/ui/file_manager/gallery/images/100/mosaic_view.png
new file mode 100644
index 0000000..115cee02
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/mosaic_view.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/print.png b/ui/file_manager/gallery/images/100/print.png
new file mode 100644
index 0000000..c31be896
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/print.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/share.png b/ui/file_manager/gallery/images/100/share.png
new file mode 100644
index 0000000..73434ac
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/share.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/slide_view.png b/ui/file_manager/gallery/images/100/slide_view.png
new file mode 100644
index 0000000..b033319
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/slide_view.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/100/slideshow.png b/ui/file_manager/gallery/images/100/slideshow.png
new file mode 100644
index 0000000..72434a86
--- /dev/null
+++ b/ui/file_manager/gallery/images/100/slideshow.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/delete.png b/ui/file_manager/gallery/images/200/delete.png
new file mode 100644
index 0000000..b3e9036
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/delete.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/edit.png b/ui/file_manager/gallery/images/200/edit.png
new file mode 100644
index 0000000..7444fc4
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/edit.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_1up.png b/ui/file_manager/gallery/images/200/icon_1up.png
deleted file mode 100644
index 58cbc28..0000000
--- a/ui/file_manager/gallery/images/200/icon_1up.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_1up_selected.png b/ui/file_manager/gallery/images/200/icon_1up_selected.png
deleted file mode 100644
index a0ca726f..0000000
--- a/ui/file_manager/gallery/images/200/icon_1up_selected.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_delete.png b/ui/file_manager/gallery/images/200/icon_delete.png
deleted file mode 100644
index a55ac6c..0000000
--- a/ui/file_manager/gallery/images/200/icon_delete.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_delete_selected.png b/ui/file_manager/gallery/images/200/icon_delete_selected.png
deleted file mode 100644
index af54168a..0000000
--- a/ui/file_manager/gallery/images/200/icon_delete_selected.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_edit.png b/ui/file_manager/gallery/images/200/icon_edit.png
deleted file mode 100644
index 288bc5b..0000000
--- a/ui/file_manager/gallery/images/200/icon_edit.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_edit_selected.png b/ui/file_manager/gallery/images/200/icon_edit_selected.png
deleted file mode 100644
index bcf9933..0000000
--- a/ui/file_manager/gallery/images/200/icon_edit_selected.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_mosaic.png b/ui/file_manager/gallery/images/200/icon_mosaic.png
deleted file mode 100644
index 3e1a621..0000000
--- a/ui/file_manager/gallery/images/200/icon_mosaic.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_mosaic_selected.png b/ui/file_manager/gallery/images/200/icon_mosaic_selected.png
deleted file mode 100644
index d9e329d..0000000
--- a/ui/file_manager/gallery/images/200/icon_mosaic_selected.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_print.png b/ui/file_manager/gallery/images/200/icon_print.png
deleted file mode 100644
index b5a9be0c..0000000
--- a/ui/file_manager/gallery/images/200/icon_print.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_print_selected.png b/ui/file_manager/gallery/images/200/icon_print_selected.png
deleted file mode 100644
index 048a341..0000000
--- a/ui/file_manager/gallery/images/200/icon_print_selected.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_share.png b/ui/file_manager/gallery/images/200/icon_share.png
deleted file mode 100644
index b1da6d9..0000000
--- a/ui/file_manager/gallery/images/200/icon_share.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_share_selected.png b/ui/file_manager/gallery/images/200/icon_share_selected.png
deleted file mode 100644
index b3cd00f..0000000
--- a/ui/file_manager/gallery/images/200/icon_share_selected.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_slideshow.png b/ui/file_manager/gallery/images/200/icon_slideshow.png
deleted file mode 100644
index fec87c0..0000000
--- a/ui/file_manager/gallery/images/200/icon_slideshow.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/icon_slideshow_selected.png b/ui/file_manager/gallery/images/200/icon_slideshow_selected.png
deleted file mode 100644
index 4e1ed5a..0000000
--- a/ui/file_manager/gallery/images/200/icon_slideshow_selected.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/mosaic_view.png b/ui/file_manager/gallery/images/200/mosaic_view.png
new file mode 100644
index 0000000..d5e77783
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/mosaic_view.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/print.png b/ui/file_manager/gallery/images/200/print.png
new file mode 100644
index 0000000..ce9aee8
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/print.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/share.png b/ui/file_manager/gallery/images/200/share.png
new file mode 100644
index 0000000..734f566
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/share.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/slide_view.png b/ui/file_manager/gallery/images/200/slide_view.png
new file mode 100644
index 0000000..acd2f8f2
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/slide_view.png
Binary files differ
diff --git a/ui/file_manager/gallery/images/200/slideshow.png b/ui/file_manager/gallery/images/200/slideshow.png
new file mode 100644
index 0000000..ffa67ad
--- /dev/null
+++ b/ui/file_manager/gallery/images/200/slideshow.png
Binary files differ
diff --git a/ui/file_manager/gallery/js/background.js b/ui/file_manager/gallery/js/background.js
index dbb98be..f3bbed6c 100644
--- a/ui/file_manager/gallery/js/background.js
+++ b/ui/file_manager/gallery/js/background.js
@@ -9,11 +9,13 @@
  */
 var windowCreateOptions = {
   id: 'gallery',
-  innerBounds: {
+  outerBounds: {
     minWidth: 820,
     minHeight: 554
   },
-  frame: 'none'
+  frame: {
+    color: '#1E2023'
+  }
 };
 
 /**
diff --git a/ui/file_manager/gallery/js/gallery.js b/ui/file_manager/gallery/js/gallery.js
index c12c4a7..67a6e68b 100644
--- a/ui/file_manager/gallery/js/gallery.js
+++ b/ui/file_manager/gallery/js/gallery.js
@@ -17,8 +17,7 @@
  */
 function Gallery(volumeManager) {
   /**
-   * @type {{appWindow: chrome.app.window.AppWindow, onClose: function(),
-   *     onMaximize: function(), onMinimize: function(),
+   * @type {{appWindow: chrome.app.window.AppWindow,
    *     onAppRegionChanged: function(), readonlyDirName: string,
    *     displayStringFunction: function(), loadTimeData: Object,
    *     curDirEntry: Entry, searchResults: *}}
@@ -29,15 +28,6 @@
    */
   this.context_ = {
     appWindow: chrome.app.window.current(),
-    onClose: function() { window.close(); },
-    onMaximize: function() {
-      var appWindow = chrome.app.window.current();
-      if (appWindow.isMaximized())
-        appWindow.restore();
-      else
-        appWindow.maximize();
-    },
-    onMinimize: function() { chrome.app.window.current().minimize(); },
     onAppRegionChanged: function() {},
     readonlyDirName: '',
     displayStringFunction: function() { return ''; },
@@ -95,33 +85,9 @@
   var content = queryRequiredElement(document, '#content');
   content.addEventListener('click', this.onContentClick_.bind(this));
 
-  this.header_ = queryRequiredElement(document, '#header');
   this.topToolbar_ = queryRequiredElement(document, '#top-toolbar');
   this.bottomToolbar_ = queryRequiredElement(document, '#bottom-toolbar');
 
-  var preventDefault = function(event) { event.preventDefault(); };
-
-  var minimizeButton = util.createChild(this.header_,
-                                        'minimize-button tool dimmable',
-                                        'button');
-  minimizeButton.tabIndex = -1;
-  minimizeButton.addEventListener('click', this.onMinimize_.bind(this));
-  minimizeButton.addEventListener('mousedown', preventDefault);
-
-  var maximizeButton = util.createChild(this.header_,
-                                        'maximize-button tool dimmable',
-                                        'button');
-  maximizeButton.tabIndex = -1;
-  maximizeButton.addEventListener('click', this.onMaximize_.bind(this));
-  maximizeButton.addEventListener('mousedown', preventDefault);
-
-  var closeButton = util.createChild(this.header_,
-                                     'close-button tool dimmable',
-                                     'button');
-  closeButton.tabIndex = -1;
-  closeButton.addEventListener('click', this.onClose_.bind(this));
-  closeButton.addEventListener('mousedown', preventDefault);
-
   this.filenameSpacer_ = queryRequiredElement(this.topToolbar_,
       '.filename-spacer');
   this.filenameEdit_ = util.createChild(this.filenameSpacer_,
@@ -143,9 +109,15 @@
 
   this.errorBanner_ = new ErrorBanner(this.container_);
 
-  this.modeButton_ = queryRequiredElement(this.topToolbar_, 'button.mode');
-  this.modeButton_.addEventListener('click',
-      this.toggleMode_.bind(this, undefined));
+  var slideModeButton = queryRequiredElement(
+      this.topToolbar_, '.button.slide-mode');
+  slideModeButton.addEventListener(
+      'click', this.onSlideModeButtonClicked_.bind(this));
+
+  var mosaicModeButton = queryRequiredElement(
+      this.topToolbar_, '.button.mosaic-mode');
+  mosaicModeButton.addEventListener(
+      'click', this.onMosaicModeButtonClicked_.bind(this));
 
   this.mosaicMode_ = new MosaicMode(content,
                                     this.errorBanner_,
@@ -173,10 +145,10 @@
     cr.dispatchSimpleEvent(this, 'image-displayed');
   }.bind(this));
 
-  this.deleteButton_ = this.initToolbarButton_('delete', 'GALLERY_DELETE');
+  this.deleteButton_ = queryRequiredElement(this.topToolbar_, '.button.delete');
   this.deleteButton_.addEventListener('click', this.delete_.bind(this));
 
-  this.shareButton_ = this.initToolbarButton_('share', 'GALLERY_SHARE');
+  this.shareButton_ = queryRequiredElement(this.topToolbar_, '.button.share');
   this.shareButton_.addEventListener(
       'click', this.onShareButtonClick_.bind(this));
 
@@ -265,20 +237,6 @@
 };
 
 /**
- * Initializes a toolbar button.
- *
- * @param {string} className Class to add.
- * @param {string} title Button title.
- * @return {!HTMLElement} Newly created button.
- * @private
- */
-Gallery.prototype.initToolbarButton_ = function(className, title) {
-  var button = queryRequiredElement(this.topToolbar_, 'button.' + className);
-  button.title = str(title);
-  return button;
-};
-
-/**
  * Loads the content.
  *
  * @param {!Array<!Entry>} selectedEntries Array of selected entries.
@@ -420,45 +378,6 @@
 };
 
 /**
- * Handles user's 'Close' action.
- * @private
- */
-Gallery.prototype.onClose_ = function() {
-  this.executeWhenReady(this.context_.onClose);
-};
-
-/**
- * Handles user's 'Maximize' action (Escape or a click on the X icon).
- * @private
- */
-Gallery.prototype.onMaximize_ = function() {
-  this.executeWhenReady(this.context_.onMaximize);
-};
-
-/**
- * Handles user's 'Maximize' action (Escape or a click on the X icon).
- * @private
- */
-Gallery.prototype.onMinimize_ = function() {
-  this.executeWhenReady(this.context_.onMinimize);
-};
-
-/**
- * Executes a function when the editor is done with the modifications.
- * @param {function()} callback Function to execute.
- */
-Gallery.prototype.executeWhenReady = function(callback) {
-  this.currentMode_.executeWhenReady(callback);
-};
-
-/**
- * @return {!Object} File manager private API.
- */
-Gallery.getFileManagerPrivate = function() {
-  return chrome.fileManagerPrivate || window.top.chrome.fileManagerPrivate;
-};
-
-/**
  * @return {boolean} True if some tool is currently active.
  */
 Gallery.prototype.hasActiveTool = function() {
@@ -479,6 +398,9 @@
  * Sets the current mode, update the UI.
  * @param {!(SlideMode|MosaicMode)} mode Current mode.
  * @private
+ *
+ * TODO(yawano): Since this method is confusing with changeCurrentMode_. Rename
+ *     or remove this method.
  */
 Gallery.prototype.setCurrentMode_ = function(mode) {
   if (mode !== this.slideMode_ && mode !== this.mosaicMode_)
@@ -487,7 +409,81 @@
   this.currentMode_ = mode;
   this.container_.setAttribute('mode', this.currentMode_.getName());
   this.updateSelectionAndState_();
-  this.updateButtons_();
+};
+
+/**
+ * Handles click event of SlideModeButton.
+ * @param {!Event} event An event.
+ * @private
+ */
+Gallery.prototype.onSlideModeButtonClicked_ = function(event) {
+  this.changeCurrentMode_(this.slideMode_, event);
+};
+
+/**
+ * Handles click event of MosaicModeButton.
+ * @param {!Event} event An event.
+ * @private
+ */
+Gallery.prototype.onMosaicModeButtonClicked_ = function(event) {
+  this.changeCurrentMode_(this.mosaicMode_, event);
+};
+
+/**
+ * Change current mode.
+ * @param {!(SlideMode|MosaicMode)} mode Target mode.
+ * @param {Event=} opt_event Event that caused this call.
+ * @private
+ */
+Gallery.prototype.changeCurrentMode_ = function(mode, opt_event) {
+  return new Promise(function(fulfill, reject) {
+    // Do not re-enter while changing the mode.
+    if (this.currentMode_ === mode || this.changingMode_) {
+      fulfill();
+      return;
+    }
+
+    if (opt_event)
+      this.onUserAction_();
+
+    this.changingMode_ = true;
+
+    var onModeChanged = function() {
+      this.changingMode_ = false;
+      fulfill();
+    }.bind(this);
+
+    var tileIndex = Math.max(0, this.selectionModel_.selectedIndex);
+
+    var mosaic = this.mosaicMode_.getMosaic();
+    var tileRect = mosaic.getTileRect(tileIndex);
+
+    if (mode === this.mosaicMode_) {
+      this.setCurrentMode_(this.mosaicMode_);
+      mosaic.transform(
+          tileRect, this.slideMode_.getSelectedImageRect(), true /* instant */);
+      this.slideMode_.leave(
+          tileRect,
+          function() {
+            // Animate back to normal position.
+            mosaic.transform(null, null);
+            mosaic.show();
+            onModeChanged();
+          }.bind(this));
+      this.bottomToolbar_.hidden = true;
+    } else {
+      this.setCurrentMode_(this.slideMode_);
+      this.slideMode_.enter(
+          tileRect,
+          function() {
+            // Animate to zoomed position.
+            mosaic.transform(tileRect, this.slideMode_.getSelectedImageRect());
+            mosaic.hide();
+          }.bind(this),
+          onModeChanged);
+      this.bottomToolbar_.hidden = false;
+    }
+  }.bind(this));
 };
 
 /**
@@ -497,52 +493,13 @@
  * @private
  */
 Gallery.prototype.toggleMode_ = function(opt_callback, opt_event) {
-  if (!this.modeButton_)
-    return;
+  var targetMode = this.currentMode_ === this.slideMode_ ?
+      this.mosaicMode_ : this.slideMode_;
 
-  if (this.changingMode_) // Do not re-enter while changing the mode.
-    return;
-
-  if (opt_event)
-    this.onUserAction_();
-
-  this.changingMode_ = true;
-
-  var onModeChanged = function() {
-    this.changingMode_ = false;
-    if (opt_callback) opt_callback();
-  }.bind(this);
-
-  var tileIndex = Math.max(0, this.selectionModel_.selectedIndex);
-
-  var mosaic = this.mosaicMode_.getMosaic();
-  var tileRect = mosaic.getTileRect(tileIndex);
-
-  if (this.currentMode_ === this.slideMode_) {
-    this.setCurrentMode_(this.mosaicMode_);
-    mosaic.transform(
-        tileRect, this.slideMode_.getSelectedImageRect(), true /* instant */);
-    this.slideMode_.leave(
-        tileRect,
-        function() {
-          // Animate back to normal position.
-          mosaic.transform(null, null);
-          mosaic.show();
-          onModeChanged();
-        }.bind(this));
-    this.bottomToolbar_.hidden = true;
-  } else {
-    this.setCurrentMode_(this.slideMode_);
-    this.slideMode_.enter(
-        tileRect,
-        function() {
-          // Animate to zoomed position.
-          mosaic.transform(tileRect, this.slideMode_.getSelectedImageRect());
-          mosaic.hide();
-        }.bind(this),
-        onModeChanged);
-    this.bottomToolbar_.hidden = false;
-  }
+  this.changeCurrentMode_(targetMode, opt_event).then(function() {
+    if (opt_callback)
+      opt_callback();
+  });
 };
 
 /**
@@ -891,19 +848,6 @@
 };
 
 /**
- * Updates buttons.
- * @private
- */
-Gallery.prototype.updateButtons_ = function() {
-  if (this.modeButton_) {
-    var oppositeMode =
-        this.currentMode_ === this.slideMode_ ? this.mosaicMode_ :
-                                                this.slideMode_;
-    this.modeButton_.title = str(oppositeMode.getTitle());
-  }
-};
-
-/**
  * Enters the debug mode.
  */
 Gallery.prototype.debugMe = function() {
diff --git a/ui/file_manager/gallery/js/gallery_util.js b/ui/file_manager/gallery/js/gallery_util.js
index c5d3fe0..7b04bfd 100644
--- a/ui/file_manager/gallery/js/gallery_util.js
+++ b/ui/file_manager/gallery/js/gallery_util.js
@@ -45,6 +45,8 @@
 
   return entriesPromise.then(function(entries) {
     return entries.filter(function(entry) {
+      // Currently the gallery doesn't support mime types, so checking by
+      // file extensions is enough.
       return FileType.isImage(entry) || FileType.isRaw(entry);
     }).sort(function(a, b) {
       return a.name.localeCompare(b.name);
diff --git a/ui/file_manager/gallery/js/slide_mode.js b/ui/file_manager/gallery/js/slide_mode.js
index 4443fe8..fd80c428 100644
--- a/ui/file_manager/gallery/js/slide_mode.js
+++ b/ui/file_manager/gallery/js/slide_mode.js
@@ -340,8 +340,7 @@
    * @const
    */
   var slideShowButton = queryRequiredElement(this.topToolbar_,
-      'button.slideshow');
-  slideShowButton.title = this.displayStringFunction_('GALLERY_SLIDESHOW');
+      '.button.slideshow');
   slideShowButton.addEventListener('click',
       this.startSlideshow.bind(this, SlideMode.SLIDESHOW_INTERVAL_FIRST));
 
@@ -362,9 +361,7 @@
    * @private
    * @const
    */
-  this.editButton_ = queryRequiredElement(this.topToolbar_, 'button.edit');
-  this.editButton_.title = this.displayStringFunction_('GALLERY_EDIT');
-  this.editButton_.disabled = true;  // Disabled by default.
+  this.editButton_ = queryRequiredElement(this.topToolbar_, '.button.edit');
   this.editButton_.addEventListener('click', this.toggleEditor.bind(this));
 
   /**
@@ -372,9 +369,7 @@
    * @private
    * @const
    */
-  this.printButton_ = queryRequiredElement(this.topToolbar_, 'button.print');
-  this.printButton_.title = this.displayStringFunction_('GALLERY_PRINT');
-  this.printButton_.disabled = true;  // Disabled by default.
+  this.printButton_ = queryRequiredElement(this.topToolbar_, '.button.print');
   this.printButton_.addEventListener('click', this.print_.bind(this));
 
   /**
@@ -1113,7 +1108,7 @@
 
   if (this.isSlideshowOn_()) {
     switch (keyID) {
-      case 'U+001B':  // Escape exits the slideshow.
+      case 'U+001B':  // Escape
       case 'MediaStop':
         this.stopSlideshow_(event);
         break;
diff --git a/ui/file_manager/gallery/manifest.json b/ui/file_manager/gallery/manifest.json
index 6ac41fe4..fc3f893bc 100644
--- a/ui/file_manager/gallery/manifest.json
+++ b/ui/file_manager/gallery/manifest.json
@@ -17,6 +17,7 @@
     "256": "images/icon256.png"
   },
   "permissions": [
+    "app.window.fullscreen.overrideEsc",
     "chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj",
     "chrome://extension-icon/",
     "chrome://resources/",
diff --git a/ui/file_manager/integration_tests/file_manager/open_image_files.js b/ui/file_manager/integration_tests/file_manager/open_image_files.js
index 5fa208b..f02b3fa 100644
--- a/ui/file_manager/integration_tests/file_manager/open_image_files.js
+++ b/ui/file_manager/integration_tests/file_manager/open_image_files.js
@@ -20,7 +20,7 @@
       TestEntryInfo.getExpectedRows(path == RootPath.DRIVE ?
           BASIC_DRIVE_ENTRY_SET : BASIC_LOCAL_ENTRY_SET).sort();
   var expectedFilesAfter =
-      expectedFilesBefore.concat([ENTRIES.image2.getExpectedRow()]).sort();
+      expectedFilesBefore.concat([ENTRIES.image3.getExpectedRow()]).sort();
 
   StepsRunner.run([
     function() {
@@ -31,7 +31,7 @@
       appId = inAppId;
 
       // Add an additional image file.
-      addEntries(['local', 'drive'], [ENTRIES.image2], this.next);
+      addEntries(['local', 'drive'], [ENTRIES.image3], this.next);
     },
     function(result) {
       chrome.test.assertTrue(result);
@@ -58,13 +58,13 @@
     function() {
       // Open another file in Files.app.
       remoteCall.callRemoteTestUtil(
-          'openFile', appId, ['image2.png'], this.next);
+          'openFile', appId, ['image3.jpg'], this.next);
     },
     function(result) {
       chrome.test.assertTrue(result);
       // Wait for the file opened.
       galleryApp.waitForSlideImage(
-          galleryAppId, 1024, 768, 'image2').then(this.next);
+          galleryAppId, 640, 480, 'image3').then(this.next);
     },
     function() {
       // Close window
diff --git a/ui/file_manager/integration_tests/gallery/open_image_files.js b/ui/file_manager/integration_tests/gallery/open_image_files.js
index 86fe2464..2a26dff 100644
--- a/ui/file_manager/integration_tests/gallery/open_image_files.js
+++ b/ui/file_manager/integration_tests/gallery/open_image_files.js
@@ -16,7 +16,7 @@
   var launchedPromise = launch(testVolumeName, volumeType, [ENTRIES.desktop]);
   return launchedPromise.then(function(args) {
     var WIDTH = 880;
-    var HEIGHT = 570;
+    var HEIGHT = 603; /* Inner height 570px + native header 33px. */
     var appId = args.appId;
     var resizedWindowPromise = gallery.callRemoteTestUtil(
         'resizeWindow', appId, [WIDTH, HEIGHT]
@@ -67,7 +67,7 @@
  * @return {Promise} Promise to be fulfilled with on success.
  */
 function openMultipleImages(testVolumeName, volumeType) {
-  var testEntries = [ENTRIES.desktop, ENTRIES.image2, ENTRIES.image3];
+  var testEntries = [ENTRIES.desktop, ENTRIES.image3];
   var launchedPromise = launch(testVolumeName, volumeType, testEntries);
   return launchedPromise.then(function(args) {
     var appId = args.appId;
@@ -79,8 +79,8 @@
           appId,
           ['.mosaic-tile']
       ).then(function(tiles) {
-        if (tiles.length !== 3)
-          return pending('The number of tiles is expected 3, but is %d',
+        if (tiles.length !== 2)
+          return pending('The number of tiles is expected 2, but is %d',
                          tiles.length);
         return tiles;
       });
diff --git a/ui/file_manager/integration_tests/gallery/photo_editor.js b/ui/file_manager/integration_tests/gallery/photo_editor.js
index 2e3e742..499a44c 100644
--- a/ui/file_manager/integration_tests/gallery/photo_editor.js
+++ b/ui/file_manager/integration_tests/gallery/photo_editor.js
@@ -30,7 +30,7 @@
 
     // Lauch the photo editor.
     var photoEditorPromise = slideImagePromise.then(function() {
-      return gallery.waitAndClickElement(appId, 'button.edit');
+      return gallery.waitAndClickElement(appId, '.button.edit');
     });
 
     return photoEditorPromise.then(function() {
diff --git a/ui/file_manager/integration_tests/gallery/slide_mode.js b/ui/file_manager/integration_tests/gallery/slide_mode.js
index 372b928..d29f88c 100644
--- a/ui/file_manager/integration_tests/gallery/slide_mode.js
+++ b/ui/file_manager/integration_tests/gallery/slide_mode.js
@@ -13,7 +13,7 @@
  * @return {Promise} Promise to be fulfilled with on success.
  */
 function traverseSlideImages(testVolumeName, volumeType) {
-  var testEntries = [ENTRIES.desktop, ENTRIES.image2, ENTRIES.image3];
+  var testEntries = [ENTRIES.desktop, ENTRIES.image3];
   var launchedPromise = launch(
       testVolumeName, volumeType, testEntries, testEntries.slice(0, 1));
   var appId;
@@ -25,10 +25,6 @@
   }).then(function() {
     return gallery.waitAndClickElement(appId, '.arrow.right');
   }).then(function() {
-    return gallery.waitForSlideImage(appId, 1024, 768, 'image2');
-  }).then(function() {
-    return gallery.waitAndClickElement(appId, '.arrow.right');
-  }).then(function() {
     return gallery.waitForSlideImage(appId, 640, 480, 'image3');
   }).then(function() {
     return gallery.waitAndClickElement(appId, '.arrow.right');
@@ -82,7 +78,7 @@
     appId = args.appId;
     return gallery.waitForSlideImage(appId, 800, 600, 'My Desktop Background');
   }).then(function() {
-    return gallery.waitAndClickElement(appId, 'button.delete');
+    return gallery.waitAndClickElement(appId, '.button.delete');
   }).then(function() {
     return gallery.waitAndClickElement(appId, '.cr-dialog-ok');
   }).then(function() {
diff --git a/ui/file_manager/integration_tests/test_util.js b/ui/file_manager/integration_tests/test_util.js
index 025f971..2b586a6 100644
--- a/ui/file_manager/integration_tests/test_util.js
+++ b/ui/file_manager/integration_tests/test_util.js
@@ -205,7 +205,7 @@
 
   world: new TestEntryInfo(
       EntryType.FILE, 'video.ogv', 'world.ogv',
-      'text/plain', SharedOption.NONE, 'Jul 4, 2012, 10:35 AM',
+      'video/ogg', SharedOption.NONE, 'Jul 4, 2012, 10:35 AM',
       'world.ogv', '59 KB', 'OGG video'),
 
   unsupported: new TestEntryInfo(
@@ -218,19 +218,23 @@
       'image/png', SharedOption.NONE, 'Jan 18, 2038, 1:02 AM',
       'My Desktop Background.png', '272 bytes', 'PNG image'),
 
+  // An image file without an extension, to confirm that file type detection
+  // using mime types works fine.
   image2: new TestEntryInfo(
-      EntryType.FILE, 'image2.png', 'image2.png',
+      EntryType.FILE, 'image2.png', 'image2',
       'image/png', SharedOption.NONE, 'Jan 18, 2038, 1:02 AM',
-      'image2.png', '4 KB', 'PNG image'),
+      'image2', '4 KB', 'PNG image'),
 
   image3: new TestEntryInfo(
       EntryType.FILE, 'image3.jpg', 'image3.jpg',
-      'image/jpg', SharedOption.NONE, 'Jan 18, 2038, 1:02 AM',
-      'image3.jpg', '272 bytes', 'JPEG image'),
+      'image/jpeg', SharedOption.NONE, 'Jan 18, 2038, 1:02 AM',
+      'image3.jpg', '3 KB', 'JPEG image'),
 
+  // An ogg file without a mime type, to confirm that file type detection using
+  // file extensions works fine.
   beautiful: new TestEntryInfo(
       EntryType.FILE, 'music.ogg', 'Beautiful Song.ogg',
-      'text/plain', SharedOption.NONE, 'Nov 12, 2086, 12:00 PM',
+      null, SharedOption.NONE, 'Nov 12, 2086, 12:00 PM',
       'Beautiful Song.ogg', '14 KB', 'OGG audio'),
 
   photos: new TestEntryInfo(
diff --git a/ui/file_manager/integration_tests/video_player/background.js b/ui/file_manager/integration_tests/video_player/background.js
index f1e91d2d8..a386dde 100644
--- a/ui/file_manager/integration_tests/video_player/background.js
+++ b/ui/file_manager/integration_tests/video_player/background.js
@@ -62,6 +62,27 @@
 }
 
 /**
+ * Opens video player with a single video.
+ * @param {string} volumeName Test volume name passed to the addEntries
+ *     function. Either 'drive' or 'local'.
+ * @param {VolumeManagerCommon.VolumeType} volumeType Volume type.
+ * @param {TestEntryInfo} entry File to be opened.
+ * @return {Promise} Promise to be fulfilled with the video player element.
+ */
+function openSingleVideo(volumeName, volumeType, entry) {
+  var entries = [entry];
+  return launch(volumeName, volumeType, entries).then(function(args) {
+    var videoPlayer = args[1];
+
+    chrome.test.assertTrue('first-video' in videoPlayer.attributes);
+    chrome.test.assertTrue('last-video' in videoPlayer.attributes);
+    chrome.test.assertFalse('multiple' in videoPlayer.attributes);
+    chrome.test.assertFalse('disabled' in videoPlayer.attributes);
+    return args;
+  });
+};
+
+/**
  * Verifies if there are no Javascript errors in any of the app windows.
  * @param {function()} Completion callback.
  */
diff --git a/ui/file_manager/integration_tests/video_player/open_video_files.js b/ui/file_manager/integration_tests/video_player/open_video_files.js
index 1832875..e0685039 100644
--- a/ui/file_manager/integration_tests/video_player/open_video_files.js
+++ b/ui/file_manager/integration_tests/video_player/open_video_files.js
@@ -5,31 +5,11 @@
 'use strict';
 
 /**
- * Opens video player with a single video.
- * @param {string} volumeName Test volume name passed to the addEntries
- *     function. Either 'drive' or 'local'.
- * @param {VolumeManagerCommon.VolumeType} volumeType Volume type.
- * @return {Promise} Promise to be fulfilled with the video player element.
- */
-function openSingleVideo(volumeName, volumeType) {
-  var entries = [ENTRIES.world];
-  return launch(volumeName, volumeType, entries).then(function(args) {
-    var videoPlayer = args[1];
-
-    chrome.test.assertTrue('first-video' in videoPlayer.attributes);
-    chrome.test.assertTrue('last-video' in videoPlayer.attributes);
-    chrome.test.assertFalse('multiple' in videoPlayer.attributes);
-    chrome.test.assertFalse('disabled' in videoPlayer.attributes);
-    return args;
-  });
-};
-
-/**
  * The openSingleImage test for Downloads.
  * @return {Promise} Promise to be fulfilled with on success.
  */
 testcase.openSingleVideoOnDownloads = function() {
-    var test = openSingleVideo('local', 'downloads');
+    var test = openSingleVideo('local', 'downloads', ENTRIES.world);
     return test.then(function(args) {
       var videoPlayer = args[1];
       chrome.test.assertFalse('cast-available' in videoPlayer.attributes);
@@ -41,7 +21,7 @@
  * @return {Promise} Promise to be fulfilled with on success.
  */
 testcase.openSingleVideoOnDrive = function() {
-    var test = openSingleVideo('drive', 'drive');
+    var test = openSingleVideo('drive', 'drive', ENTRIES.world);
     return test.then(function(args) {
       var appWindow = args[0];
       var videoPlayer = args[1];
diff --git a/ui/gfx/canvas_skia.cc b/ui/gfx/canvas_skia.cc
index 428c32a8..0d1b70d0 100644
--- a/ui/gfx/canvas_skia.cc
+++ b/ui/gfx/canvas_skia.cc
@@ -7,10 +7,10 @@
 #include "base/i18n/rtl.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/numerics/safe_conversions.h"
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/safe_integer_conversions.h"
 #include "ui/gfx/range/range.h"
 #include "ui/gfx/render_text.h"
 #include "ui/gfx/shadow_value.h"
@@ -141,7 +141,7 @@
     std::vector<base::string16> strings;
     ElideRectangleText(text, font_list, *width, INT_MAX, wrap_behavior,
                        &strings);
-    Rect rect(ClampToInt(*width), INT_MAX);
+    Rect rect(base::saturated_cast<int>(*width), INT_MAX);
     scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
     UpdateRenderText(rect, base::string16(), font_list, flags, 0,
                      render_text.get());
@@ -161,7 +161,8 @@
     *height = h;
   } else {
     scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
-    Rect rect(ClampToInt(*width), ClampToInt(*height));
+    Rect rect(base::saturated_cast<int>(*width),
+              base::saturated_cast<int>(*height));
     base::string16 adjusted_text = text;
     StripAcceleratorChars(flags, &adjusted_text);
     UpdateRenderText(rect, adjusted_text, font_list, flags, 0,
diff --git a/ui/gfx/geometry/rect_unittest.cc b/ui/gfx/geometry/rect_unittest.cc
index 8c8370b6c..00a9677 100644
--- a/ui/gfx/geometry/rect_unittest.cc
+++ b/ui/gfx/geometry/rect_unittest.cc
@@ -497,11 +497,6 @@
       std::numeric_limits<int>::max() },
     { 20000.5f, 20000.5f, 0.5f, 0.5f,
       20001, 20001, 0, 0 },
-    { std::numeric_limits<float>::quiet_NaN(),
-      std::numeric_limits<float>::quiet_NaN(),
-      std::numeric_limits<float>::quiet_NaN(),
-      std::numeric_limits<float>::quiet_NaN(),
-      0, 0, 0, 0 }
   };
 
   for (size_t i = 0; i < arraysize(tests); ++i) {
@@ -549,11 +544,6 @@
       std::numeric_limits<int>::max() },
     { 20000.5f, 20000.5f, 0.5f, 0.5f,
       20000, 20000, 1, 1 },
-    { std::numeric_limits<float>::quiet_NaN(),
-      std::numeric_limits<float>::quiet_NaN(),
-      std::numeric_limits<float>::quiet_NaN(),
-      std::numeric_limits<float>::quiet_NaN(),
-      0, 0, 0, 0 }
   };
 
   for (size_t i = 0; i < arraysize(tests); ++i) {
diff --git a/ui/gfx/geometry/safe_integer_conversions.h b/ui/gfx/geometry/safe_integer_conversions.h
index 8733780..5efe134f 100644
--- a/ui/gfx/geometry/safe_integer_conversions.h
+++ b/ui/gfx/geometry/safe_integer_conversions.h
@@ -8,34 +8,25 @@
 #include <cmath>
 #include <limits>
 
+#include "base/numerics/safe_conversions.h"
 #include "ui/gfx/gfx_export.h"
 
 namespace gfx {
 
-inline int ClampToInt(float value) {
-  if (value != value)
-    return 0; // no int NaN.
-  if (value >= std::numeric_limits<int>::max())
-    return std::numeric_limits<int>::max();
-  if (value <= std::numeric_limits<int>::min())
-    return std::numeric_limits<int>::min();
-  return static_cast<int>(value);
-}
-
 inline int ToFlooredInt(float value) {
-  return ClampToInt(std::floor(value));
+  return base::saturated_cast<int>(std::floor(value));
 }
 
 inline int ToCeiledInt(float value) {
-  return ClampToInt(std::ceil(value));
+  return base::saturated_cast<int>(std::ceil(value));
 }
 
 inline int ToFlooredInt(double value) {
-  return ClampToInt(std::floor(value));
+  return base::saturated_cast<int>(std::floor(value));
 }
 
 inline int ToCeiledInt(double value) {
-  return ClampToInt(std::ceil(value));
+  return base::saturated_cast<int>(std::ceil(value));
 }
 
 inline int ToRoundedInt(float value) {
@@ -44,7 +35,7 @@
     rounded = std::floor(value + 0.5f);
   else
     rounded = std::ceil(value - 0.5f);
-  return ClampToInt(rounded);
+  return base::saturated_cast<int>(rounded);
 }
 
 inline int ToRoundedInt(double value) {
@@ -53,7 +44,7 @@
     rounded = std::floor(value + 0.5);
   else
     rounded = std::ceil(value - 0.5);
-  return ClampToInt(rounded);
+  return base::saturated_cast<int>(rounded);
 }
 
 inline bool IsExpressibleAsInt(float value) {
diff --git a/ui/gfx/geometry/safe_integer_conversions_unittest.cc b/ui/gfx/geometry/safe_integer_conversions_unittest.cc
index 099dc4d..91bdbb8 100644
--- a/ui/gfx/geometry/safe_integer_conversions_unittest.cc
+++ b/ui/gfx/geometry/safe_integer_conversions_unittest.cc
@@ -10,32 +10,7 @@
 
 namespace gfx {
 
-TEST(SafeIntegerConversions, ClampToInt) {
-  EXPECT_EQ(0, ClampToInt(std::numeric_limits<float>::quiet_NaN()));
-
-  float max = std::numeric_limits<int>::max();
-  float min = std::numeric_limits<int>::min();
-  float infinity = std::numeric_limits<float>::infinity();
-
-  int int_max = std::numeric_limits<int>::max();
-  int int_min = std::numeric_limits<int>::min();
-
-  EXPECT_EQ(int_max, ClampToInt(infinity));
-  EXPECT_EQ(int_max, ClampToInt(max));
-  EXPECT_EQ(int_max, ClampToInt(max + 100));
-
-  EXPECT_EQ(-100, ClampToInt(-100.5f));
-  EXPECT_EQ(0, ClampToInt(0));
-  EXPECT_EQ(100, ClampToInt(100.5f));
-
-  EXPECT_EQ(int_min, ClampToInt(-infinity));
-  EXPECT_EQ(int_min, ClampToInt(min));
-  EXPECT_EQ(int_min, ClampToInt(min - 100));
-}
-
 TEST(SafeIntegerConversions, ToFlooredInt) {
-  EXPECT_EQ(0, ToFlooredInt(std::numeric_limits<float>::quiet_NaN()));
-
   float max = std::numeric_limits<int>::max();
   float min = std::numeric_limits<int>::min();
   float infinity = std::numeric_limits<float>::infinity();
@@ -57,8 +32,6 @@
 }
 
 TEST(SafeIntegerConversions, ToCeiledInt) {
-  EXPECT_EQ(0, ToCeiledInt(std::numeric_limits<float>::quiet_NaN()));
-
   float max = std::numeric_limits<int>::max();
   float min = std::numeric_limits<int>::min();
   float infinity = std::numeric_limits<float>::infinity();
@@ -80,8 +53,6 @@
 }
 
 TEST(SafeIntegerConversions, ToRoundedInt) {
-  EXPECT_EQ(0, ToRoundedInt(std::numeric_limits<float>::quiet_NaN()));
-
   float max = std::numeric_limits<int>::max();
   float min = std::numeric_limits<int>::min();
   float infinity = std::numeric_limits<float>::infinity();
diff --git a/ui/gfx/overlay_transform.h b/ui/gfx/overlay_transform.h
index 382d5c39..252fc734 100644
--- a/ui/gfx/overlay_transform.h
+++ b/ui/gfx/overlay_transform.h
@@ -17,6 +17,7 @@
   OVERLAY_TRANSFORM_ROTATE_90,
   OVERLAY_TRANSFORM_ROTATE_180,
   OVERLAY_TRANSFORM_ROTATE_270,
+  OVERLAY_TRANSFORM_LAST = OVERLAY_TRANSFORM_ROTATE_270
 };
 
 }  // namespace gfx
diff --git a/ui/gfx/transform_unittest.cc b/ui/gfx/transform_unittest.cc
index 1944142..eb0b2fdcc6 100644
--- a/ui/gfx/transform_unittest.cc
+++ b/ui/gfx/transform_unittest.cc
@@ -448,10 +448,6 @@
     { 0, 0, 10.0f, 20.0f, 10, 20},
     { 0, 0, -10.0f, -20.0f, 0, 0},
     { 0, 0, -10.0f, -20.0f, -10, -20},
-    { 0, 0,
-      std::numeric_limits<float>::quiet_NaN(),
-      std::numeric_limits<float>::quiet_NaN(),
-      10, 20},
   };
 
   Transform xform;
@@ -481,7 +477,6 @@
     { 1, .1f, 1},
     { 1, 100.0f, 100},
     { 1, -1.0f, -100},
-    { 1, std::numeric_limits<float>::quiet_NaN(), 1}
   };
 
   Transform xform;
@@ -513,7 +508,6 @@
     { 1, 0, 90.0f, 0, 1},
     { 1, 0, 360.0f, 0, 1},
     { 1, 0, 0.0f, 0, 1},
-    { 1, 0, std::numeric_limits<float>::quiet_NaN(), 1, 0}
   };
 
   Transform xform;
@@ -541,10 +535,6 @@
     { 0, 0, 10.0f, 20.0f, 10, 20},
     { 10, 20, 10.0f, 20.0f, 20, 40},
     { 10, 20, 0.0f, 0.0f, 10, 20},
-    { 0, 0,
-      std::numeric_limits<float>::quiet_NaN(),
-      std::numeric_limits<float>::quiet_NaN(),
-      0, 0}
   };
 
   for (size_t i = 0; i < arraysize(test_cases); ++i) {
@@ -597,7 +587,6 @@
     { 1, 1.0f, 1},
     { 1, 0.0f, 0},
     { 0, 10.0f, 0},
-    { 1, std::numeric_limits<float>::quiet_NaN(), 0},
   };
 
   for (size_t i = 0; i < arraysize(test_cases); ++i) {
diff --git a/ui/gl/gl_implementation_ozone.cc b/ui/gl/gl_implementation_ozone.cc
index 2a85720..715084f 100644
--- a/ui/gl/gl_implementation_ozone.cc
+++ b/ui/gl/gl_implementation_ozone.cc
@@ -44,9 +44,10 @@
     case kGLImplementationOSMesaGL:
       return InitializeStaticGLBindingsOSMesaGL();
     case kGLImplementationEGLGLES2:
-      if (!ui::SurfaceFactoryOzone::GetInstance()->LoadEGLGLES2Bindings(
-              base::Bind(&AddGLNativeLibrary),
-              base::Bind(&SetGLGetProcAddressProc)))
+      if (!ui::OzonePlatform::GetInstance()
+               ->GetSurfaceFactoryOzone()
+               ->LoadEGLGLES2Bindings(base::Bind(&AddGLNativeLibrary),
+                                      base::Bind(&SetGLGetProcAddressProc)))
         return false;
       SetGLImplementation(kGLImplementationEGLGLES2);
       InitializeStaticGLBindingsGL();
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc
index 4d64da7..2e193a5 100644
--- a/ui/gl/gl_surface_egl.cc
+++ b/ui/gl/gl_surface_egl.cc
@@ -30,6 +30,7 @@
 #endif
 
 #if defined (USE_OZONE)
+#include "ui/ozone/public/ozone_platform.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
 #endif
 
@@ -305,9 +306,9 @@
   };
 
 #if defined(USE_OZONE)
-  const EGLint* config_attribs =
-      ui::SurfaceFactoryOzone::GetInstance()->GetEGLSurfaceProperties(
-          kConfigAttribs);
+  const EGLint* config_attribs = ui::OzonePlatform::GetInstance()
+                                     ->GetSurfaceFactoryOzone()
+                                     ->GetEGLSurfaceProperties(kConfigAttribs);
 #else
   const EGLint* config_attribs = kConfigAttribs;
 #endif
diff --git a/ui/gl/gl_surface_ozone.cc b/ui/gl/gl_surface_ozone.cc
index 3b2e76a0..c7783588 100644
--- a/ui/gl/gl_surface_ozone.cc
+++ b/ui/gl/gl_surface_ozone.cc
@@ -23,6 +23,7 @@
 #include "ui/gl/scoped_binders.h"
 #include "ui/gl/scoped_make_current.h"
 #include "ui/ozone/public/native_pixmap.h"
+#include "ui/ozone/public/ozone_platform.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
 #include "ui/ozone/public/surface_ozone_egl.h"
 
@@ -118,7 +119,8 @@
   }
 
   Destroy();
-  ozone_surface_ = ui::SurfaceFactoryOzone::GetInstance()
+  ozone_surface_ = ui::OzonePlatform::GetInstance()
+                       ->GetSurfaceFactoryOzone()
                        ->CreateEGLSurfaceForWidget(widget_)
                        .Pass();
   if (!ozone_surface_) {
@@ -478,8 +480,10 @@
     gfx::OverlayTransform transform,
     const gfx::Rect& bounds_rect,
     const gfx::RectF& crop_rect) {
-  return ui::SurfaceFactoryOzone::GetInstance()->ScheduleOverlayPlane(
-      widget, z_order, transform, pixmap_, bounds_rect, crop_rect);
+  return ui::OzonePlatform::GetInstance()
+      ->GetSurfaceFactoryOzone()
+      ->ScheduleOverlayPlane(widget, z_order, transform, pixmap_, bounds_rect,
+                             crop_rect);
 }
 
 GLSurfaceOzoneSurfacelessSurfaceImpl::SurfaceImage::~SurfaceImage() {
@@ -584,9 +588,11 @@
     return true;
   for (size_t i = 0; i < arraysize(textures_); i++) {
     scoped_refptr<ui::NativePixmap> pixmap =
-        ui::SurfaceFactoryOzone::GetInstance()->CreateNativePixmap(
-            widget_, GetSize(), ui::SurfaceFactoryOzone::BGRA_8888,
-            ui::SurfaceFactoryOzone::SCANOUT);
+        ui::OzonePlatform::GetInstance()
+            ->GetSurfaceFactoryOzone()
+            ->CreateNativePixmap(widget_, GetSize(),
+                                 ui::SurfaceFactoryOzone::BGRA_8888,
+                                 ui::SurfaceFactoryOzone::SCANOUT);
     if (!pixmap)
       return false;
     scoped_refptr<SurfaceImage> image =
@@ -628,9 +634,12 @@
   if (GetGLImplementation() == kGLImplementationEGLGLES2 &&
       window != kNullAcceleratedWidget &&
       GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
-      ui::SurfaceFactoryOzone::GetInstance()->CanShowPrimaryPlaneAsOverlay()) {
+      ui::OzonePlatform::GetInstance()
+          ->GetSurfaceFactoryOzone()
+          ->CanShowPrimaryPlaneAsOverlay()) {
     scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
-        ui::SurfaceFactoryOzone::GetInstance()
+        ui::OzonePlatform::GetInstance()
+            ->GetSurfaceFactoryOzone()
             ->CreateSurfacelessEGLSurfaceForWidget(window);
     if (!surface_ozone)
       return nullptr;
@@ -656,10 +665,12 @@
   if (window != kNullAcceleratedWidget) {
     scoped_refptr<GLSurface> surface;
     if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
-        ui::SurfaceFactoryOzone::GetInstance()
+        ui::OzonePlatform::GetInstance()
+            ->GetSurfaceFactoryOzone()
             ->CanShowPrimaryPlaneAsOverlay()) {
       scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
-          ui::SurfaceFactoryOzone::GetInstance()
+          ui::OzonePlatform::GetInstance()
+              ->GetSurfaceFactoryOzone()
               ->CreateSurfacelessEGLSurfaceForWidget(window);
       if (!surface_ozone)
         return NULL;
@@ -667,8 +678,9 @@
                                                          window);
     } else {
       scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
-          ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
-              window);
+          ui::OzonePlatform::GetInstance()
+              ->GetSurfaceFactoryOzone()
+              ->CreateEGLSurfaceForWidget(window);
       if (!surface_ozone)
         return NULL;
 
@@ -718,7 +730,9 @@
 }
 
 EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
-  return ui::SurfaceFactoryOzone::GetInstance()->GetNativeDisplay();
+  return ui::OzonePlatform::GetInstance()
+      ->GetSurfaceFactoryOzone()
+      ->GetNativeDisplay();
 }
 
 }  // namespace gfx
diff --git a/ui/keyboard/keyboard_switches.cc b/ui/keyboard/keyboard_switches.cc
index 09d8fbce..55114f3 100644
--- a/ui/keyboard/keyboard_switches.cc
+++ b/ui/keyboard/keyboard_switches.cc
@@ -28,7 +28,10 @@
 const char kFloatingVirtualKeyboard[] = "floating-virtual-keyboard";
 const char kFloatingVirtualKeyboardDisabled[] ="disabled";
 const char kFloatingVirtualKeyboardEnabled[] ="enabled";
-const char kDisableSmartVirtualKeyboard[] = "disable-smart-virtual-keyboard";
+
+const char kSmartVirtualKeyboard[] = "smart-virtual-keyboard";
+const char kSmartVirtualKeyboardDisabled[] = "disabled";
+const char kSmartVirtualKeyboardEnabled[] = "enabled";
 
 const char kDisableVirtualKeyboardOverscroll[] =
     "disable-virtual-keyboard-overscroll";
diff --git a/ui/keyboard/keyboard_switches.h b/ui/keyboard/keyboard_switches.h
index d9296ca..e0fdc77e 100644
--- a/ui/keyboard/keyboard_switches.h
+++ b/ui/keyboard/keyboard_switches.h
@@ -70,9 +70,15 @@
 // to provide access to content that would otherwise be occluded.
 KEYBOARD_EXPORT extern const char kEnableVirtualKeyboardOverscroll[];
 
-// Disable automatic showing/hiding of the keyboard based on the devices plugged
-// in.
-KEYBOARD_EXPORT extern const char kDisableSmartVirtualKeyboard[];
+// Controls automatic showing/hiding of the keyboard based on the devices
+// plugged in.
+KEYBOARD_EXPORT extern const char kSmartVirtualKeyboard[];
+
+// Enables smart deploy for the virtual keyboard.
+KEYBOARD_EXPORT extern const char kSmartVirtualKeyboardEnabled[];
+
+// Disables smart deploy for the virtual keyboard.
+KEYBOARD_EXPORT extern const char kSmartVirtualKeyboardDisabled[];
 
 }  // namespace switches
 }  // namespace keyboard
diff --git a/ui/keyboard/keyboard_util.cc b/ui/keyboard/keyboard_util.cc
index 00b9f9e9..e49e1be 100644
--- a/ui/keyboard/keyboard_util.cc
+++ b/ui/keyboard/keyboard_util.cc
@@ -174,7 +174,14 @@
   std::string keyboard_switch =
       base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
           switches::kGestureEditing);
-  return keyboard_switch == switches::kGestureEditingEnabled;
+  return keyboard_switch != switches::kGestureEditingDisabled;
+}
+
+bool IsSmartDeployEnabled() {
+  std::string keyboard_switch =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kSmartVirtualKeyboard);
+  return keyboard_switch != switches::kSmartVirtualKeyboardDisabled;
 }
 
 bool IsMaterialDesignEnabled() {
diff --git a/ui/keyboard/keyboard_util.h b/ui/keyboard/keyboard_util.h
index 8f72556..d0b7d08 100644
--- a/ui/keyboard/keyboard_util.h
+++ b/ui/keyboard/keyboard_util.h
@@ -76,6 +76,9 @@
 // Returns true if the virtual keyboard is enabled.
 KEYBOARD_EXPORT bool IsKeyboardEnabled();
 
+// Returns true if smart deployment of the virtual keyboard is enabled.
+KEYBOARD_EXPORT bool IsSmartDeployEnabled();
+
 // Returns true if keyboard overscroll mode is enabled.
 KEYBOARD_EXPORT bool IsKeyboardOverscrollEnabled();
 
diff --git a/ui/login/display_manager.js b/ui/login/display_manager.js
index a7cc9ce57..17b63091 100644
--- a/ui/login/display_manager.js
+++ b/ui/login/display_manager.js
@@ -544,7 +544,8 @@
       // Due to other origin iframe and long ChromeVox focusing correspondingly
       // passive aria-label title is not pronounced.
       // Gaia hack can be removed on fixed crbug.com/316726.
-      if (nextStepId == SCREEN_GAIA_SIGNIN) {
+      if (nextStepId == SCREEN_GAIA_SIGNIN ||
+          nextStepId == SCREEN_OOBE_ENROLLMENT) {
         newStep.setAttribute(
             'aria-label',
             loadTimeData.getString('signinScreenTitle'));
diff --git a/ui/ozone/common/gpu/ozone_gpu_message_params.cc b/ui/ozone/common/gpu/ozone_gpu_message_params.cc
index de90c80e..100f208 100644
--- a/ui/ozone/common/gpu/ozone_gpu_message_params.cc
+++ b/ui/ozone/common/gpu/ozone_gpu_message_params.cc
@@ -4,6 +4,9 @@
 
 #include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
 
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/ipc/gfx_param_traits.h"
+
 namespace ui {
 
 DisplayMode_Params::DisplayMode_Params()
@@ -29,4 +32,22 @@
 
 DisplaySnapshot_Params::~DisplaySnapshot_Params() {}
 
+OverlayCheck_Params::OverlayCheck_Params()
+    : transform(gfx::OVERLAY_TRANSFORM_INVALID),
+      format(SurfaceFactoryOzone::UNKNOWN),
+      plane_z_order(0) {
+}
+
+OverlayCheck_Params::OverlayCheck_Params(
+    const OverlayCandidatesOzone::OverlaySurfaceCandidate& candidate)
+    : buffer_size(candidate.buffer_size),
+      transform(candidate.transform),
+      format(candidate.format),
+      display_rect(gfx::ToNearestRect(candidate.display_rect)),
+      plane_z_order(candidate.plane_z_order) {
+}
+
+OverlayCheck_Params::~OverlayCheck_Params() {
+}
+
 }  // namespace ui
diff --git a/ui/ozone/common/gpu/ozone_gpu_message_params.h b/ui/ozone/common/gpu/ozone_gpu_message_params.h
index a2d543a..cc0eb0a 100644
--- a/ui/ozone/common/gpu/ozone_gpu_message_params.h
+++ b/ui/ozone/common/gpu/ozone_gpu_message_params.h
@@ -11,7 +11,10 @@
 #include "ui/display/types/display_constants.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/gfx/overlay_transform.h"
 #include "ui/ozone/ozone_export.h"
+#include "ui/ozone/public/overlay_candidates_ozone.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
 
 namespace ui {
 
@@ -44,6 +47,19 @@
   std::string string_representation;
 };
 
+struct OZONE_EXPORT OverlayCheck_Params {
+  OverlayCheck_Params();
+  OverlayCheck_Params(
+      const OverlayCandidatesOzone::OverlaySurfaceCandidate& candidate);
+  ~OverlayCheck_Params();
+
+  gfx::Size buffer_size;
+  gfx::OverlayTransform transform;
+  SurfaceFactoryOzone::BufferFormat format;
+  gfx::Rect display_rect;
+  int plane_z_order;
+};
+
 }  // namespace ui
 
 #endif  // UI_OZONE_COMMON_GPU_OZONE_GPU_MESSAGE_PARAMS_H_
diff --git a/ui/ozone/common/gpu/ozone_gpu_messages.h b/ui/ozone/common/gpu/ozone_gpu_messages.h
index b58af6a..070c757f 100644
--- a/ui/ozone/common/gpu/ozone_gpu_messages.h
+++ b/ui/ozone/common/gpu/ozone_gpu_messages.h
@@ -29,8 +29,12 @@
 
 IPC_ENUM_TRAITS_MAX_VALUE(ui::HDCPState, ui::HDCP_STATE_LAST)
 
-// clang-format off
+IPC_ENUM_TRAITS_MAX_VALUE(gfx::OverlayTransform, gfx::OVERLAY_TRANSFORM_LAST)
 
+IPC_ENUM_TRAITS_MAX_VALUE(ui::SurfaceFactoryOzone::BufferFormat,
+                          ui::SurfaceFactoryOzone::BUFFER_FORMAT_LAST)
+
+// clang-format off
 IPC_STRUCT_TRAITS_BEGIN(ui::DisplayMode_Params)
   IPC_STRUCT_TRAITS_MEMBER(size)
   IPC_STRUCT_TRAITS_MEMBER(is_interlaced)
@@ -60,6 +64,14 @@
   IPC_STRUCT_TRAITS_MEMBER(b)
 IPC_STRUCT_TRAITS_END()
 
+IPC_STRUCT_TRAITS_BEGIN(ui::OverlayCheck_Params)
+  IPC_STRUCT_TRAITS_MEMBER(buffer_size)
+  IPC_STRUCT_TRAITS_MEMBER(transform)
+  IPC_STRUCT_TRAITS_MEMBER(format)
+  IPC_STRUCT_TRAITS_MEMBER(display_rect)
+  IPC_STRUCT_TRAITS_MEMBER(plane_z_order)
+IPC_STRUCT_TRAITS_END()
+
 // clang-format on
 
 //------------------------------------------------------------------------------
@@ -77,13 +89,13 @@
 IPC_MESSAGE_CONTROL2(OzoneGpuMsg_CursorMove,
                      gfx::AcceleratedWidget, gfx::Point)
 
-// Explicit creation of a WindowDelegate. We explicitly create the window
-// delegate such that any state change in the window is not lost while the
-// surface is created on the GPU side.
-IPC_MESSAGE_CONTROL1(OzoneGpuMsg_CreateWindowDelegate,
+// Explicit creation of a window. We explicitly create the window such
+// that any state change in the window is not lost while the surface is
+// created on the GPU side.
+IPC_MESSAGE_CONTROL1(OzoneGpuMsg_CreateWindow,
                      gfx::AcceleratedWidget /* widget */)
 
-IPC_MESSAGE_CONTROL1(OzoneGpuMsg_DestroyWindowDelegate,
+IPC_MESSAGE_CONTROL1(OzoneGpuMsg_DestroyWindow,
                      gfx::AcceleratedWidget /* widget */)
 
 // Updates the location and size of the widget on the screen.
@@ -128,6 +140,10 @@
                      int64_t,                             // display ID,
                      std::vector<ui::GammaRampRGBEntry>)  // lut
 
+IPC_MESSAGE_CONTROL2(OzoneGpuMsg_CheckOverlayCapabilities,
+                     gfx::AcceleratedWidget /* widget */,
+                     std::vector<ui::OverlayCheck_Params> /* overlays */)
+
 //------------------------------------------------------------------------------
 // Browser Messages
 // These messages are from the GPU to the browser process.
@@ -157,3 +173,8 @@
 // Response to OzoneGpuMsg_RelinquishDisplayControl.
 IPC_MESSAGE_CONTROL1(OzoneHostMsg_DisplayControlRelinquished,
                      bool /* success */)
+
+// Response for OzoneGpuMsg_CheckOverlayCapabilities
+IPC_MESSAGE_CONTROL2(OzoneHostMsg_OverlayCapabilitiesReceived,
+                     gfx::AcceleratedWidget /* widget */,
+                     bool /* result */)
diff --git a/ui/ozone/demo/software_renderer.cc b/ui/ozone/demo/software_renderer.cc
index 45cbd7c..162d5e0e 100644
--- a/ui/ozone/demo/software_renderer.cc
+++ b/ui/ozone/demo/software_renderer.cc
@@ -7,6 +7,7 @@
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkSurface.h"
 #include "ui/gfx/vsync_provider.h"
+#include "ui/ozone/public/ozone_platform.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
 #include "ui/ozone/public/surface_ozone_canvas.h"
 
@@ -28,8 +29,9 @@
 }
 
 bool SoftwareRenderer::Initialize() {
-  software_surface_ =
-      ui::SurfaceFactoryOzone::GetInstance()->CreateCanvasForWidget(widget_);
+  software_surface_ = ui::OzonePlatform::GetInstance()
+                          ->GetSurfaceFactoryOzone()
+                          ->CreateCanvasForWidget(widget_);
   if (!software_surface_) {
     LOG(ERROR) << "Failed to create software surface";
     return false;
diff --git a/ui/ozone/gpu/BUILD.gn b/ui/ozone/gpu/BUILD.gn
index b59bf374..43fd615 100644
--- a/ui/ozone/gpu/BUILD.gn
+++ b/ui/ozone/gpu/BUILD.gn
@@ -17,6 +17,6 @@
     "//ui/gfx",
     "//ui/gfx/geometry",
     "//ui/gl",
-    "//ui/ozone:ozone_base",
+    "//ui/ozone:ozone",
   ]
 }
diff --git a/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc b/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc
index df7fca4..babdc67 100644
--- a/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc
+++ b/ui/ozone/gpu/gpu_memory_buffer_factory_ozone_native_buffer.cc
@@ -8,6 +8,7 @@
 #include "ui/gl/gl_image_egl.h"
 #include "ui/gl/gl_image_linux_dma_buffer.h"
 #include "ui/ozone/public/native_pixmap.h"
+#include "ui/ozone/public/ozone_platform.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
 #include "ui/ozone/public/surface_ozone_egl.h"
 
@@ -35,8 +36,10 @@
                             gfx::OverlayTransform transform,
                             const gfx::Rect& bounds_rect,
                             const gfx::RectF& crop_rect) override {
-    return SurfaceFactoryOzone::GetInstance()->ScheduleOverlayPlane(
-        widget, z_order, transform, pixmap_, bounds_rect, crop_rect);
+    return OzonePlatform::GetInstance()
+        ->GetSurfaceFactoryOzone()
+        ->ScheduleOverlayPlane(widget, z_order, transform, pixmap_, bounds_rect,
+                               crop_rect);
   }
 
  protected:
@@ -72,8 +75,10 @@
                             gfx::OverlayTransform transform,
                             const gfx::Rect& bounds_rect,
                             const gfx::RectF& crop_rect) override {
-    return SurfaceFactoryOzone::GetInstance()->ScheduleOverlayPlane(
-        widget, z_order, transform, pixmap_, bounds_rect, crop_rect);
+    return OzonePlatform::GetInstance()
+        ->GetSurfaceFactoryOzone()
+        ->ScheduleOverlayPlane(widget, z_order, transform, pixmap_, bounds_rect,
+                               crop_rect);
   }
 
  protected:
@@ -144,9 +149,10 @@
     int client_id,
     gfx::PluginWindowHandle surface_handle) {
   scoped_refptr<NativePixmap> pixmap =
-      SurfaceFactoryOzone::GetInstance()->CreateNativePixmap(
-          surface_handle, size, GetOzoneFormatFor(format),
-          GetOzoneUsageFor(usage));
+      OzonePlatform::GetInstance()
+          ->GetSurfaceFactoryOzone()
+          ->CreateNativePixmap(surface_handle, size, GetOzoneFormatFor(format),
+                               GetOzoneUsageFor(usage));
   if (!pixmap.get()) {
     LOG(ERROR) << "Failed to create pixmap " << size.width() << "x"
                << size.height() << " format " << format << ", usage " << usage;
diff --git a/ui/ozone/gpu/ozone_gpu.gyp b/ui/ozone/gpu/ozone_gpu.gyp
index cbc895d..e6e2b656 100644
--- a/ui/ozone/gpu/ozone_gpu.gyp
+++ b/ui/ozone/gpu/ozone_gpu.gyp
@@ -15,7 +15,7 @@
         '../../gfx/gfx.gyp:gfx',
         '../../gfx/gfx.gyp:gfx_geometry',
         '../../gl/gl.gyp:gl',
-        '../ozone.gyp:ozone_base',
+        '../ozone.gyp:ozone',
       ],
       'defines': [
         'OZONE_GPU_IMPLEMENTATION',
diff --git a/ui/ozone/platform/drm/BUILD.gn b/ui/ozone/platform/drm/BUILD.gn
index 6429e6b..9f447a2 100644
--- a/ui/ozone/platform/drm/BUILD.gn
+++ b/ui/ozone/platform/drm/BUILD.gn
@@ -75,6 +75,8 @@
     "host/drm_gpu_platform_support_host.h",
     "host/drm_native_display_delegate.cc",
     "host/drm_native_display_delegate.h",
+    "host/drm_overlay_candidates_host.cc",
+    "host/drm_overlay_candidates_host.h",
     "host/drm_overlay_manager.cc",
     "host/drm_overlay_manager.h",
     "host/drm_window_host.cc",
diff --git a/ui/ozone/platform/drm/drm.gypi b/ui/ozone/platform/drm/drm.gypi
index dc8ef0db..dd427a9 100644
--- a/ui/ozone/platform/drm/drm.gypi
+++ b/ui/ozone/platform/drm/drm.gypi
@@ -96,6 +96,8 @@
         'host/drm_gpu_platform_support_host.h',
         'host/drm_native_display_delegate.cc',
         'host/drm_native_display_delegate.h',
+        'host/drm_overlay_candidates_host.cc',
+        'host/drm_overlay_candidates_host.h',
         'host/drm_overlay_manager.cc',
         'host/drm_overlay_manager.h',
         'host/drm_window_host.cc',
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_platform_support.cc b/ui/ozone/platform/drm/gpu/drm_gpu_platform_support.cc
index 92df3229..0e1f9e2 100644
--- a/ui/ozone/platform/drm/gpu/drm_gpu_platform_support.cc
+++ b/ui/ozone/platform/drm/gpu/drm_gpu_platform_support.cc
@@ -13,6 +13,7 @@
 #include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
 #include "ui/ozone/platform/drm/gpu/drm_gpu_display_manager.h"
 #include "ui/ozone/platform/drm/gpu/drm_window.h"
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
 #include "ui/ozone/platform/drm/gpu/screen_manager.h"
 
 namespace ui {
@@ -121,8 +122,8 @@
 
   bool MessageAffectsCursorState(uint32 message_type) {
     switch (message_type) {
-      case OzoneGpuMsg_CreateWindowDelegate::ID:
-      case OzoneGpuMsg_DestroyWindowDelegate::ID:
+      case OzoneGpuMsg_CreateWindow::ID:
+      case OzoneGpuMsg_DestroyWindow::ID:
       case OzoneGpuMsg_WindowBoundsChanged::ID:
       case OzoneGpuMsg_ConfigureNativeDisplay::ID:
       case OzoneGpuMsg_DisableNativeDisplay::ID:
@@ -167,10 +168,12 @@
 DrmGpuPlatformSupport::DrmGpuPlatformSupport(
     DrmDeviceManager* drm_device_manager,
     ScreenManager* screen_manager,
+    ScanoutBufferGenerator* buffer_generator,
     scoped_ptr<DrmGpuDisplayManager> display_manager)
     : sender_(NULL),
       drm_device_manager_(drm_device_manager),
       screen_manager_(screen_manager),
+      buffer_generator_(buffer_generator),
       display_manager_(display_manager.Pass()) {
   filter_ = new DrmGpuPlatformSupportMessageFilter(
       screen_manager, base::Bind(&DrmGpuPlatformSupport::SetIOTaskRunner,
@@ -196,9 +199,8 @@
   bool handled = true;
 
   IPC_BEGIN_MESSAGE_MAP(DrmGpuPlatformSupport, message)
-  IPC_MESSAGE_HANDLER(OzoneGpuMsg_CreateWindowDelegate, OnCreateWindowDelegate)
-  IPC_MESSAGE_HANDLER(OzoneGpuMsg_DestroyWindowDelegate,
-                      OnDestroyWindowDelegate)
+  IPC_MESSAGE_HANDLER(OzoneGpuMsg_CreateWindow, OnCreateWindow)
+  IPC_MESSAGE_HANDLER(OzoneGpuMsg_DestroyWindow, OnDestroyWindow)
   IPC_MESSAGE_HANDLER(OzoneGpuMsg_WindowBoundsChanged, OnWindowBoundsChanged)
 
   IPC_MESSAGE_HANDLER(OzoneGpuMsg_CursorSet, OnCursorSet)
@@ -217,6 +219,8 @@
   IPC_MESSAGE_HANDLER(OzoneGpuMsg_GetHDCPState, OnGetHDCPState)
   IPC_MESSAGE_HANDLER(OzoneGpuMsg_SetHDCPState, OnSetHDCPState)
   IPC_MESSAGE_HANDLER(OzoneGpuMsg_SetGammaRamp, OnSetGammaRamp);
+  IPC_MESSAGE_HANDLER(OzoneGpuMsg_CheckOverlayCapabilities,
+                      OnCheckOverlayCapabilities)
   IPC_MESSAGE_UNHANDLED(handled = false);
   IPC_END_MESSAGE_MAP()
 
@@ -228,16 +232,14 @@
   return false;
 }
 
-void DrmGpuPlatformSupport::OnCreateWindowDelegate(
-    gfx::AcceleratedWidget widget) {
+void DrmGpuPlatformSupport::OnCreateWindow(gfx::AcceleratedWidget widget) {
   scoped_ptr<DrmWindow> delegate(
       new DrmWindow(widget, drm_device_manager_, screen_manager_));
   delegate->Initialize();
   screen_manager_->AddWindow(widget, delegate.Pass());
 }
 
-void DrmGpuPlatformSupport::OnDestroyWindowDelegate(
-    gfx::AcceleratedWidget widget) {
+void DrmGpuPlatformSupport::OnDestroyWindow(gfx::AcceleratedWidget widget) {
   scoped_ptr<DrmWindow> delegate = screen_manager_->RemoveWindow(widget);
   delegate->Shutdown();
 }
@@ -260,6 +262,14 @@
   screen_manager_->GetWindow(widget)->MoveCursor(location);
 }
 
+void DrmGpuPlatformSupport::OnCheckOverlayCapabilities(
+    gfx::AcceleratedWidget widget,
+    const std::vector<OverlayCheck_Params>& overlays) {
+  sender_->Send(new OzoneHostMsg_OverlayCapabilitiesReceived(
+      widget, screen_manager_->GetWindow(widget)
+                  ->TestPageFlip(overlays, buffer_generator_)));
+}
+
 void DrmGpuPlatformSupport::OnRefreshNativeDisplays() {
   sender_->Send(
       new OzoneHostMsg_UpdateNativeDisplays(display_manager_->GetDisplays()));
diff --git a/ui/ozone/platform/drm/gpu/drm_gpu_platform_support.h b/ui/ozone/platform/drm/gpu/drm_gpu_platform_support.h
index 27e84e1..e6aa6b7e 100644
--- a/ui/ozone/platform/drm/gpu/drm_gpu_platform_support.h
+++ b/ui/ozone/platform/drm/gpu/drm_gpu_platform_support.h
@@ -33,15 +33,18 @@
 class DrmSurfaceFactory;
 class DrmWindow;
 class ScreenManager;
+class ScanoutBufferGenerator;
 
 struct DisplayMode_Params;
 struct DisplaySnapshot_Params;
+struct OverlayCheck_Params;
 struct GammaRampRGBEntry;
 
 class DrmGpuPlatformSupport : public GpuPlatformSupport {
  public:
   DrmGpuPlatformSupport(DrmDeviceManager* drm_device_manager,
                         ScreenManager* screen_manager,
+                        ScanoutBufferGenerator* buffer_generator,
                         scoped_ptr<DrmGpuDisplayManager> display_manager);
   ~DrmGpuPlatformSupport() override;
 
@@ -56,8 +59,8 @@
   bool OnMessageReceived(const IPC::Message& message) override;
 
  private:
-  void OnCreateWindowDelegate(gfx::AcceleratedWidget widget);
-  void OnDestroyWindowDelegate(gfx::AcceleratedWidget widget);
+  void OnCreateWindow(gfx::AcceleratedWidget widget);
+  void OnDestroyWindow(gfx::AcceleratedWidget widget);
   void OnWindowBoundsChanged(gfx::AcceleratedWidget widget,
                              const gfx::Rect& bounds);
   void OnCursorSet(gfx::AcceleratedWidget widget,
@@ -65,6 +68,9 @@
                    const gfx::Point& location,
                    int frame_delay_ms);
   void OnCursorMove(gfx::AcceleratedWidget widget, const gfx::Point& location);
+  void OnCheckOverlayCapabilities(
+      gfx::AcceleratedWidget widget,
+      const std::vector<OverlayCheck_Params>& overlays);
 
   // Display related IPC handlers.
   void OnRefreshNativeDisplays();
@@ -87,6 +93,7 @@
   IPC::Sender* sender_;                   // Not owned.
   DrmDeviceManager* drm_device_manager_;  // Not owned.
   ScreenManager* screen_manager_;         // Not owned.
+  ScanoutBufferGenerator* buffer_generator_;  // Not owned.
 
   scoped_ptr<DrmGpuDisplayManager> display_manager_;
   ScopedVector<GpuPlatformSupport> handlers_;
diff --git a/ui/ozone/platform/drm/gpu/drm_window.cc b/ui/ozone/platform/drm/gpu/drm_window.cc
index b2f7a460..81756f79 100644
--- a/ui/ozone/platform/drm/gpu/drm_window.cc
+++ b/ui/ozone/platform/drm/gpu/drm_window.cc
@@ -8,9 +8,11 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkDevice.h"
 #include "third_party/skia/include/core/SkSurface.h"
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
 #include "ui/ozone/platform/drm/gpu/drm_buffer.h"
 #include "ui/ozone/platform/drm/gpu/drm_device.h"
 #include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
 #include "ui/ozone/platform/drm/gpu/screen_manager.h"
 
 namespace ui {
@@ -25,6 +27,9 @@
 #define DRM_CAP_CURSOR_HEIGHT 0x9
 #endif
 
+void EmptyFlipCallback(gfx::SwapResult) {
+}
+
 void UpdateCursorImage(DrmBuffer* cursor, const SkBitmap& image) {
   SkRect damage;
   image.getBounds(&damage);
@@ -139,6 +144,36 @@
   return true;
 }
 
+bool DrmWindow::TestPageFlip(const std::vector<OverlayCheck_Params>& overlays,
+                             ScanoutBufferGenerator* buffer_generator) {
+  if (!controller_)
+    return true;
+  for (const auto& overlay : overlays) {
+    // It is possible that the cc rect we get actually falls off the edge of
+    // the screen. Usually this is prevented via things like status bars
+    // blocking overlaying or cc clipping it, but in case it wasn't properly
+    // clipped (since GL will render this situation fine) just ignore it here.
+    // This should be an extremely rare occurrance.
+    if (overlay.plane_z_order != 0 && !bounds().Contains(overlay.display_rect))
+      return false;
+  }
+
+  scoped_refptr<DrmDevice> drm = controller_->GetAllocationDrmDevice();
+  OverlayPlaneList planes;
+  for (const auto& overlay : overlays) {
+    gfx::Size size =
+        (overlay.plane_z_order == 0) ? bounds().size() : overlay.buffer_size;
+    scoped_refptr<ScanoutBuffer> buffer = buffer_generator->Create(drm, size);
+    if (!buffer)
+      return false;
+    planes.push_back(OverlayPlane(buffer, overlay.plane_z_order,
+                                  overlay.transform, overlay.display_rect,
+                                  gfx::RectF(gfx::Size(1, 1))));
+  }
+  return controller_->SchedulePageFlip(planes, true, true,
+                                       base::Bind(&EmptyFlipCallback));
+}
+
 const OverlayPlane* DrmWindow::GetLastModesetBuffer() {
   return OverlayPlane::GetPrimaryPlane(last_submitted_planes_);
 }
diff --git a/ui/ozone/platform/drm/gpu/drm_window.h b/ui/ozone/platform/drm/gpu/drm_window.h
index 1164f17..36d3b5b 100644
--- a/ui/ozone/platform/drm/gpu/drm_window.h
+++ b/ui/ozone/platform/drm/gpu/drm_window.h
@@ -29,6 +29,8 @@
 class DrmBuffer;
 class DrmDeviceManager;
 class HardwareDisplayController;
+struct OverlayCheck_Params;
+class ScanoutBufferGenerator;
 class ScreenManager;
 
 // A delegate of the platform window (DrmWindow) on the GPU process. This is
@@ -84,6 +86,8 @@
   void QueueOverlayPlane(const OverlayPlane& plane);
 
   bool SchedulePageFlip(bool is_sync, const SwapCompletionCallback& callback);
+  bool TestPageFlip(const std::vector<OverlayCheck_Params>& planes,
+                    ScanoutBufferGenerator* buffer_generator);
 
   // Returns the last buffer associated with this window.
   const OverlayPlane* GetLastModesetBuffer();
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.cc b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
index 41a2c03..448da1d 100644
--- a/ui/ozone/platform/drm/host/drm_display_host_manager.cc
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.cc
@@ -5,11 +5,10 @@
 #include "ui/ozone/platform/drm/host/drm_display_host_manager.h"
 
 #include <fcntl.h>
-#include <stdio.h>
 #include <xf86drm.h>
 
-#include "base/logging.h"
-#include "base/strings/stringprintf.h"
+#include "base/files/file_enumerator.h"
+#include "base/posix/eintr_wrapper.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/worker_pool.h"
@@ -32,6 +31,8 @@
     OnOpenDeviceReplyCallback;
 
 const char kDefaultGraphicsCardPattern[] = "/dev/dri/card%d";
+const char kVgemDevDriCardPath[] = "/dev/dri/";
+const char kVgemSysCardPath[] = "/sys/bus/platform/devices/vgem/drm/";
 
 const char* kDisplayActionString[] = {
     "ADD",
@@ -76,6 +77,22 @@
   return base::FilePath();
 }
 
+base::FilePath GetVgemCardPath() {
+  base::FileEnumerator file_iter(base::FilePath(kVgemSysCardPath), false,
+                                 base::FileEnumerator::DIRECTORIES,
+                                 FILE_PATH_LITERAL("card*"));
+
+  while (!file_iter.Next().empty()) {
+    // Inspect the card%d directories in the directory and extract the filename.
+    std::string vgem_card_path =
+        kVgemDevDriCardPath + file_iter.GetInfo().GetName().BaseName().value();
+    DVLOG(1) << "VGEM card path is " << vgem_card_path;
+    return base::FilePath(vgem_card_path);
+  }
+  DVLOG(1) << "Don't support VGEM";
+  return base::FilePath();
+}
+
 class FindDrmDisplayHostById {
  public:
   explicit FindDrmDisplayHostById(int64_t display_id)
@@ -111,6 +128,16 @@
       return;
     }
     drm_devices_.insert(primary_graphics_card_path_);
+
+    vgem_card_path_ = GetVgemCardPath();
+    if (!vgem_card_path_.empty()) {
+      int fd = HANDLE_EINTR(
+          open(vgem_card_path_.value().c_str(), O_RDWR | O_CLOEXEC));
+      if (fd < 0) {
+        PLOG(ERROR) << "Failed to open vgem: " << vgem_card_path_.value();
+      }
+      vgem_card_device_file_.reset(fd);
+    }
   }
 
   device_manager_->AddObserver(this);
@@ -191,6 +218,8 @@
             << " for " << event.path.value();
     switch (event.action_type) {
       case DeviceEvent::ADD:
+        if (event.path == vgem_card_path_)
+          continue;
         if (drm_devices_.find(event.path) == drm_devices_.end()) {
           task_pending_ = base::WorkerPool::PostTask(
               FROM_HERE,
@@ -210,6 +239,7 @@
       case DeviceEvent::REMOVE:
         DCHECK(event.path != primary_graphics_card_path_)
             << "Removing primary graphics card";
+        DCHECK(event.path != vgem_card_path_) << "Removing VGEM device";
         auto it = drm_devices_.find(event.path);
         if (it != drm_devices_.end()) {
           task_pending_ = base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/ui/ozone/platform/drm/host/drm_display_host_manager.h b/ui/ozone/platform/drm/host/drm_display_host_manager.h
index c0da4dd6..b986f610 100644
--- a/ui/ozone/platform/drm/host/drm_display_host_manager.h
+++ b/ui/ozone/platform/drm/host/drm_display_host_manager.h
@@ -8,7 +8,7 @@
 #include <queue>
 #include <set>
 
-#include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "ui/display/types/native_display_delegate.h"
@@ -98,6 +98,9 @@
   // with the GPU process trying to open it and aquire DRM master.
   base::FilePath primary_graphics_card_path_;
 
+  // File path for virtual gem (VGEM) device.
+  base::FilePath vgem_card_path_;
+
   // Keeps track if there is a dummy display. This happens on initialization
   // when there is no connection to the GPU to update the displays.
   bool has_dummy_display_;
@@ -126,6 +129,9 @@
   // established.
   scoped_ptr<DrmDeviceHandle> primary_drm_device_handle_;
 
+  // Manages the VGEM device by itself and doesn't send it to GPU process.
+  base::ScopedFD vgem_card_device_file_;
+
   base::WeakPtrFactory<DrmDisplayHostManager> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(DrmDisplayHostManager);
diff --git a/ui/ozone/platform/drm/host/drm_overlay_candidates_host.cc b/ui/ozone/platform/drm/host/drm_overlay_candidates_host.cc
new file mode 100644
index 0000000..52e31b1
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_overlay_candidates_host.cc
@@ -0,0 +1,141 @@
+// 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 "ui/ozone/platform/drm/host/drm_overlay_candidates_host.h"
+
+#include <algorithm>
+
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/ozone/common/gpu/ozone_gpu_messages.h"
+#include "ui/ozone/platform/drm/host/drm_gpu_platform_support_host.h"
+
+namespace ui {
+
+namespace {
+const size_t kMaxCacheSize = 100;
+}  // namespace
+
+bool DrmOverlayCandidatesHost::OverlayCompare::operator()(
+    const OverlayCheck_Params& l,
+    const OverlayCheck_Params& r) {
+  if (l.plane_z_order < r.plane_z_order)
+    return true;
+  if (l.plane_z_order > r.plane_z_order)
+    return false;
+  if (l.display_rect < r.display_rect)
+    return true;
+  if (l.display_rect != r.display_rect)
+    return false;
+  if (l.format < r.format)
+    return true;
+  if (l.format > r.format)
+    return false;
+  if (l.transform < r.transform)
+    return true;
+  if (l.transform > r.transform)
+    return false;
+  if (l.buffer_size.width() < r.buffer_size.width())
+    return true;
+  if (l.buffer_size.width() > r.buffer_size.width())
+    return false;
+  return l.buffer_size.height() < r.buffer_size.height();
+}
+
+DrmOverlayCandidatesHost::DrmOverlayCandidatesHost(
+    gfx::AcceleratedWidget widget,
+    DrmGpuPlatformSupportHost* platform_support)
+    : widget_(widget),
+      platform_support_(platform_support),
+      cache_(kMaxCacheSize) {
+  platform_support_->RegisterHandler(this);
+}
+
+DrmOverlayCandidatesHost::~DrmOverlayCandidatesHost() {
+  platform_support_->UnregisterHandler(this);
+}
+
+void DrmOverlayCandidatesHost::CheckOverlaySupport(
+    OverlaySurfaceCandidateList* candidates) {
+  if (candidates->size() == 2)
+    CheckSingleOverlay(candidates);
+}
+
+void DrmOverlayCandidatesHost::CheckSingleOverlay(
+    OverlaySurfaceCandidateList* candidates) {
+  OverlayCandidatesOzone::OverlaySurfaceCandidate* first = &(*candidates)[0];
+  OverlayCandidatesOzone::OverlaySurfaceCandidate* second = &(*candidates)[1];
+  OverlayCandidatesOzone::OverlaySurfaceCandidate* overlay;
+  if (first->plane_z_order == 0) {
+    overlay = second;
+  } else if (second->plane_z_order == 0) {
+    overlay = first;
+  } else {
+    return;
+  }
+  // 0.01 constant chosen to match DCHECKs in gfx::ToNearestRect and avoid
+  // that code asserting on quads that we accept.
+  if (!gfx::IsNearestRectWithinDistance(overlay->display_rect, 0.01f))
+    return;
+  if (overlay->transform == gfx::OVERLAY_TRANSFORM_INVALID)
+    return;
+
+  OverlayCheck_Params lookup(*overlay);
+  auto iter = cache_.Get(lookup);
+  if (iter == cache_.end()) {
+    cache_.Put(lookup, false);
+    SendRequest(*candidates, lookup);
+  } else {
+    overlay->overlay_handled = iter->second;
+  }
+}
+
+void DrmOverlayCandidatesHost::OnChannelEstablished(
+    int host_id,
+    scoped_refptr<base::SingleThreadTaskRunner> send_runner,
+    const base::Callback<void(IPC::Message*)>& sender) {
+}
+
+void DrmOverlayCandidatesHost::OnChannelDestroyed(int host_id) {
+}
+
+bool DrmOverlayCandidatesHost::OnMessageReceived(const IPC::Message& message) {
+  bool handled = false;
+  IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(DrmOverlayCandidatesHost, message, &handled)
+  IPC_MESSAGE_FORWARD(OzoneHostMsg_OverlayCapabilitiesReceived, this,
+                      DrmOverlayCandidatesHost::OnOverlayResult)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+void DrmOverlayCandidatesHost::SendRequest(
+    const OverlaySurfaceCandidateList& candidates,
+    const OverlayCheck_Params& check) {
+  if (!platform_support_->IsConnected())
+    return;
+  pending_checks_.push_back(check);
+  std::vector<OverlayCheck_Params> list;
+  for (const auto& candidate : candidates)
+    list.push_back(OverlayCheck_Params(candidate));
+  platform_support_->Send(
+      new OzoneGpuMsg_CheckOverlayCapabilities(widget_, list));
+}
+
+void DrmOverlayCandidatesHost::OnOverlayResult(bool* handled,
+                                               gfx::AcceleratedWidget widget,
+                                               bool result) {
+  if (widget != widget_)
+    return;
+  *handled = true;
+  DCHECK(!pending_checks_.empty());
+  ProcessResult(pending_checks_.front(), result);
+  pending_checks_.pop_front();
+}
+
+void DrmOverlayCandidatesHost::ProcessResult(const OverlayCheck_Params& check,
+                                             bool result) {
+  if (result)
+    cache_.Put(check, true);
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/drm/host/drm_overlay_candidates_host.h b/ui/ozone/platform/drm/host/drm_overlay_candidates_host.h
new file mode 100644
index 0000000..2f00cac
--- /dev/null
+++ b/ui/ozone/platform/drm/host/drm_overlay_candidates_host.h
@@ -0,0 +1,85 @@
+// 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 UI_OZONE_PLATFORM_DRM_HOST_OVERLAY_CANDIDATES_H_
+#define UI_OZONE_PLATFORM_DRM_HOST_OVERLAY_CANDIDATES_H_
+
+#include <deque>
+#include <map>
+#include <vector>
+
+#include "base/containers/mru_cache.h"
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
+#include "ui/ozone/public/gpu_platform_support_host.h"
+#include "ui/ozone/public/overlay_candidates_ozone.h"
+
+namespace ui {
+
+class DrmGpuPlatformSupportHost;
+
+// This is an implementation of OverlayCandidatesOzone where the driver is asked
+// about overlay capabilities via IPC. We have no way of querying abstract
+// capabilities, only if a particular configuration is supported or not.
+// Each time we we are asked if a particular configuration is supported, if we
+// have not seen that configuration before, it is IPCed to the GPU via
+// OzoneGpuMsg_CheckOverlayCapabilities; a test commit is then performed and
+// the result is returned in OzoneHostMsg_OverlayCapabilitiesReceived. Testing
+// is asynchronous, until the reply arrives that configuration will be failed.
+//
+// There is a many:1 relationship between this class and
+// DrmGpuPlatformSupportHost, each compositor will own one of these objects.
+// Each request has a unique request ID, which is assigned from a shared
+// sequence number so that replies can be routed to the correct object.
+class DrmOverlayCandidatesHost : public OverlayCandidatesOzone,
+                                 public GpuPlatformSupportHost {
+  struct OverlayCompare {
+    bool operator()(const OverlayCheck_Params& l, const OverlayCheck_Params& r);
+  };
+
+ public:
+  DrmOverlayCandidatesHost(gfx::AcceleratedWidget widget,
+                           DrmGpuPlatformSupportHost* platform_support);
+  ~DrmOverlayCandidatesHost() override;
+
+  // OverlayCandidatesOzone:
+  void CheckOverlaySupport(OverlaySurfaceCandidateList* candidates) override;
+
+  // GpuPlatformSupportHost:
+  void OnChannelEstablished(
+      int host_id,
+      scoped_refptr<base::SingleThreadTaskRunner> send_runner,
+      const base::Callback<void(IPC::Message*)>& sender) override;
+  void OnChannelDestroyed(int host_id) override;
+  bool OnMessageReceived(const IPC::Message& message) override;
+
+ private:
+  void SendRequest(const OverlaySurfaceCandidateList& candidates,
+                   const OverlayCheck_Params& check);
+  void OnOverlayResult(bool* handled,
+                       gfx::AcceleratedWidget widget,
+                       bool result);
+  void ProcessResult(const OverlayCheck_Params& check, bool result);
+
+  void CheckSingleOverlay(OverlaySurfaceCandidateList* candidates);
+
+  gfx::AcceleratedWidget widget_;
+  DrmGpuPlatformSupportHost* platform_support_;  // Not owned.
+
+  std::deque<OverlayCheck_Params> pending_checks_;
+
+  template <class KeyType, class ValueType>
+  struct OverlayMap {
+    typedef std::map<KeyType, ValueType, OverlayCompare> Type;
+  };
+  base::MRUCacheBase<OverlayCheck_Params,
+                     bool,
+                     base::MRUCacheNullDeletor<bool>,
+                     OverlayMap> cache_;
+
+  DISALLOW_COPY_AND_ASSIGN(DrmOverlayCandidatesHost);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_DRM_HOST_OVERLAY_CANDIDATES_H_
diff --git a/ui/ozone/platform/drm/host/drm_overlay_manager.cc b/ui/ozone/platform/drm/host/drm_overlay_manager.cc
index 7143001..4f101cc3 100644
--- a/ui/ozone/platform/drm/host/drm_overlay_manager.cc
+++ b/ui/ozone/platform/drm/host/drm_overlay_manager.cc
@@ -6,59 +6,17 @@
 
 #include "base/command_line.h"
 #include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/ozone/platform/drm/host/drm_overlay_candidates_host.h"
 #include "ui/ozone/public/overlay_candidates_ozone.h"
 #include "ui/ozone/public/ozone_switches.h"
 
 namespace ui {
-namespace {
 
-class SingleOverlay : public OverlayCandidatesOzone {
- public:
-  SingleOverlay() {}
-  ~SingleOverlay() override {}
-
-  void CheckOverlaySupport(OverlaySurfaceCandidateList* candidates) override {
-    if (candidates->size() == 2) {
-      OverlayCandidatesOzone::OverlaySurfaceCandidate* first =
-          &(*candidates)[0];
-      OverlayCandidatesOzone::OverlaySurfaceCandidate* second =
-          &(*candidates)[1];
-      OverlayCandidatesOzone::OverlaySurfaceCandidate* overlay;
-      if (first->plane_z_order == 0) {
-        overlay = second;
-      } else if (second->plane_z_order == 0) {
-        overlay = first;
-      } else {
-        NOTREACHED();
-        return;
-      }
-      // 0.01 constant chosen to match DCHECKs in gfx::ToNearestRect and avoid
-      // that code asserting on quads that we accept.
-      if (overlay->plane_z_order > 0 &&
-          IsTransformSupported(overlay->transform) &&
-          gfx::IsNearestRectWithinDistance(overlay->display_rect, 0.01f)) {
-        overlay->overlay_handled = true;
-      }
-    }
-  }
-
- private:
-  bool IsTransformSupported(gfx::OverlayTransform transform) {
-    switch (transform) {
-      case gfx::OVERLAY_TRANSFORM_NONE:
-        return true;
-      default:
-        return false;
-    }
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(SingleOverlay);
-};
-
-}  // namespace
-
-DrmOverlayManager::DrmOverlayManager(bool allow_surfaceless)
-    : allow_surfaceless_(allow_surfaceless) {
+DrmOverlayManager::DrmOverlayManager(
+    bool allow_surfaceless,
+    DrmGpuPlatformSupportHost* platform_support_host)
+    : platform_support_host_(platform_support_host),
+      allow_surfaceless_(allow_surfaceless) {
   is_supported_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kOzoneTestSingleOverlaySupport);
 }
@@ -70,7 +28,8 @@
     gfx::AcceleratedWidget w) {
   if (!is_supported_)
     return nullptr;
-  return make_scoped_ptr(new SingleOverlay());
+  return make_scoped_ptr(
+      new DrmOverlayCandidatesHost(w, platform_support_host_));
 }
 
 bool DrmOverlayManager::CanShowPrimaryPlaneAsOverlay() {
diff --git a/ui/ozone/platform/drm/host/drm_overlay_manager.h b/ui/ozone/platform/drm/host/drm_overlay_manager.h
index 91bdd51..fcaf6212 100644
--- a/ui/ozone/platform/drm/host/drm_overlay_manager.h
+++ b/ui/ozone/platform/drm/host/drm_overlay_manager.h
@@ -5,14 +5,16 @@
 #ifndef UI_OZONE_PLATFORM_DRM_HOST_DRM_OVERLAY_MANAGER_H_
 #define UI_OZONE_PLATFORM_DRM_HOST_DRM_OVERLAY_MANAGER_H_
 
-#include "base/memory/scoped_ptr.h"
 #include "ui/ozone/public/overlay_manager_ozone.h"
 
 namespace ui {
 
+class DrmGpuPlatformSupportHost;
+
 class DrmOverlayManager : public OverlayManagerOzone {
  public:
-  DrmOverlayManager(bool allow_surfaceless);
+  DrmOverlayManager(bool allow_surfaceless,
+                    DrmGpuPlatformSupportHost* platform_support_host);
   ~DrmOverlayManager() override;
 
   // OverlayManagerOzone:
@@ -21,6 +23,7 @@
   bool CanShowPrimaryPlaneAsOverlay() override;
 
  private:
+  DrmGpuPlatformSupportHost* platform_support_host_;
   bool allow_surfaceless_;
   bool is_supported_;
 
diff --git a/ui/ozone/platform/drm/host/drm_window_host.cc b/ui/ozone/platform/drm/host/drm_window_host.cc
index 54913814..4ce21c3 100644
--- a/ui/ozone/platform/drm/host/drm_window_host.cc
+++ b/ui/ozone/platform/drm/host/drm_window_host.cc
@@ -45,7 +45,7 @@
   cursor_->OnWindowRemoved(widget_);
 
   sender_->RemoveChannelObserver(this);
-  sender_->Send(new OzoneGpuMsg_DestroyWindowDelegate(widget_));
+  sender_->Send(new OzoneGpuMsg_DestroyWindow(widget_));
 }
 
 void DrmWindowHost::Initialize() {
@@ -179,7 +179,7 @@
 }
 
 void DrmWindowHost::OnChannelEstablished() {
-  sender_->Send(new OzoneGpuMsg_CreateWindowDelegate(widget_));
+  sender_->Send(new OzoneGpuMsg_CreateWindow(widget_));
   SendBoundsChange();
 }
 
diff --git a/ui/ozone/platform/drm/ozone_platform_drm.cc b/ui/ozone/platform/drm/ozone_platform_drm.cc
index c0a6ce7..3c4a623 100644
--- a/ui/ozone/platform/drm/ozone_platform_drm.cc
+++ b/ui/ozone/platform/drm/ozone_platform_drm.cc
@@ -95,13 +95,13 @@
         scoped_ptr<DrmDeviceGenerator>(new DrmDeviceGenerator())));
     window_manager_.reset(new DrmWindowHostManager());
     cursor_.reset(new DrmCursor(window_manager_.get()));
-    overlay_manager_.reset(new DrmOverlayManager(false));
+    overlay_manager_.reset(new DrmOverlayManager(false, nullptr));
     surface_factory_ozone_.reset(new DrmSurfaceFactory(screen_manager_.get()));
     scoped_ptr<DrmGpuDisplayManager> display_manager(new DrmGpuDisplayManager(
         screen_manager_.get(), drm_device_manager_.get()));
     gpu_platform_support_.reset(new DrmGpuPlatformSupport(
         drm_device_manager_.get(), screen_manager_.get(),
-        display_manager.Pass()));
+        buffer_generator_.get(), display_manager.Pass()));
     gpu_platform_support_host_.reset(
         new DrmGpuPlatformSupportHost(cursor_.get()));
     display_manager_.reset(new DrmDisplayHostManager(
diff --git a/ui/ozone/platform/drm/ozone_platform_gbm.cc b/ui/ozone/platform/drm/ozone_platform_gbm.cc
index d7b85a39..d70490e 100644
--- a/ui/ozone/platform/drm/ozone_platform_gbm.cc
+++ b/ui/ozone/platform/drm/ozone_platform_gbm.cc
@@ -158,7 +158,8 @@
     display_manager_.reset(new DrmDisplayHostManager(
         gpu_platform_support_host_.get(), device_manager_.get()));
     cursor_factory_ozone_.reset(new BitmapCursorFactoryOzone);
-    overlay_manager_.reset(new DrmOverlayManager(use_surfaceless_));
+    overlay_manager_.reset(new DrmOverlayManager(
+        use_surfaceless_, gpu_platform_support_host_.get()));
 #if defined(USE_XKBCOMMON)
     KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(make_scoped_ptr(
         new XkbKeyboardLayoutEngine(xkb_evdev_code_converter_)));
@@ -185,7 +186,7 @@
         screen_manager_.get(), drm_device_manager_.get()));
     gpu_platform_support_.reset(new DrmGpuPlatformSupport(
         drm_device_manager_.get(), screen_manager_.get(),
-        display_manager.Pass()));
+        buffer_generator_.get(), display_manager.Pass()));
   }
 
  private:
diff --git a/ui/ozone/public/overlay_candidates_ozone.h b/ui/ozone/public/overlay_candidates_ozone.h
index c573330..2ae0d12 100644
--- a/ui/ozone/public/overlay_candidates_ozone.h
+++ b/ui/ozone/public/overlay_candidates_ozone.h
@@ -27,6 +27,8 @@
     gfx::OverlayTransform transform;
     // Format of the buffer to composite.
     SurfaceFactoryOzone::BufferFormat format;
+    // Size of the buffer, in pixels.
+    gfx::Size buffer_size;
     // Rect on the display to position the overlay to. Input rectangle may
     // not have integer coordinates, but when accepting for overlay, must
     // be modified by CheckOverlaySupport to output integer values.
diff --git a/ui/ozone/public/surface_factory_ozone.cc b/ui/ozone/public/surface_factory_ozone.cc
index c4efc0611..09344c43 100644
--- a/ui/ozone/public/surface_factory_ozone.cc
+++ b/ui/ozone/public/surface_factory_ozone.cc
@@ -13,22 +13,10 @@
 
 namespace ui {
 
-// static
-SurfaceFactoryOzone* SurfaceFactoryOzone::impl_ = NULL;
-
 SurfaceFactoryOzone::SurfaceFactoryOzone() {
-  DCHECK(!impl_) << "There should only be a single SurfaceFactoryOzone.";
-  impl_ = this;
 }
 
 SurfaceFactoryOzone::~SurfaceFactoryOzone() {
-  DCHECK_EQ(impl_, this);
-  impl_ = NULL;
-}
-
-SurfaceFactoryOzone* SurfaceFactoryOzone::GetInstance() {
-  DCHECK(impl_) << "No SurfaceFactoryOzone implementation set.";
-  return impl_;
 }
 
 intptr_t SurfaceFactoryOzone::GetNativeDisplay() {
diff --git a/ui/ozone/public/surface_factory_ozone.h b/ui/ozone/public/surface_factory_ozone.h
index 3a509960..5e813dc 100644
--- a/ui/ozone/public/surface_factory_ozone.h
+++ b/ui/ozone/public/surface_factory_ozone.h
@@ -8,16 +8,11 @@
 #include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/native_library.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/overlay_transform.h"
 #include "ui/ozone/ozone_base_export.h"
 
-class SkBitmap;
-class SkCanvas;
-
 namespace ui {
 
 class NativePixmap;
@@ -64,7 +59,7 @@
     UNKNOWN,
     BGRA_8888,
     RGBX_8888,
-    RGB_888,
+    BUFFER_FORMAT_LAST = RGBX_8888
   };
 
   enum BufferUsage {
@@ -78,12 +73,6 @@
   typedef base::Callback<void(GLGetProcAddressProc)>
       SetGLGetProcAddressProcCallback;
 
-  SurfaceFactoryOzone();
-  virtual ~SurfaceFactoryOzone();
-
-  // Returns the singleton instance.
-  static SurfaceFactoryOzone* GetInstance();
-
   // Returns native platform display handle. This is used to obtain the EGL
   // display connection for the native display.
   virtual intptr_t GetNativeDisplay();
@@ -159,8 +148,12 @@
   // such as MAP for zero copy or SCANOUT for display controller.
   virtual bool CanCreateNativePixmap(BufferUsage usage);
 
+ protected:
+  SurfaceFactoryOzone();
+  virtual ~SurfaceFactoryOzone();
+
  private:
-  static SurfaceFactoryOzone* impl_;  // not owned
+  DISALLOW_COPY_AND_ASSIGN(SurfaceFactoryOzone);
 };
 
 }  // namespace ui
diff --git a/ui/ozone/public/system_input_injector.h b/ui/ozone/public/system_input_injector.h
index 9dc346d9..3c379c0 100644
--- a/ui/ozone/public/system_input_injector.h
+++ b/ui/ozone/public/system_input_injector.h
@@ -41,7 +41,9 @@
 
   // Simulates a key press.  SystemInputInjector maps |physical_key| to the
   // correct logical key based on the current keyboard layout.
-  virtual void InjectKeyPress(DomCode physical_key, bool down) = 0;
+  virtual void InjectKeyPress(DomCode physical_key,
+                              bool down,
+                              bool enable_repeat) = 0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SystemInputInjector);
diff --git a/ui/views/DEPS b/ui/views/DEPS
index c1d3570..3aa9664 100644
--- a/ui/views/DEPS
+++ b/ui/views/DEPS
@@ -25,4 +25,7 @@
   "examples_browser_main_parts\.cc": [
     "+ui/wm/test"
   ],
+  "view_unittest\.cc": [
+    "+cc/playback"
+  ],
 }
diff --git a/ui/views/accessibility/ax_aura_obj_wrapper.h b/ui/views/accessibility/ax_aura_obj_wrapper.h
index 00f9c59..ab6f925 100644
--- a/ui/views/accessibility/ax_aura_obj_wrapper.h
+++ b/ui/views/accessibility/ax_aura_obj_wrapper.h
@@ -10,6 +10,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "ui/gfx/geometry/point.h"
 #include "ui/views/views_export.h"
 
 namespace ui {
@@ -36,6 +37,7 @@
   virtual void Focus() {}
   virtual void MakeVisible() {}
   virtual void SetSelection(int32 start, int32 end) {}
+  virtual void ShowContextMenu() {}
 };
 
 }  // namespace views
diff --git a/ui/views/accessibility/ax_view_obj_wrapper.cc b/ui/views/accessibility/ax_view_obj_wrapper.cc
index 8c9d3bc..3e65ba43 100644
--- a/ui/views/accessibility/ax_view_obj_wrapper.cc
+++ b/ui/views/accessibility/ax_view_obj_wrapper.cc
@@ -95,4 +95,9 @@
   // TODO(dtseng): Implement.
 }
 
+void AXViewObjWrapper::ShowContextMenu() {
+  view_->ShowContextMenu(view_->bounds().CenterPoint(),
+                         ui::MENU_SOURCE_KEYBOARD);
+}
+
 }  // namespace views
diff --git a/ui/views/accessibility/ax_view_obj_wrapper.h b/ui/views/accessibility/ax_view_obj_wrapper.h
index 4208bfc..39cbc65 100644
--- a/ui/views/accessibility/ax_view_obj_wrapper.h
+++ b/ui/views/accessibility/ax_view_obj_wrapper.h
@@ -27,6 +27,7 @@
   void Focus() override;
   void MakeVisible() override;
   void SetSelection(int32 start, int32 end) override;
+  void ShowContextMenu() override;
 
  private:
   View* view_;
diff --git a/ui/views/button_drag_utils.cc b/ui/views/button_drag_utils.cc
index 0e7b3982..a84fa62 100644
--- a/ui/views/button_drag_utils.cc
+++ b/ui/views/button_drag_utils.cc
@@ -8,7 +8,7 @@
 #include "ui/base/dragdrop/drag_utils.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/base/resource/resource_bundle.h"
-#include "ui/compositor/paint_context.h"
+#include "ui/compositor/canvas_painter.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/vector2d.h"
@@ -76,7 +76,7 @@
   // Render the image.
   scoped_ptr<gfx::Canvas> canvas(
       views::GetCanvasForDragImage(widget, prefsize));
-  button.Paint(ui::PaintContext(canvas.get()));
+  button.Paint(ui::CanvasPainter(canvas.get(), 1.f).context());
   drag_utils::SetDragImageOnDataObject(*canvas, press_point, data);
 }
 
diff --git a/ui/views/cocoa/bridged_content_view.mm b/ui/views/cocoa/bridged_content_view.mm
index fa0731c8..5325a58 100644
--- a/ui/views/cocoa/bridged_content_view.mm
+++ b/ui/views/cocoa/bridged_content_view.mm
@@ -8,7 +8,7 @@
 #import "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #include "ui/base/ime/text_input_client.h"
-#include "ui/compositor/paint_context.h"
+#include "ui/compositor/canvas_painter.h"
 #import "ui/events/cocoa/cocoa_event_utils.h"
 #include "ui/events/keycodes/dom/dom_code.h"
 #import "ui/events/keycodes/keyboard_code_conversion_mac.h"
@@ -312,7 +312,8 @@
     return;
 
   gfx::CanvasSkiaPaint canvas(dirtyRect, false /* opaque */);
-  hostedView_->GetWidget()->OnNativeWidgetPaint(ui::PaintContext(&canvas));
+  hostedView_->GetWidget()->OnNativeWidgetPaint(
+      ui::CanvasPainter(&canvas, 1.f).context());
 }
 
 - (NSTextInputContext*)inputContext {
diff --git a/ui/views/cocoa/native_widget_mac_nswindow.mm b/ui/views/cocoa/native_widget_mac_nswindow.mm
index 00b2e1a..50e8dfa4 100644
--- a/ui/views/cocoa/native_widget_mac_nswindow.mm
+++ b/ui/views/cocoa/native_widget_mac_nswindow.mm
@@ -40,7 +40,12 @@
 }
 
 - (BOOL)canBecomeMainWindow {
-  return [self delegate] && [self viewsWidget]->CanActivate();
+  if (![self delegate])
+    return NO;
+
+  // Dialogs shouldn't take large shadows away from their parent window.
+  views::Widget* widget = [self viewsWidget];
+  return widget->CanActivate() && !widget->IsDialogBox();
 }
 
 // Override sendEvent to allow key events to be forwarded to a toolkit-views
diff --git a/ui/views/controls/label_unittest.cc b/ui/views/controls/label_unittest.cc
index 32fabd78..47cb37a 100644
--- a/ui/views/controls/label_unittest.cc
+++ b/ui/views/controls/label_unittest.cc
@@ -9,7 +9,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/accessibility/ax_view_state.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/compositor/paint_context.h"
+#include "ui/compositor/canvas_painter.h"
 #include "ui/gfx/canvas.h"
 #include "ui/views/border.h"
 #include "ui/views/test/focus_manager_test.h"
@@ -305,14 +305,14 @@
   label.SetBounds(0, 0, 200, 200);
 
   gfx::Canvas canvas(gfx::Size(200, 200), 1.0f, true);
-  label.Paint(ui::PaintContext(&canvas));
+  label.Paint(ui::CanvasPainter(&canvas, 1.f).context());
   EXPECT_EQ(1u, label.lines_.size());
   EXPECT_EQ(ASCIIToUTF16("Example"), label.lines_[0]->GetDisplayText());
 
   label.SetText(ASCIIToUTF16("Altered"));
   // The altered text should be painted even though Layout() or SetBounds() are
   // not called.
-  label.Paint(ui::PaintContext(&canvas));
+  label.Paint(ui::CanvasPainter(&canvas, 1.f).context());
   EXPECT_EQ(1u, label.lines_.size());
   EXPECT_EQ(ASCIIToUTF16("Altered"), label.lines_[0]->GetDisplayText());
 }
@@ -482,7 +482,7 @@
 
   // Paint() doesn't change the preferred size.
   gfx::Canvas canvas;
-  label.Paint(ui::PaintContext(&canvas));
+  label.Paint(ui::CanvasPainter(&canvas, 1.f).context());
   EXPECT_EQ(narrow_size.ToString(), label.GetPreferredSize().ToString());
 }
 
@@ -555,7 +555,7 @@
   EXPECT_EQ(0u, label.lines_.size());
 
   gfx::Canvas canvas(preferred_size, 1.0f, true);
-  label.Paint(ui::PaintContext(&canvas));
+  label.Paint(ui::CanvasPainter(&canvas, 1.f).context());
   EXPECT_EQ(1u, label.lines_.size());
 
   // Label should recreate its RenderText object when it's invisible, to release
@@ -575,14 +575,14 @@
   label.SetVisible(true);
   EXPECT_EQ(0u, label.lines_.size());
 
-  label.Paint(ui::PaintContext(&canvas));
+  label.Paint(ui::CanvasPainter(&canvas, 1.f).context());
   EXPECT_EQ(1u, label.lines_.size());
 
   // Changing layout just resets |lines_|. It'll recover next time it's drawn.
   label.SetBounds(0, 0, 10, 10);
   EXPECT_EQ(0u, label.lines_.size());
 
-  label.Paint(ui::PaintContext(&canvas));
+  label.Paint(ui::CanvasPainter(&canvas, 1.f).context());
   EXPECT_EQ(1u, label.lines_.size());
 }
 
@@ -597,7 +597,7 @@
   label.SizeToPreferredSize();
 
   gfx::Canvas canvas(label.GetPreferredSize(), 1.0f, true);
-  label.Paint(ui::PaintContext(&canvas));
+  label.Paint(ui::CanvasPainter(&canvas, 1.f).context());
 
   // There's only one 'line', RenderText itself supports multiple lines.
   EXPECT_EQ(1u, label.lines_.size());
diff --git a/ui/views/controls/menu/menu_event_dispatcher_linux.cc b/ui/views/controls/menu/menu_event_dispatcher.cc
similarity index 97%
rename from ui/views/controls/menu/menu_event_dispatcher_linux.cc
rename to ui/views/controls/menu/menu_event_dispatcher.cc
index f61d58b..e24365b 100644
--- a/ui/views/controls/menu/menu_event_dispatcher_linux.cc
+++ b/ui/views/controls/menu/menu_event_dispatcher.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 "ui/views/controls/menu/menu_event_dispatcher_linux.h"
+#include "ui/views/controls/menu/menu_event_dispatcher.h"
 
 #include "base/memory/scoped_ptr.h"
 #include "ui/aura/window.h"
diff --git a/ui/views/controls/menu/menu_event_dispatcher_linux.h b/ui/views/controls/menu/menu_event_dispatcher.h
similarity index 83%
rename from ui/views/controls/menu/menu_event_dispatcher_linux.h
rename to ui/views/controls/menu/menu_event_dispatcher.h
index 657cb7e..cc6eeba 100644
--- a/ui/views/controls/menu/menu_event_dispatcher_linux.h
+++ b/ui/views/controls/menu/menu_event_dispatcher.h
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifndef UI_VIEWS_CONTROLS_MENU_MENU_EVENT_DISPATCHER_H_
+#define UI_VIEWS_CONTROLS_MENU_MENU_EVENT_DISPATCHER_H_
+
 #include "base/macros.h"
 #include "ui/events/platform/platform_event_dispatcher.h"
 
@@ -30,3 +33,5 @@
 
 }  // namespace internal
 }  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_MENU_MENU_EVENT_DISPATCHER_H_
diff --git a/ui/views/controls/menu/menu_message_loop_aura.cc b/ui/views/controls/menu/menu_message_loop_aura.cc
index 9ec89e9..3ed33281 100644
--- a/ui/views/controls/menu/menu_message_loop_aura.cc
+++ b/ui/views/controls/menu/menu_message_loop_aura.cc
@@ -29,7 +29,7 @@
 #include "ui/views/controls/menu/menu_message_pump_dispatcher_win.h"
 #include "ui/views/win/hwnd_util.h"
 #else
-#include "ui/views/controls/menu/menu_event_dispatcher_linux.h"
+#include "ui/views/controls/menu/menu_event_dispatcher.h"
 #endif
 
 using aura::client::ScreenPositionClient;
@@ -60,8 +60,10 @@
   ~ActivationChangeObserverImpl() override { Cleanup(); }
 
   // aura::client::ActivationChangeObserver:
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override {
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override {
     if (!controller_->drag_in_progress())
       controller_->CancelAll();
   }
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 9e4111d..347de70d 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -14,7 +14,7 @@
 #include "ui/base/dragdrop/drag_utils.h"
 #include "ui/base/touch/selection_bound.h"
 #include "ui/base/ui_base_switches_util.h"
-#include "ui/compositor/paint_context.h"
+#include "ui/compositor/canvas_painter.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/events/event.h"
 #include "ui/events/keycodes/keyboard_codes.h"
@@ -1082,7 +1082,7 @@
   // Desktop Linux Aura does not yet support transparency in drag images.
   canvas->DrawColor(GetBackgroundColor());
 #endif
-  label.Paint(ui::PaintContext(canvas.get()));
+  label.Paint(ui::CanvasPainter(canvas.get(), 1.f).context());
   const gfx::Vector2d kOffset(-15, 0);
   drag_utils::SetDragImageOnDataObject(*canvas, kOffset, data);
   if (controller_)
diff --git a/ui/views/controls/webview/webview_interactive_uitest.cc b/ui/views/controls/webview/webview_interactive_uitest.cc
index e13b24e..88aab9f 100644
--- a/ui/views/controls/webview/webview_interactive_uitest.cc
+++ b/ui/views/controls/webview/webview_interactive_uitest.cc
@@ -92,8 +92,8 @@
   content::WebContents* web_contents1 = webview->GetWebContents();
   web_contents1->GetRenderViewHost()->GetProcess()->Init();
   content::RenderViewHostTester::For(web_contents1->GetRenderViewHost())
-      ->CreateRenderView(base::string16(), MSG_ROUTING_NONE, MSG_ROUTING_NONE,
-                         -1, false);
+      ->CreateTestRenderView(base::string16(), MSG_ROUTING_NONE,
+                             MSG_ROUTING_NONE, -1, false);
   webview->RequestFocus();
   ui::TextInputClient* client1 = webview->GetTextInputClient();
   EXPECT_NE(nullptr, client1);
@@ -105,8 +105,8 @@
                                                         nullptr));
   web_contents2->GetRenderViewHost()->GetProcess()->Init();
   content::RenderViewHostTester::For(web_contents2->GetRenderViewHost())
-      ->CreateRenderView(base::string16(), MSG_ROUTING_NONE, MSG_ROUTING_NONE,
-                         -1, false);
+      ->CreateTestRenderView(base::string16(), MSG_ROUTING_NONE,
+                             MSG_ROUTING_NONE, -1, false);
   webview->SetWebContents(web_contents2.get());
   ui::TextInputClient* client2 = webview->GetTextInputClient();
   EXPECT_NE(nullptr, client2);
diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc
index d4a270e..1a103b73 100644
--- a/ui/views/view_unittest.cc
+++ b/ui/views/view_unittest.cc
@@ -9,6 +9,8 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "cc/playback/display_item_list.h"
+#include "cc/playback/display_item_list_settings.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -445,21 +447,29 @@
   v2->SetBounds(3, 4, 6, 5);
   v1->AddChildView(v2);
 
-  gfx::Canvas canvas(root_view->size(), 1.f, true);
-  gfx::Rect paint_area(1, 1);
-
-  EXPECT_FALSE(v1->did_paint_);
-  EXPECT_FALSE(v2->did_paint_);
-  root_view->Paint(ui::PaintContext(&canvas));
-  EXPECT_TRUE(v1->did_paint_);
-  EXPECT_TRUE(v2->did_paint_);
-
+  // Paint everything once, since it has to build its cache. Then we can test
+  // invalidation.
+  gfx::Rect first_paint(1, 1);
+  scoped_refptr<cc::DisplayItemList> list =
+      cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint, first_paint));
   v1->Reset();
   v2->Reset();
+
+  gfx::Rect paint_area(1, 1);
+  gfx::Rect root_area(root_view->size());
+  list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
+
+  // With a known invalidation, v1 and v2 are not painted.
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, root_area, paint_area));
+  EXPECT_FALSE(v1->did_paint_);
+  EXPECT_FALSE(v2->did_paint_);
+
+  // With unknown invalidation, v1 and v2 are painted.
   root_view->Paint(
-      ui::PaintContext(ui::PaintContext(&canvas, paint_area),
+      ui::PaintContext(ui::PaintContext(list.get(), 1.f, root_area, paint_area),
                        ui::PaintContext::CLONE_WITHOUT_INVALIDATION));
   EXPECT_TRUE(v1->did_paint_);
   EXPECT_TRUE(v2->did_paint_);
@@ -480,12 +490,22 @@
   v2->SetBounds(3, 4, 6, 5);
   v1->AddChildView(v2);
 
-  gfx::Canvas canvas(root_view->size(), 1.f, true);
+  // Paint everything once, since it has to build its cache. Then we can test
+  // invalidation.
+  gfx::Rect first_paint(1, 1);
+  scoped_refptr<cc::DisplayItemList> list =
+      cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint, first_paint));
+  v1->Reset();
+  v2->Reset();
+
   gfx::Rect paint_area(25, 26);
+  gfx::Rect root_area(root_view->size());
+  list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
 
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
-  root_view->Paint(ui::PaintContext(&canvas, paint_area));
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, root_area, paint_area));
   EXPECT_TRUE(v1->did_paint_);
   EXPECT_TRUE(v2->did_paint_);
 }
@@ -518,12 +538,22 @@
   EXPECT_EQ(gfx::Rect(6, 15, 6, 5), v2->layer()->bounds());
   v2->SetPaintToLayer(false);
 
-  gfx::Canvas canvas(root_view->size(), 1.f, true);
+  // Paint everything once, since it has to build its cache. Then we can test
+  // invalidation.
+  gfx::Rect first_paint(1, 1);
+  scoped_refptr<cc::DisplayItemList> list =
+      cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint, first_paint));
+  v1->Reset();
+  v2->Reset();
+
   gfx::Rect paint_area(25, 26);
+  gfx::Rect root_area(root_view->size());
+  list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
 
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
-  root_view->Paint(ui::PaintContext(&canvas, paint_area));
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, root_area, paint_area));
   EXPECT_TRUE(v1->did_paint_);
   EXPECT_TRUE(v2->did_paint_);
 }
@@ -543,12 +573,22 @@
   v2->SetBounds(3, 4, 6, 5);
   v1->AddChildView(v2);
 
-  gfx::Canvas canvas(root_view->size(), 1.f, true);
+  // Paint everything once, since it has to build its cache. Then we can test
+  // invalidation.
+  gfx::Rect first_paint(1, 1);
+  scoped_refptr<cc::DisplayItemList> list =
+      cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint, first_paint));
+  v1->Reset();
+  v2->Reset();
+
   gfx::Rect paint_area(9, 10, 5, 6);
+  gfx::Rect root_area(root_view->size());
+  list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
 
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
-  root_view->Paint(ui::PaintContext(&canvas, paint_area));
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, root_area, paint_area));
   EXPECT_TRUE(v1->did_paint_);
   EXPECT_TRUE(v2->did_paint_);
 }
@@ -581,12 +621,22 @@
   EXPECT_EQ(gfx::Rect(6, 15, 6, 5), v2->layer()->bounds());
   v2->SetPaintToLayer(false);
 
-  gfx::Canvas canvas(root_view->size(), 1.f, true);
+  // Paint everything once, since it has to build its cache. Then we can test
+  // invalidation.
+  gfx::Rect first_paint(1, 1);
+  scoped_refptr<cc::DisplayItemList> list =
+      cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint, first_paint));
+  v1->Reset();
+  v2->Reset();
+
   gfx::Rect paint_area(2, 10, 5, 6);
+  gfx::Rect root_area(root_view->size());
+  list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
 
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
-  root_view->Paint(ui::PaintContext(&canvas, paint_area));
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, root_area, paint_area));
   EXPECT_TRUE(v1->did_paint_);
   EXPECT_TRUE(v2->did_paint_);
 }
@@ -606,12 +656,22 @@
   v2->SetBounds(3, 4, 6, 5);
   v1->AddChildView(v2);
 
-  gfx::Canvas canvas(root_view->size(), 1.f, true);
+  // Paint everything once, since it has to build its cache. Then we can test
+  // invalidation.
+  gfx::Rect first_paint(1, 1);
+  scoped_refptr<cc::DisplayItemList> list =
+      cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint, first_paint));
+  v1->Reset();
+  v2->Reset();
+
   gfx::Rect paint_area(9, 10, 2, 3);
+  gfx::Rect root_area(root_view->size());
+  list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
 
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
-  root_view->Paint(ui::PaintContext(&canvas, paint_area));
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, root_area, paint_area));
   EXPECT_TRUE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
 }
@@ -644,12 +704,22 @@
   EXPECT_EQ(gfx::Rect(6, 15, 6, 5), v2->layer()->bounds());
   v2->SetPaintToLayer(false);
 
-  gfx::Canvas canvas(root_view->size(), 1.f, true);
+  // Paint everything once, since it has to build its cache. Then we can test
+  // invalidation.
+  gfx::Rect first_paint(1, 1);
+  scoped_refptr<cc::DisplayItemList> list =
+      cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint, first_paint));
+  v1->Reset();
+  v2->Reset();
+
   gfx::Rect paint_area(2, 10, 2, 3);
+  gfx::Rect root_area(root_view->size());
+  list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
 
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
-  root_view->Paint(ui::PaintContext(&canvas, paint_area));
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, root_area, paint_area));
   EXPECT_TRUE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
 }
@@ -669,12 +739,22 @@
   v2->SetBounds(3, 4, 6, 5);
   v1->AddChildView(v2);
 
-  gfx::Canvas canvas(root_view->size(), 1.f, true);
+  // Paint everything once, since it has to build its cache. Then we can test
+  // invalidation.
+  gfx::Rect first_paint(1, 1);
+  scoped_refptr<cc::DisplayItemList> list =
+      cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint, first_paint));
+  v1->Reset();
+  v2->Reset();
+
   gfx::Rect paint_area(9, 10, 2, 1);
+  gfx::Rect root_area(root_view->size());
+  list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
 
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
-  root_view->Paint(ui::PaintContext(&canvas, paint_area));
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, root_area, paint_area));
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
 }
@@ -707,12 +787,22 @@
   EXPECT_EQ(gfx::Rect(6, 15, 6, 5), v2->layer()->bounds());
   v2->SetPaintToLayer(false);
 
-  gfx::Canvas canvas(root_view->size(), 1.f, true);
+  // Paint everything once, since it has to build its cache. Then we can test
+  // invalidation.
+  gfx::Rect first_paint(1, 1);
+  scoped_refptr<cc::DisplayItemList> list =
+      cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint, first_paint));
+  v1->Reset();
+  v2->Reset();
+
   gfx::Rect paint_area(2, 10, 2, 1);
+  gfx::Rect root_area(root_view->size());
+  list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
 
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
-  root_view->Paint(ui::PaintContext(&canvas, paint_area));
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, root_area, paint_area));
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
 }
@@ -732,13 +822,23 @@
   v2->SetBounds(3, 4, 6, 5);
   root_view->AddChildView(v2);
 
-  gfx::Canvas canvas(root_view->size(), 1.f, true);
+  // Paint everything once, since it has to build its cache. Then we can test
+  // invalidation.
+  gfx::Rect first_paint(1, 1);
+  scoped_refptr<cc::DisplayItemList> list =
+      cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint, first_paint));
+  v1->Reset();
+  v2->Reset();
+
   // Intersects with the second child only.
   gfx::Rect paint_area(3, 3, 1, 2);
+  gfx::Rect root_area(root_view->size());
+  list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
 
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
-  root_view->Paint(ui::PaintContext(&canvas, paint_area));
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, root_area, paint_area));
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_TRUE(v2->did_paint_);
 
@@ -749,7 +849,7 @@
   v2->Reset();
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
-  root_view->Paint(ui::PaintContext(&canvas, paint_area));
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, root_area, paint_area));
   EXPECT_TRUE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
 }
@@ -782,13 +882,23 @@
   EXPECT_EQ(gfx::Rect(16, 4, 6, 5), v2->layer()->bounds());
   v2->SetPaintToLayer(false);
 
-  gfx::Canvas canvas(root_view->size(), 1.f, true);
+  // Paint everything once, since it has to build its cache. Then we can test
+  // invalidation.
+  gfx::Rect first_paint(1, 1);
+  scoped_refptr<cc::DisplayItemList> list =
+      cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, first_paint, first_paint));
+  v1->Reset();
+  v2->Reset();
+
   // Intersects with the first child only.
   gfx::Rect paint_area(3, 10, 1, 2);
+  gfx::Rect root_area(root_view->size());
+  list = cc::DisplayItemList::Create(root_area, cc::DisplayItemListSettings());
 
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
-  root_view->Paint(ui::PaintContext(&canvas, paint_area));
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, root_area, paint_area));
   EXPECT_TRUE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
 
@@ -799,7 +909,7 @@
   v2->Reset();
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_FALSE(v2->did_paint_);
-  root_view->Paint(ui::PaintContext(&canvas, paint_area));
+  root_view->Paint(ui::PaintContext(list.get(), 1.f, root_area, paint_area));
   EXPECT_FALSE(v1->did_paint_);
   EXPECT_TRUE(v2->did_paint_);
 }
@@ -820,26 +930,36 @@
   v2->SetBounds(3, 4, 6, 5);
   v1->AddChildView(v2);
 
-  EXPECT_FALSE(v1->did_paint_);
-  EXPECT_FALSE(v2->did_paint_);
+  // Paint everything once, since it has to build its cache. Then we can test
+  // invalidation.
+  gfx::Rect first_paint(1, 1);
+  scoped_refptr<cc::DisplayItemList> list =
+      cc::DisplayItemList::Create(first_paint, cc::DisplayItemListSettings());
+  v1->Paint(ui::PaintContext(list.get(), 1.f, first_paint, first_paint));
+  v1->Reset();
+  v2->Reset();
 
   {
-    gfx::Canvas canvas(root_view->size(), 1.f, true);
     gfx::Rect paint_area(25, 26);
+    gfx::Rect view_area(root_view->size());
+    scoped_refptr<cc::DisplayItemList> list =
+        cc::DisplayItemList::Create(view_area, cc::DisplayItemListSettings());
 
     // The promoted views are not painted as they are separate paint roots.
-    root_view->Paint(ui::PaintContext(&canvas, paint_area));
+    root_view->Paint(ui::PaintContext(list.get(), 1.f, view_area, paint_area));
     EXPECT_FALSE(v1->did_paint_);
     EXPECT_FALSE(v2->did_paint_);
   }
 
   {
-    gfx::Canvas canvas(v1->size(), 1.f, true);
     gfx::Rect paint_area(1, 1);
+    gfx::Rect view_area(v1->size());
+    scoped_refptr<cc::DisplayItemList> list =
+        cc::DisplayItemList::Create(view_area, cc::DisplayItemListSettings());
 
     // The |v1| view is painted. If it used its offset incorrect, it would think
     // its at (10,11) instead of at (0,0) since it is the paint root.
-    v1->Paint(ui::PaintContext(&canvas, paint_area));
+    v1->Paint(ui::PaintContext(list.get(), 1.f, view_area, paint_area));
     EXPECT_TRUE(v1->did_paint_);
     EXPECT_FALSE(v2->did_paint_);
   }
@@ -847,12 +967,14 @@
   v1->Reset();
 
   {
-    gfx::Canvas canvas(v1->size(), 1.f, true);
     gfx::Rect paint_area(3, 3, 1, 2);
+    gfx::Rect view_area(v1->size());
+    scoped_refptr<cc::DisplayItemList> list =
+        cc::DisplayItemList::Create(view_area, cc::DisplayItemListSettings());
 
     // The |v2| view is painted also. If it used its offset incorrect, it would
     // think its at (13,15) instead of at (3,4) since |v1| is the paint root.
-    v1->Paint(ui::PaintContext(&canvas, paint_area));
+    v1->Paint(ui::PaintContext(list.get(), 1.f, view_area, paint_area));
     EXPECT_TRUE(v1->did_paint_);
     EXPECT_TRUE(v2->did_paint_);
   }
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index 6da0fa7..319667e 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -95,8 +95,6 @@
       'controls/menu/menu_controller_delegate.h',
       'controls/menu/menu_delegate.cc',
       'controls/menu/menu_delegate.h',
-      'controls/menu/menu_event_dispatcher_linux.cc',
-      'controls/menu/menu_event_dispatcher_linux.h',
       'controls/menu/menu_host.cc',
       'controls/menu/menu_host.h',
       'controls/menu/menu_host_root_view.cc',
@@ -370,6 +368,8 @@
       'bubble/tray_bubble_view.h',
       'controls/menu/display_change_listener_aura.cc',
       'controls/menu/menu_config_aura.cc',
+      'controls/menu/menu_event_dispatcher.cc',
+      'controls/menu/menu_event_dispatcher.h',
       'controls/menu/menu_message_loop_aura.cc',
       'controls/menu/menu_message_loop_aura.h',
       'controls/native/native_view_host_aura.cc',
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index c82ced73..33629f9a 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -1111,8 +1111,10 @@
 // DesktopNativeWidgetAura, aura::client::ActivationChangeObserver
 //    implementation:
 
-void DesktopNativeWidgetAura::OnWindowActivated(aura::Window* gained_active,
-                                                aura::Window* lost_active) {
+void DesktopNativeWidgetAura::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
   DCHECK(content_window_ == gained_active || content_window_ == lost_active);
   if (gained_active == content_window_ && restore_focus_on_activate_) {
     restore_focus_on_activate_ = false;
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
index e92aa840..0419fab 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -213,8 +213,10 @@
   bool ShouldActivate() const override;
 
   // Overridden from aura::client::ActivationChangeObserver:
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
 
   // Overridden from aura::client::FocusChangeObserver:
   void OnWindowFocused(aura::Window* gained_focus,
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
index a927a48..a663f38 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
@@ -678,10 +678,6 @@
   GetWidget()->non_client_view()->ResetWindowControls();
 }
 
-void DesktopWindowTreeHostWin::PaintLayeredWindow(gfx::Canvas* canvas) {
-  GetWidget()->GetRootView()->Paint(ui::PaintContext(canvas));
-}
-
 gfx::NativeViewAccessible DesktopWindowTreeHostWin::GetNativeViewAccessible() {
   return GetWidget()->GetRootView()->GetNativeViewAccessible();
 }
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
index dc9f1be..413c0c13 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
@@ -147,7 +147,6 @@
   void GetMinMaxSize(gfx::Size* min_size, gfx::Size* max_size) const override;
   gfx::Size GetRootViewSize() const override;
   void ResetWindowControls() override;
-  void PaintLayeredWindow(gfx::Canvas* canvas) override;
   gfx::NativeViewAccessible GetNativeViewAccessible() override;
   bool ShouldHandleSystemCommands() const override;
   InputMethod* GetInputMethod() override;
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index bf113e6..92ff22ac 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -936,8 +936,10 @@
 ////////////////////////////////////////////////////////////////////////////////
 // NativeWidgetAura, aura::client::ActivationChangeObserver implementation:
 
-void NativeWidgetAura::OnWindowActivated(aura::Window* gained_active,
-                                         aura::Window* lost_active) {
+void NativeWidgetAura::OnWindowActivated(
+    aura::client::ActivationChangeObserver::ActivationReason,
+    aura::Window* gained_active,
+    aura::Window* lost_active) {
   DCHECK(window_ == gained_active || window_ == lost_active);
   if (GetWidget()->GetFocusManager()) {
     if (window_ == gained_active)
diff --git a/ui/views/widget/native_widget_aura.h b/ui/views/widget/native_widget_aura.h
index 40a9c47..6c38c3e4 100644
--- a/ui/views/widget/native_widget_aura.h
+++ b/ui/views/widget/native_widget_aura.h
@@ -177,8 +177,10 @@
   bool ShouldActivate() const override;
 
   // Overridden from aura::client::ActivationChangeObserver:
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
 
   // Overridden from aura::client::FocusChangeObserver:
   void OnWindowFocused(aura::Window* gained_focus,
diff --git a/ui/views/widget/native_widget_mac_unittest.mm b/ui/views/widget/native_widget_mac_unittest.mm
index f3510d49..5434e93 100644
--- a/ui/views/widget/native_widget_mac_unittest.mm
+++ b/ui/views/widget/native_widget_mac_unittest.mm
@@ -670,6 +670,28 @@
   }
 }
 
+// Tests Cocoa properties that should be given to particular widget types.
+TEST_F(NativeWidgetMacTest, NativeProperties) {
+  // Create a regular widget (TYPE_WINDOW).
+  Widget* regular_widget = CreateNativeDesktopWidget();
+  EXPECT_TRUE([regular_widget->GetNativeWindow() canBecomeKeyWindow]);
+  EXPECT_TRUE([regular_widget->GetNativeWindow() canBecomeMainWindow]);
+
+  // Disabling activation should prevent key and main status.
+  regular_widget->widget_delegate()->set_can_activate(false);
+  EXPECT_FALSE([regular_widget->GetNativeWindow() canBecomeKeyWindow]);
+  EXPECT_FALSE([regular_widget->GetNativeWindow() canBecomeMainWindow]);
+
+  // Create a dialog widget (also TYPE_WINDOW), but with a DialogDelegate.
+  Widget* dialog_widget = views::DialogDelegate::CreateDialogWidget(
+      new ChildModalDialogDelegate, nullptr, regular_widget->GetNativeView());
+  EXPECT_TRUE([dialog_widget->GetNativeWindow() canBecomeKeyWindow]);
+  // Dialogs shouldn't take main status away from their parent.
+  EXPECT_FALSE([dialog_widget->GetNativeWindow() canBecomeMainWindow]);
+
+  regular_widget->CloseNow();
+}
+
 }  // namespace test
 }  // namespace views
 
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 3e262c1..76818369 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -2308,6 +2308,9 @@
   if (ui::GetTouchInputInfoWrapper(reinterpret_cast<HTOUCHINPUT>(l_param),
                                    num_points, input.get(),
                                    sizeof(TOUCHINPUT))) {
+    // input[i].dwTime doesn't necessarily relate to the system time at all,
+    // so use base::TimeTicks::Now().
+    const base::TimeTicks event_time = base::TimeTicks::Now();
     int flags = ui::GetModifiersFromKeyState();
     TouchEvents touch_events;
     for (int i = 0; i < num_points; ++i) {
@@ -2348,20 +2351,16 @@
         touch_event_type = ui::ET_TOUCH_MOVED;
       }
       if (touch_event_type != ui::ET_UNKNOWN) {
-        // input[i].dwTime doesn't necessarily relate to the system time at all,
-        // so use base::TimeTicks::Now()
-        const base::TimeTicks now = base::TimeTicks::Now();
         ui::TouchEvent event(touch_event_type,
                              gfx::Point(point.x, point.y),
                              id_generator_.GetGeneratedID(input[i].dwID),
-                             now - base::TimeTicks());
+                             event_time - base::TimeTicks());
         event.set_flags(flags);
         event.latency()->AddLatencyNumberWithTimestamp(
             ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
             0,
             0,
-            base::TimeTicks::FromInternalValue(
-                event.time_stamp().ToInternalValue()),
+            event_time,
             1);
 
         touch_events.push_back(event);
diff --git a/ui/views/win/hwnd_message_handler_delegate.h b/ui/views/win/hwnd_message_handler_delegate.h
index eda75f3..d5f5f813 100644
--- a/ui/views/win/hwnd_message_handler_delegate.h
+++ b/ui/views/win/hwnd_message_handler_delegate.h
@@ -74,8 +74,6 @@
 
   virtual void ResetWindowControls() = 0;
 
-  virtual void PaintLayeredWindow(gfx::Canvas* canvas) = 0;
-
   virtual InputMethod* GetInputMethod() = 0;
 
   virtual gfx::NativeViewAccessible GetNativeViewAccessible() = 0;
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.js b/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.js
index ecc9bab4..d795a76 100644
--- a/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.js
+++ b/ui/webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.js
@@ -54,6 +54,10 @@
   properties: {
     /**
      * If set, the ONC data properties will be used to display the icon.
+     * NOTE: Because this is a Polymer element, it can not be set using
+     * data binding; it must be set directly. TODO(stevenjb): Use
+     * NetworkStateProperties instead and replace CrOncDataElement with a
+     * set of utility functions.
      *
      * @type {?CrOncDataElement}
      */
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.css b/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.css
new file mode 100644
index 0000000..b4d5de05
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.css
@@ -0,0 +1,15 @@
+/* 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. */
+
+#container {
+  border: 1px solid;
+  max-height: 1000px;
+  min-height: 50px;
+  overflow-y: auto;
+}
+
+/* Note: the 'flex' attribute on core-list doesn't work as expected. */
+#networkList {
+  flex: 1;
+}
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.html b/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.html
new file mode 100644
index 0000000..af8f941
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.html
@@ -0,0 +1,20 @@
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_collapse/cr_collapse.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_data.html">
+
+<dom-module id="cr-network-list">
+  <link rel="import" type="css" href="cr_network_list.css">
+  <template>
+    <cr-collapse on-core-resize="onResized_" opened="{{opened}}">
+      <div id="container" class="layout vertical flex">
+        <template is="dom-repeat" items="[[networks]]">
+          <cr-network-list-item network-state="[[item]]" is-list-item
+              on-click="onSelected_">
+          </cr-network-list-item>
+        </template>
+      </div>
+    </cr-collapse>
+  </template>
+  <script src="cr_network_list.js"></script>
+</dom-module>
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.js b/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.js
new file mode 100644
index 0000000..98db0d92
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.js
@@ -0,0 +1,77 @@
+// 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 Polymer element for displaying a collapsable list of networks.
+ */
+
+(function() {
+
+/** @typedef {chrome.networkingPrivate.NetworkStateProperties} */
+var NetworkStateProperties;
+
+/**
+ * Polymer class definition for 'cr-network-list'.
+ * TODO(stevenjb): Update with iron-list(?) once implemented in Polymer 1.0.
+ * @element cr-network-list
+ */
+Polymer({
+  is: 'cr-network-list',
+
+  properties: {
+    /**
+     * The maximum height in pixels for the list.
+     */
+    maxHeight: {
+      type: Number,
+      value: 1000,
+      observer: 'maxHeightChanged_'
+    },
+
+    /**
+     * The list of network state properties for the items to display.
+     *
+     * @type {!Array<!NetworkStateProperties>}
+     */
+    networks: {
+      type: Array,
+      value: function() { return []; }
+    },
+
+    /**
+     * True if the list is opened.
+     *
+     * @attribute opened
+     * @type {boolean}
+     * @default false
+     */
+    opened: false,
+  },
+
+  /**
+   * Polymer maxHeight changed method.
+   */
+  maxHeightChanged_: function() {
+    this.$.container.style.maxHeight = this.maxHeight + "px";
+  },
+
+  /**
+   * Called when the cr-collapse element changes size (i.e. is opened).
+   * @private
+   */
+  onResized_: function() {
+    if (this.opened)
+      this.$.networkList.updateSize();
+  },
+
+  /**
+   * Event triggered when a list item is selected.
+   * @param {!{target: !CrNetworkListItem}} event
+   * @private
+   */
+  onSelected_: function(event) {
+    this.fire('selected', event.model.item);
+  }
+});
+})();
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.css b/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.css
new file mode 100644
index 0000000..a1b1025
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.css
@@ -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. */
+
+span {
+  cursor: default;
+}
+
+#divOuter {
+  border-style: none;
+  display: flex;
+  flex-direction: row;
+  margin: 0;
+  padding: 4px;
+}
+
+#divOuter.listItem:hover {
+  background-color: lightgrey;
+}
+
+#divIcon {
+  display: flex;
+  flex: 0 0 auto;
+  flex-direction: column;
+  justify-content: center;
+}
+
+#icon {
+  height: 32px;
+  width: 32px;
+}
+
+#divDetail {
+  display: flex;
+  flex: 1 0 auto;
+  flex-direction: row;
+}
+
+#divText {
+  display: flex;
+  flex: 1 0 auto;
+  flex-direction: column;
+  justify-content: center;
+}
+
+#networkName {
+  -webkit-margin-start: 8px;
+  font-size: 16px;
+}
+
+#networkState {
+  -webkit-margin-start: 8px;
+  color: grey;
+  font-size: 14px;
+}
+
+.connected {
+  font-weight: bold;
+}
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.html b/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.html
new file mode 100644
index 0000000..d9c37e8
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.html
@@ -0,0 +1,20 @@
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_onc/cr_onc_data.html">
+<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.html">
+
+<dom-module id="cr-network-list-item">
+  <link rel="import" type="css" href="cr_network_list_item.css">
+  <template>
+    <div id="divOuter" class$="[[isListItemClass_(isListItem)]]">
+      <div id="divIcon">
+        <cr-network-icon id="icon" isListItem="[[isListItem]]">
+        </cr-network-icon>
+      </div>
+      <div id="divText">
+        <span id="networkName"></span>
+        <span id="networkStateText" hidden$="[[isListItem]]"></span>
+      </div>
+    </div>
+  </template>
+  <script src="cr_network_list_item.js"></script>
+</dom-module>
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.js b/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.js
new file mode 100644
index 0000000..6b0e2e2
--- /dev/null
+++ b/ui/webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.js
@@ -0,0 +1,119 @@
+// 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 Polymer element for displaying information about a network
+ * in a list or summary based on ONC state properties.
+ */
+(function() {
+
+/** @typedef {chrome.networkingPrivate.NetworkStateProperties} */
+var NetworkStateProperties;
+
+/**
+ * TODO(stevenjb): Replace getText with a proper localization function that
+ * handles string substitution.
+ * Performs argument substitution, replacing %1, %2, etc in 'text' with
+ * corresponding entries in |args|.
+ * @param {string} text The string to perform the substitution on.
+ * @param {?Array<string>} args The arguments to replace %1, %2, etc with.
+ */
+function getText(text, args) {
+  var res = text;
+  if (!args)
+    return res;
+  for (var i = 0; i < args.length; ++i) {
+    var key = '%' + (i + 1);
+    res = res.replace(key, args[i]);
+  }
+  return res;
+}
+
+/**
+ * Returns the appropriate connection state text.
+ * @param {string} state The connection state.
+ * @param {string} name The name of the network.
+ */
+function getConnectionStateText(state, name) {
+  if (state == 'Connected')
+    return getText('Connected to %1', [name]);
+  if (state == 'Connecting')
+    return getText('Connecting to %1...', [name]);
+  if (state == 'NotConnected')
+    return getText('Not Connected');
+  return getText(state);
+};
+
+/**
+ * Polymer class definition for 'cr-network-list-item'.
+ * @element cr-network-list-item
+ */
+Polymer({
+  is: 'cr-network-list-item',
+
+  properties: {
+    /**
+     * The ONC data properties used to display the list item.
+     *
+     * @type {?NetworkStateProperties}
+     */
+    networkState: {
+      type: Object,
+      value: null,
+      observer: 'networkStateChanged_'
+    },
+
+    /**
+     * If true, the element is part of a list of networks and only displays
+     * the network icon and name. Otherwise the element is assumed to be a
+     * stand-alone item (e.g. as part of a summary) and displays the name
+     * of the network type plus the network name and connection state.
+     */
+    isListItem:  {
+      type: Boolean,
+      value: false
+    },
+  },
+
+  /**
+   * Polymer networkState changed method. Updates the element based on the
+   * network state.
+   */
+  networkStateChanged_: function() {
+    if (!this.networkState)
+      return;
+
+    // Set icon.networkState explicitly since networkState is an element.
+    this.$.icon.networkState = CrOncDataElement.create(this.networkState);
+
+    var network = this.networkState;
+    var isDisconnected =
+        network.ConnectionState == CrOnc.ConnectionState.NOT_CONNECTED;
+    if (this.isListItem) {
+      this.$.networkName.textContent = getText(network.Name);
+      this.$.networkName.classList.toggle('connected', !isDisconnected);
+    } else if (network.Name && network.ConnectionState) {
+      this.$.networkName.textContent = getText(network.Type);
+      this.$.networkName.classList.toggle('connected', false);
+      this.$.networkStateText.textContent =
+          getConnectionStateText(network.ConnectionState, network.Name);
+      this.$.networkStateText.classList.toggle('connected', !isDisconnected);
+    } else {
+      this.$.networkName.textContent = getText(network.Type);
+      this.$.networkName.classList.toggle('connected', false);
+      this.$.networkStateText.textContent = getText('Disabled');
+      this.$.networkStateText.classList.toggle('connected', false);
+    }
+  },
+
+  /**
+   * @param {string} isListItem The value of this.isListItem.
+   * @return {string} The class name based on isListItem.
+   * @private
+   */
+  isListItemClass_:  function(isListItem) {
+    return isListItem ? "isListItem" : "";
+  }
+});
+})();
diff --git a/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data.js b/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data.js
index 7dc8f2f..1eee57f2 100644
--- a/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data.js
+++ b/ui/webui/resources/cr_elements/v1_0/cr_onc/cr_onc_data.js
@@ -85,6 +85,10 @@
  * @return {!CrOncDataElement} A cr-onc-data element.
  */
 CrOncDataElement.create = function(state) {
+  if (!state) {
+    console.error('CrOncDataElement.create called with null state');
+    return null;
+  }
   var oncData = /** @type {!CrOncDataElement} */ (
       document.createElement('cr-onc-data'));
   oncData.data = state;
diff --git a/ui/webui/resources/cr_elements_resources.grdp b/ui/webui/resources/cr_elements_resources.grdp
index a05c08d..4719fb8 100644
--- a/ui/webui/resources/cr_elements_resources.grdp
+++ b/ui/webui/resources/cr_elements_resources.grdp
@@ -174,6 +174,24 @@
   <structure name="IDR_CR_ELEMENTS_1_0_CR_NETWORK_ICON_JS"
              file="../../webui/resources/cr_elements/v1_0/cr_network_icon/cr_network_icon.js"
              type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_NETWORK_LIST_CSS"
+             file="../../webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.css"
+             type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_NETWORK_LIST_HTML"
+             file="../../webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.html"
+             type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_NETWORK_LIST_JS"
+             file="../../webui/resources/cr_elements/v1_0/cr_network_list/cr_network_list.js"
+             type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_NETWORK_LIST_ITEM_CSS"
+             file="../../webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.css"
+             type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_NETWORK_LIST_ITEM_HTML"
+             file="../../webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.html"
+             type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_1_0_CR_NETWORK_LIST_ITEM_JS"
+             file="../../webui/resources/cr_elements/v1_0/cr_network_list_item/cr_network_list_item.js"
+             type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_1_0_CR_ONC_TYPES_JS"
              file="../../webui/resources/cr_elements/v1_0/cr_onc/cr_onc_types.js"
              type="chrome_html" />
diff --git a/ui/webui/resources/html/action_link.html b/ui/webui/resources/html/action_link.html
new file mode 100644
index 0000000..6c2852c
--- /dev/null
+++ b/ui/webui/resources/html/action_link.html
@@ -0,0 +1,2 @@
+<!-- Allows importing via HTML imports to avoid duplicating this resource. -->
+<script src="chrome://resources/js/action_link.js"></script>
\ No newline at end of file
diff --git a/ui/webui/resources/js/cr/ui/compiled_resources.gyp b/ui/webui/resources/js/cr/ui/compiled_resources.gyp
index c8da03c..06c91f9fe 100644
--- a/ui/webui/resources/js/cr/ui/compiled_resources.gyp
+++ b/ui/webui/resources/js/cr/ui/compiled_resources.gyp
@@ -13,5 +13,18 @@
       },
       'includes': ['../../../../../../third_party/closure_compiler/compile_js.gypi'],
     },
+    {
+      'target_name': 'overlay',
+      'variables': {
+        'depends': [
+          '../../cr.js',
+          '../../util.js',
+        ],
+        'externs': [
+          '../../../../../../third_party/closure_compiler/externs/chrome_send_externs.js',
+        ],
+      },
+      'includes': ['../../../../../../third_party/closure_compiler/compile_js.gypi'],
+    },
   ],
 }
diff --git a/ui/webui/resources/js/cr/ui/focus_outline_manager.js b/ui/webui/resources/js/cr/ui/focus_outline_manager.js
index df8dadc..5a8ed8e 100644
--- a/ui/webui/resources/js/cr/ui/focus_outline_manager.js
+++ b/ui/webui/resources/js/cr/ui/focus_outline_manager.js
@@ -41,19 +41,19 @@
 
     doc.addEventListener('focus', function(event) {
       // Update visibility only when focus is actually changed.
-      self.updateVisiblity_();
+      self.updateVisibility();
     }, true);
 
     doc.addEventListener('focusout', function(event) {
       window.setTimeout(function() {
         if (!doc.hasFocus()) {
           self.focusByKeyboard_ = true;
-          self.updateVisiblity_();
+          self.updateVisibility();
         }
       }, 0);
     });
 
-    this.updateVisiblity_();
+    this.updateVisibility();
   }
 
   FocusOutlineManager.prototype = {
@@ -64,8 +64,7 @@
      */
     focusByKeyboard_: true,
 
-    /** @private */
-    updateVisiblity_: function() {
+    updateVisibility: function() {
       this.visible = this.focusByKeyboard_;
     },
 
diff --git a/ui/webui/resources/js/cr/ui/overlay.js b/ui/webui/resources/js/cr/ui/overlay.js
index 892df027..56f339f 100644
--- a/ui/webui/resources/js/cr/ui/overlay.js
+++ b/ui/webui/resources/js/cr/ui/overlay.js
@@ -97,6 +97,8 @@
     var closeButtons = overlay.querySelectorAll('.page > .close-button');
     for (var i = 0; i < closeButtons.length; i++) {
       closeButtons[i].addEventListener('click', function(e) {
+        if (cr.ui.FocusOutlineManager)
+          cr.ui.FocusOutlineManager.forDocument(document).updateVisibility();
         cr.dispatchSimpleEvent(overlay, 'cancelOverlay');
       });
     }
diff --git a/ui/webui/resources/js/cr/ui/page_manager/page_manager.js b/ui/webui/resources/js/cr/ui/page_manager/page_manager.js
index 578adbd..8fafc82c 100644
--- a/ui/webui/resources/js/cr/ui/page_manager/page_manager.js
+++ b/ui/webui/resources/js/cr/ui/page_manager/page_manager.js
@@ -476,9 +476,11 @@
       if (!overlay || !overlay.canShowPage())
         return false;
 
+      var focusOutlineManager = cr.ui.FocusOutlineManager.forDocument(document);
+
       // Save the currently focused element in the page for restoration later.
       var currentPage = this.getTopmostVisiblePage();
-      if (currentPage)
+      if (currentPage && focusOutlineManager.visible)
         currentPage.lastFocusedElement = document.activeElement;
 
       if ((!rootPage || !rootPage.sticky) &&
@@ -495,14 +497,11 @@
         overlay.didChangeHash();
       }
 
-      // Change focus to the overlay if any other control was focused by
-      // keyboard before. Otherwise, no one should have focus.
-      if (document.activeElement != document.body) {
-        if (cr.ui.FocusOutlineManager.forDocument(document).visible)
-          overlay.focus();
-        if (!overlay.pageDiv.contains(document.activeElement))
-          document.activeElement.blur();
-      }
+      if (focusOutlineManager.visible)
+        overlay.focus();
+
+      if (!overlay.pageDiv.contains(document.activeElement))
+        document.activeElement.blur();
 
       if ($('search-field') && $('search-field').value == '') {
         var section = overlay.associatedSection;
@@ -627,8 +626,14 @@
      */
     restoreLastFocusedElement_: function() {
       var currentPage = this.getTopmostVisiblePage();
-      if (currentPage.lastFocusedElement)
+
+      if (!currentPage.lastFocusedElement)
+        return;
+
+      if (cr.ui.FocusOutlineManager.forDocument(document).visible)
         currentPage.lastFocusedElement.focus();
+
+      currentPage.lastFocusedElement = null;
     },
 
     /**
diff --git a/ui/webui/resources/polymer_resources.grdp b/ui/webui/resources/polymer_resources.grdp
index 52942fe..2a7b8c7 100644
--- a/ui/webui/resources/polymer_resources.grdp
+++ b/ui/webui/resources/polymer_resources.grdp
@@ -589,6 +589,12 @@
   <structure name="IDR_POLYMER_1_0_IRON_PAGES_IRON_PAGES_EXTRACTED_JS"
              file="../../../third_party/polymer/v1_0/components-chromium/iron-pages/iron-pages-extracted.js"
              type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_IRON_RANGE_BEHAVIOR_IRON_RANGE_BEHAVIOR_HTML"
+             file="../../../third_party/polymer/v1_0/components-chromium/iron-range-behavior/iron-range-behavior.html"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_IRON_RANGE_BEHAVIOR_IRON_RANGE_BEHAVIOR_EXTRACTED_JS"
+             file="../../../third_party/polymer/v1_0/components-chromium/iron-range-behavior/iron-range-behavior-extracted.js"
+             type="chrome_html" />
   <structure name="IDR_POLYMER_1_0_IRON_RESIZABLE_BEHAVIOR_IRON_RESIZABLE_BEHAVIOR_HTML"
              file="../../../third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/iron-resizable-behavior.html"
              type="chrome_html" />
@@ -674,6 +680,12 @@
   <structure name="IDR_POLYMER_1_0_PAPER_FAB_PAPER_FAB_HTML"
              file="../../../third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab.html"
              type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_PAPER_PROGRESS_PAPER_PROGRESS_EXTRACTED_JS"
+             file="../../../third_party/polymer/v1_0/components-chromium/paper-progress/paper-progress-extracted.js"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_1_0_PAPER_PROGRESS_PAPER_PROGRESS_HTML"
+             file="../../../third_party/polymer/v1_0/components-chromium/paper-progress/paper-progress.html"
+             type="chrome_html" />
   <structure name="IDR_POLYMER_1_0_PAPER_ICON_BUTTON_PAPER_ICON_BUTTON_EXTRACTED_JS"
              file="../../../third_party/polymer/v1_0/components-chromium/paper-icon-button/paper-icon-button-extracted.js"
              type="chrome_html" />
@@ -782,6 +794,21 @@
   <structure name="IDR_POLYMER_1_0_PAPER_TOOLBAR_PAPER_TOOLBAR_HTML"
              file="../../../third_party/polymer/v1_0/components-chromium/paper-toolbar/paper-toolbar.html"
              type="chrome_html" />
+  <structure name="IDR_POLYMER_08_PAPER_RADIO_BUTTON_PAPER_RADIO_BUTTON_CSS"
+             file="../../../third_party/polymer/v1_0/components-chromium/paper-radio-button/paper-radio-button.css"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_08_PAPER_RADIO_BUTTON_PAPER_RADIO_BUTTON_EXTRACTED_JS"
+             file="../../../third_party/polymer/v1_0/components-chromium/paper-radio-button/paper-radio-button-extracted.js"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_08_PAPER_RADIO_BUTTON_PAPER_RADIO_BUTTON_HTML"
+             file="../../../third_party/polymer/v1_0/components-chromium/paper-radio-button/paper-radio-button.html"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_08_PAPER_RADIO_GROUP_PAPER_RADIO_GROUP_EXTRACTED_JS"
+             file="../../../third_party/polymer/v1_0/components-chromium/paper-radio-group/paper-radio-group-extracted.js"
+             type="chrome_html" />
+  <structure name="IDR_POLYMER_08_PAPER_RADIO_GROUP_PAPER_RADIO_GROUP_HTML"
+             file="../../../third_party/polymer/v1_0/components-chromium/paper-radio-group/paper-radio-group.html"
+             type="chrome_html" />
 
   <!-- more-routing and deps -->
   <structure name="IDR_POLYMER_1_0_MORE_ROUTING_DRIVER"
diff --git a/ui/webui/resources/webui_resources.grd b/ui/webui/resources/webui_resources.grd
index dfffb37c..984947c 100644
--- a/ui/webui/resources/webui_resources.grd
+++ b/ui/webui/resources/webui_resources.grd
@@ -386,6 +386,8 @@
                  file="js/util.js" type="chrome_html" flattenhtml="true" />
       <structure name="IDR_WEBUI_JS_WEBUI_RESOURCE_TEST"
                  file="js/webui_resource_test.js" type="chrome_html" />
+      <structure name="IDR_WEBUI_HTML_ACTION_LINK"
+                 file="html/action_link.html" type="chrome_html" />
       <if expr="chromeos">
         <structure name="IDR_WEBUI_CSS_UI_ACCOUNT_TWEAKS"
                    file="css/chromeos/ui_account_tweaks.css"
diff --git a/ui/wm/core/accelerator_filter.cc b/ui/wm/core/accelerator_filter.cc
index 20eb9a5..93a9225 100644
--- a/ui/wm/core/accelerator_filter.cc
+++ b/ui/wm/core/accelerator_filter.cc
@@ -71,17 +71,4 @@
     event->StopPropagation();
 }
 
-void AcceleratorFilter::OnMouseEvent(ui::MouseEvent* event) {
-  // When a mouse event is interleaved between two key accelerators, we must
-  // store this event as an empty default accelerator in the accelerator
-  // history, so that the |AcceleratorController| can notice that something
-  // actually happened between those two key accelerators.
-  // Non-real synthesized mouse events should be ignored because we don't want
-  // them to interfere with tracking the key accelerator.
-  if (event->flags() & ui::EF_IS_SYNTHESIZED)
-    return;
-
-  accelerator_history_->StoreCurrentAccelerator(ui::Accelerator());
-}
-
 }  // namespace wm
diff --git a/ui/wm/core/accelerator_filter.h b/ui/wm/core/accelerator_filter.h
index 028b78c..90a8c18 100644
--- a/ui/wm/core/accelerator_filter.h
+++ b/ui/wm/core/accelerator_filter.h
@@ -28,9 +28,8 @@
                     ui::AcceleratorHistory* accelerator_history);
   ~AcceleratorFilter() override;
 
-  // ui::EventHandler:
+  // Overridden from ui::EventHandler:
   void OnKeyEvent(ui::KeyEvent* event) override;
-  void OnMouseEvent(ui::MouseEvent* event) override;
 
  private:
   scoped_ptr<AcceleratorDelegate> delegate_;
diff --git a/ui/wm/core/default_activation_client.cc b/ui/wm/core/default_activation_client.cc
index 20c0d79..2a2c23d 100644
--- a/ui/wm/core/default_activation_client.cc
+++ b/ui/wm/core/default_activation_client.cc
@@ -40,7 +40,7 @@
 // DefaultActivationClient, public:
 
 DefaultActivationClient::DefaultActivationClient(aura::Window* root_window)
-    : last_active_(NULL) {
+    : last_active_(nullptr) {
   aura::client::SetActivationClient(root_window, this);
   new Deleter(this, root_window);
 }
@@ -59,6 +59,14 @@
 }
 
 void DefaultActivationClient::ActivateWindow(aura::Window* window) {
+  ActivateWindowImpl(aura::client::ActivationChangeObserver::ActivationReason::
+                         ACTIVATION_CLIENT,
+                     window);
+}
+
+void DefaultActivationClient::ActivateWindowImpl(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* window) {
   aura::Window* last_active = GetActiveWindow();
   if (last_active == window)
     return;
@@ -69,41 +77,45 @@
   window->parent()->StackChildAtTop(window);
   window->AddObserver(this);
 
-  FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
-                    observers_,
-                    OnWindowActivated(window, last_active));
+  FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver, observers_,
+                    OnWindowActivated(reason, window, last_active));
 
   aura::client::ActivationChangeObserver* observer =
       aura::client::GetActivationChangeObserver(last_active);
-  if (observer)
-    observer->OnWindowActivated(window, last_active);
+  if (observer) {
+    observer->OnWindowActivated(reason, window, last_active);
+  }
   observer = aura::client::GetActivationChangeObserver(window);
-  if (observer)
-    observer->OnWindowActivated(window, last_active);
+  if (observer) {
+    observer->OnWindowActivated(reason, window, last_active);
+  }
 }
 
 void DefaultActivationClient::DeactivateWindow(aura::Window* window) {
   aura::client::ActivationChangeObserver* observer =
       aura::client::GetActivationChangeObserver(window);
-  if (observer)
-    observer->OnWindowActivated(NULL, window);
+  if (observer) {
+    observer->OnWindowActivated(aura::client::ActivationChangeObserver::
+                                    ActivationReason::ACTIVATION_CLIENT,
+                                nullptr, window);
+  }
   if (last_active_)
     ActivateWindow(last_active_);
 }
 
 aura::Window* DefaultActivationClient::GetActiveWindow() {
   if (active_windows_.empty())
-    return NULL;
+    return nullptr;
   return active_windows_.back();
 }
 
 aura::Window* DefaultActivationClient::GetActivatableWindow(
     aura::Window* window) {
-  return NULL;
+  return nullptr;
 }
 
 aura::Window* DefaultActivationClient::GetToplevelWindow(aura::Window* window) {
-  return NULL;
+  return nullptr;
 }
 
 bool DefaultActivationClient::CanActivateWindow(aura::Window* window) const {
@@ -115,14 +127,16 @@
 
 void DefaultActivationClient::OnWindowDestroyed(aura::Window* window) {
   if (window == last_active_)
-    last_active_ = NULL;
+    last_active_ = nullptr;
 
   if (window == GetActiveWindow()) {
     active_windows_.pop_back();
     aura::Window* next_active = GetActiveWindow();
     if (next_active && aura::client::GetActivationChangeObserver(next_active)) {
-      aura::client::GetActivationChangeObserver(next_active)->OnWindowActivated(
-          next_active, NULL);
+      aura::client::GetActivationChangeObserver(next_active)
+          ->OnWindowActivated(aura::client::ActivationChangeObserver::
+                                  ActivationReason::WINDOW_DISPOSITION_CHANGED,
+                              next_active, nullptr);
     }
     return;
   }
diff --git a/ui/wm/core/default_activation_client.h b/ui/wm/core/default_activation_client.h
index b5511457..894bccff 100644
--- a/ui/wm/core/default_activation_client.h
+++ b/ui/wm/core/default_activation_client.h
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/observer_list.h"
 #include "ui/aura/window_observer.h"
+#include "ui/wm/public/activation_change_observer.h"
 #include "ui/wm/public/activation_client.h"
 #include "ui/wm/wm_export.h"
 
@@ -51,6 +52,10 @@
   ~DefaultActivationClient() override;
   void RemoveActiveWindow(aura::Window* window);
 
+  void ActivateWindowImpl(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* window);
+
   // This class explicitly does NOT store the active window in a window property
   // to make sure that ActivationChangeObserver is not treated as part of the
   // aura API. Assumptions to that end will cause tests that use this client to
diff --git a/ui/wm/core/focus_controller.cc b/ui/wm/core/focus_controller.cc
index 446e82c..1fee190 100644
--- a/ui/wm/core/focus_controller.cc
+++ b/ui/wm/core/focus_controller.cc
@@ -103,38 +103,9 @@
 }
 
 void FocusController::FocusWindow(aura::Window* window) {
-  if (window &&
-      (window->Contains(focused_window_) || window->Contains(active_window_))) {
-    return;
-  }
-
-  // Focusing a window also activates its containing activatable window. Note
-  // that the rules could redirect activation activation and/or focus.
-  aura::Window* focusable = rules_->GetFocusableWindow(window);
-  aura::Window* activatable =
-      focusable ? rules_->GetActivatableWindow(focusable) : NULL;
-
-  // We need valid focusable/activatable windows in the event we're not clearing
-  // focus. "Clearing focus" is inferred by whether or not |window| passed to
-  // this function is non-NULL.
-  if (window && (!focusable || !activatable))
-    return;
-  DCHECK((focusable && activatable) || !window);
-
-  // Activation change observers may change the focused window. If this happens
-  // we must not adjust the focus below since this will clobber that change.
-  aura::Window* last_focused_window = focused_window_;
-  if (!updating_activation_)
-    SetActiveWindow(window, activatable);
-
-  // If the window's ActivationChangeObserver shifted focus to a valid window,
-  // we don't want to focus the window we thought would be focused by default.
-  bool activation_changed_focus = last_focused_window != focused_window_;
-  if (!updating_focus_ && (!activation_changed_focus || !focused_window_)) {
-    if (active_window_ && focusable)
-      DCHECK(active_window_->Contains(focusable));
-    SetFocusedWindow(focusable);
-  }
+  FocusAndActivateWindow(aura::client::ActivationChangeObserver::
+                             ActivationReason::ACTIVATION_CLIENT,
+                         window);
 }
 
 void FocusController::ResetFocusWithinActiveWindow(aura::Window* window) {
@@ -213,6 +184,43 @@
 ////////////////////////////////////////////////////////////////////////////////
 // FocusController, private:
 
+void FocusController::FocusAndActivateWindow(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* window) {
+  if (window &&
+      (window->Contains(focused_window_) || window->Contains(active_window_))) {
+    return;
+  }
+
+  // Focusing a window also activates its containing activatable window. Note
+  // that the rules could redirect activation activation and/or focus.
+  aura::Window* focusable = rules_->GetFocusableWindow(window);
+  aura::Window* activatable =
+      focusable ? rules_->GetActivatableWindow(focusable) : NULL;
+
+  // We need valid focusable/activatable windows in the event we're not clearing
+  // focus. "Clearing focus" is inferred by whether or not |window| passed to
+  // this function is non-NULL.
+  if (window && (!focusable || !activatable))
+    return;
+  DCHECK((focusable && activatable) || !window);
+
+  // Activation change observers may change the focused window. If this happens
+  // we must not adjust the focus below since this will clobber that change.
+  aura::Window* last_focused_window = focused_window_;
+  if (!updating_activation_)
+    SetActiveWindow(reason, window, activatable);
+
+  // If the window's ActivationChangeObserver shifted focus to a valid window,
+  // we don't want to focus the window we thought would be focused by default.
+  bool activation_changed_focus = last_focused_window != focused_window_;
+  if (!updating_focus_ && (!activation_changed_focus || !focused_window_)) {
+    if (active_window_ && focusable)
+      DCHECK(active_window_->Contains(focusable));
+    SetFocusedWindow(focusable);
+  }
+}
+
 void FocusController::SetFocusedWindow(aura::Window* window) {
   if (updating_focus_ || window == focused_window_)
     return;
@@ -268,8 +276,10 @@
     text_input_focus_manager->FocusTextInputClient(NULL);
 }
 
-void FocusController::SetActiveWindow(aura::Window* requested_window,
-                                      aura::Window* window) {
+void FocusController::SetActiveWindow(
+    aura::client::ActivationChangeObserver::ActivationReason reason,
+    aura::Window* requested_window,
+    aura::Window* window) {
   if (updating_activation_)
     return;
 
@@ -310,19 +320,19 @@
   if (window_tracker.Contains(lost_activation)) {
     observer = aura::client::GetActivationChangeObserver(lost_activation);
     if (observer)
-      observer->OnWindowActivated(active_window_, lost_activation);
+      observer->OnWindowActivated(reason, active_window_, lost_activation);
   }
   observer = aura::client::GetActivationChangeObserver(active_window_);
   if (observer) {
     observer->OnWindowActivated(
-        active_window_,
+        reason, active_window_,
         window_tracker.Contains(lost_activation) ? lost_activation : NULL);
   }
-  FOR_EACH_OBSERVER(aura::client::ActivationChangeObserver,
-                    activation_observers_,
-                    OnWindowActivated(active_window_,
-                                      window_tracker.Contains(lost_activation) ?
-                                      lost_activation : NULL));
+  FOR_EACH_OBSERVER(
+      aura::client::ActivationChangeObserver, activation_observers_,
+      OnWindowActivated(
+          reason, active_window_,
+          window_tracker.Contains(lost_activation) ? lost_activation : NULL));
 }
 
 void FocusController::WindowLostFocusFromDispositionChange(
@@ -335,7 +345,9 @@
   // that process so there's no point in updating focus independently.
   if (window == active_window_) {
     aura::Window* next_activatable = rules_->GetNextActivatableWindow(window);
-    SetActiveWindow(NULL, next_activatable);
+    SetActiveWindow(aura::client::ActivationChangeObserver::ActivationReason::
+                        WINDOW_DISPOSITION_CHANGED,
+                    NULL, next_activatable);
     if (!(active_window_ && active_window_->Contains(focused_window_)))
       SetFocusedWindow(next_activatable);
   } else if (window->Contains(focused_window_)) {
@@ -348,8 +360,11 @@
   // Only focus |window| if it or any of its parents can be focused. Otherwise
   // FocusWindow() will focus the topmost window, which may not be the
   // currently focused one.
-  if (rules_->CanFocusWindow(GetToplevelWindow(window)))
-    FocusWindow(window);
+  if (rules_->CanFocusWindow(GetToplevelWindow(window))) {
+    FocusAndActivateWindow(
+        aura::client::ActivationChangeObserver::ActivationReason::INPUT_EVENT,
+        window);
+  }
 }
 
 }  // namespace wm
diff --git a/ui/wm/core/focus_controller.h b/ui/wm/core/focus_controller.h
index be04b49..e00f0b63 100644
--- a/ui/wm/core/focus_controller.h
+++ b/ui/wm/core/focus_controller.h
@@ -12,6 +12,7 @@
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/window_observer.h"
 #include "ui/events/event_handler.h"
+#include "ui/wm/public/activation_change_observer.h"
 #include "ui/wm/public/activation_client.h"
 #include "ui/wm/wm_export.h"
 
@@ -24,16 +25,19 @@
 // only one focused and one active window at a time. When focus or activation
 // changes notifications are sent using the
 // aura::client::Focus/ActivationChangeObserver interfaces.
-// Changes to focus and activation can be from three sources:
-// . the Aura Client API (implemented here in aura::client::ActivationClient).
-//   (The FocusController must be set as the ActivationClient implementation
-//    for all RootWindows).
-// . input events (implemented here in ui::EventHandler).
-//   (The FocusController must be registered as a pre-target handler for
-//    the applicable environment owner, either a RootWindow or another type).
-// . Window disposition changes (implemented here in aura::WindowObserver).
-//   (The FocusController registers itself as an observer of the active and
-//    focused windows).
+// Changes to focus and activation can be from three sources. The source can be
+// determined by the ActivationReason parameter in
+// ActivationChangeObserver::OnWindowActivated(...).
+// . ActivationReason::ACTIVATION_CLIENT: The Aura Client API (implemented here
+//   in aura::client::ActivationClient). (The FocusController must be set as the
+//   ActivationClient implementation for all RootWindows).
+// . ActivationReason::INPUT_EVENT: Input events (implemented here in
+//   ui::EventHandler). (The FocusController must be registered as a pre-target
+//   handler for the applicable environment owner, either a RootWindow or
+//   another type).
+// . ActivationReason::WINDOW_DISPOSITION_CHANGED: Window disposition changes
+//   (implemented here in aura::WindowObserver). (The FocusController registers
+//   itself as an observer of the active and focused windows).
 class WM_EXPORT FocusController : public aura::client::ActivationClient,
                                   public aura::client::FocusClient,
                                   public ui::EventHandler,
@@ -75,18 +79,26 @@
   void OnWindowHierarchyChanging(const HierarchyChangeParams& params) override;
   void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override;
 
+  // Internal implementation that coordinates window focus and activation
+  // changes.
+  void FocusAndActivateWindow(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* window);
+
   // Internal implementation that sets the focused window, fires events etc.
   // This function must be called with a valid focusable window.
   void SetFocusedWindow(aura::Window* window);
 
   // Internal implementation that sets the active window, fires events etc.
   // This function must be called with a valid |activatable_window|.
-  // |requested window| refers to the window that was passed in to an external
+  // |requested_window| refers to the window that was passed in to an external
   // request (e.g. FocusWindow or ActivateWindow). It may be NULL, e.g. if
   // SetActiveWindow was not called by an external request. |activatable_window|
   // refers to the actual window to be activated, which may be different.
-  void SetActiveWindow(aura::Window* requested_window,
-                       aura::Window* activatable_window);
+  void SetActiveWindow(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* requested_window,
+      aura::Window* activatable_window);
 
   // Called when a window's disposition changed such that it and its hierarchy
   // are no longer focusable/activatable. |next| is a valid window that is used
diff --git a/ui/wm/core/focus_controller_unittest.cc b/ui/wm/core/focus_controller_unittest.cc
index 84c691f..a8bddb3 100644
--- a/ui/wm/core/focus_controller_unittest.cc
+++ b/ui/wm/core/focus_controller_unittest.cc
@@ -33,7 +33,8 @@
                                   public aura::client::FocusChangeObserver {
  public:
   FocusNotificationObserver()
-      : activation_changed_count_(0),
+      : last_activation_reason_(ActivationReason::ACTIVATION_CLIENT),
+        activation_changed_count_(0),
         focus_changed_count_(0),
         reactivation_count_(0),
         reactivation_requested_window_(NULL),
@@ -44,6 +45,9 @@
     EXPECT_EQ(activation_changed_count, activation_changed_count_);
     EXPECT_EQ(focus_changed_count, focus_changed_count_);
   }
+  ActivationReason last_activation_reason() const {
+    return last_activation_reason_;
+  }
   int reactivation_count() const {
     return reactivation_count_;
   }
@@ -56,8 +60,10 @@
 
  private:
   // Overridden from aura::client::ActivationChangeObserver:
-  void OnWindowActivated(aura::Window* gained_active,
+  void OnWindowActivated(ActivationReason reason,
+                         aura::Window* gained_active,
                          aura::Window* lost_active) override {
+    last_activation_reason_ = reason;
     ++activation_changed_count_;
   }
   void OnAttemptToReactivateWindow(aura::Window* request_active,
@@ -73,6 +79,7 @@
     ++focus_changed_count_;
   }
 
+  ActivationReason last_activation_reason_;
   int activation_changed_count_;
   int focus_changed_count_;
   int reactivation_count_;
@@ -115,7 +122,8 @@
   }
 
   // Overridden from aura::client::ActivationChangeObserver:
-  void OnWindowActivated(aura::Window* gained_active,
+  void OnWindowActivated(ActivationReason reason,
+                         aura::Window* gained_active,
                          aura::Window* lost_active) override {
     if (lost_active && lost_active == deleter_->GetDeletedWindow())
       was_notified_with_deleted_window_ = true;
@@ -158,7 +166,8 @@
   }
 
   // Overridden from aura::client::ActivationChangeObserver:
-  void OnWindowActivated(aura::Window* gained_active,
+  void OnWindowActivated(ActivationReason reason,
+                         aura::Window* gained_active,
                          aura::Window* lost_active) override {
     if (window_ && lost_active == window_) {
       delete lost_active;
@@ -303,7 +312,8 @@
 
  private:
   // Overridden from aura::client::ActivationChangeObserver:
-  void OnWindowActivated(aura::Window* gained_active,
+  void OnWindowActivated(ActivationReason reason,
+                         aura::Window* gained_active,
                          aura::Window* lost_active) override {
     // Shift focus to a child. This should prevent the default focusing from
     // occurring in FocusController::FocusWindow().
@@ -499,6 +509,11 @@
   // Input events do not change focus if the window can not be focused.
   virtual bool IsInputEvent() = 0;
 
+  // Returns the expected ActivationReason caused by calling the
+  // ActivatedWindowDirect(...) or DeactivateWindowDirect(...) methods.
+  virtual aura::client::ActivationChangeObserver::ActivationReason
+  GetExpectedActivationReason() const = 0;
+
   void FocusWindowById(int id) {
     aura::Window* window = root_window()->GetChildById(id);
     DCHECK(window);
@@ -579,6 +594,8 @@
 
     ActivateWindowById(2);
     root_observer.ExpectCounts(1, 1);
+    EXPECT_EQ(GetExpectedActivationReason(),
+              root_observer.last_activation_reason());
     observer1.ExpectCounts(1, 1);
     observer2.ExpectCounts(1, 1);
   }
@@ -895,6 +912,12 @@
     DeactivateWindow(window);
   }
   bool IsInputEvent() override { return false; }
+  // Overridden from FocusControllerDirectTestBase:
+  aura::client::ActivationChangeObserver::ActivationReason
+  GetExpectedActivationReason() const override {
+    return aura::client::ActivationChangeObserver::ActivationReason::
+        ACTIVATION_CLIENT;
+  }
 
   DISALLOW_COPY_AND_ASSIGN(FocusControllerApiTest);
 };
@@ -937,7 +960,13 @@
     ui::test::EventGenerator generator(root_window(), next_activatable);
     generator.ClickLeftButton();
   }
+  // Overridden from FocusControllerDirectTestBase:
   bool IsInputEvent() override { return true; }
+  aura::client::ActivationChangeObserver::ActivationReason
+  GetExpectedActivationReason() const override {
+    return aura::client::ActivationChangeObserver::ActivationReason::
+        INPUT_EVENT;
+  }
 
   DISALLOW_COPY_AND_ASSIGN(FocusControllerMouseEventTest);
 };
@@ -963,6 +992,11 @@
     generator.GestureTapAt(window->bounds().CenterPoint());
   }
   bool IsInputEvent() override { return true; }
+  aura::client::ActivationChangeObserver::ActivationReason
+  GetExpectedActivationReason() const override {
+    return aura::client::ActivationChangeObserver::ActivationReason::
+        INPUT_EVENT;
+  }
 
   DISALLOW_COPY_AND_ASSIGN(FocusControllerGestureEventTest);
 };
@@ -978,6 +1012,14 @@
     return parent_ ? window->parent() : window;
   }
 
+  // Returns the expected ActivationReason caused by calling the
+  // ActivatedWindowDirect(...) or DeactivateWindowDirect(...) methods.
+  aura::client::ActivationChangeObserver::ActivationReason
+  GetExpectedActivationReason() const {
+    return aura::client::ActivationChangeObserver::ActivationReason::
+        WINDOW_DISPOSITION_CHANGED;
+  }
+
   // Change the disposition of |window| in such a way as it will lose focus.
   virtual void ChangeWindowDisposition(aura::Window* window) = 0;
 
@@ -1038,6 +1080,8 @@
 
     ChangeWindowDisposition(w2);
     root_observer.ExpectCounts(1, 1);
+    EXPECT_EQ(GetExpectedActivationReason(),
+              root_observer.last_activation_reason());
     observer2.ExpectCounts(1, 1);
     observer3.ExpectCounts(1, 1);
   }
diff --git a/ui/wm/core/shadow_controller.cc b/ui/wm/core/shadow_controller.cc
index 9ba88d36..1e5dd49 100644
--- a/ui/wm/core/shadow_controller.cc
+++ b/ui/wm/core/shadow_controller.cc
@@ -113,7 +113,8 @@
   ~Impl() override;
 
   // Forwarded from ShadowController.
-  void OnWindowActivated(aura::Window* gained_active,
+  void OnWindowActivated(ActivationReason reason,
+                         aura::Window* gained_active,
                          aura::Window* lost_active);
 
   // Checks if |window| is visible and contains a property requesting a shadow.
@@ -183,7 +184,8 @@
   observer_manager_.Remove(window);
 }
 
-void ShadowController::Impl::OnWindowActivated(aura::Window* gained_active,
+void ShadowController::Impl::OnWindowActivated(ActivationReason reason,
+                                               aura::Window* gained_active,
                                                aura::Window* lost_active) {
   if (gained_active) {
     Shadow* shadow = GetShadowForWindow(gained_active);
@@ -271,9 +273,10 @@
   activation_client_->RemoveObserver(this);
 }
 
-void ShadowController::OnWindowActivated(aura::Window* gained_active,
+void ShadowController::OnWindowActivated(ActivationReason reason,
+                                         aura::Window* gained_active,
                                          aura::Window* lost_active) {
-  impl_->OnWindowActivated(gained_active, lost_active);
+  impl_->OnWindowActivated(reason, gained_active, lost_active);
 }
 
 // ShadowController::TestApi ---------------------------------------------------
diff --git a/ui/wm/core/shadow_controller.h b/ui/wm/core/shadow_controller.h
index 360a9976..b307c02 100644
--- a/ui/wm/core/shadow_controller.h
+++ b/ui/wm/core/shadow_controller.h
@@ -51,8 +51,10 @@
   ~ShadowController() override;
 
   // aura::client::ActivationChangeObserver overrides:
-  void OnWindowActivated(aura::Window* gained_active,
-                         aura::Window* lost_active) override;
+  void OnWindowActivated(
+      aura::client::ActivationChangeObserver::ActivationReason reason,
+      aura::Window* gained_active,
+      aura::Window* lost_active) override;
 
  private:
   class Impl;
diff --git a/ui/wm/public/activation_change_observer.h b/ui/wm/public/activation_change_observer.h
index 68d5b8a..57f9d27 100644
--- a/ui/wm/public/activation_change_observer.h
+++ b/ui/wm/public/activation_change_observer.h
@@ -14,11 +14,23 @@
 
 class AURA_EXPORT ActivationChangeObserver {
  public:
-  // Called when |active| gains focus, or there is no active window
-  // (|active| is NULL in this case.) |old_active| refers to the
+  // The reason or cause of a window activation change.
+  enum class ActivationReason {
+    // When a window is activated due to a call to the ActivationClient API.
+    ACTIVATION_CLIENT,
+    // When a user clicks or taps a window in the 2-dimensional screen space.
+    INPUT_EVENT,
+    // When a new window is activated as a side effect of a window
+    // disposition changing.
+    WINDOW_DISPOSITION_CHANGED,
+  };
+
+  // Called when |gained_active| gains focus, or there is no active window
+  // (|gained_active| is NULL in this case.) |lost_active| refers to the
   // previous active window or NULL if there was no previously active
-  // window.
-  virtual void OnWindowActivated(Window* gained_active,
+  // window. |reason| specifies the cause of the activation change.
+  virtual void OnWindowActivated(ActivationReason reason,
+                                 Window* gained_active,
                                  Window* lost_active) = 0;
 
   // Called when during window activation the currently active window is